Plugins
How nikcli installs plugins, patches server/TUI config, loads built-ins, and exposes plugin hooks.
Overview
Plugins extend server-side agent behavior and TUI behavior. Server plugin loading is in
packages/nikcli/src/plugin/index.ts. Plugin installation and config patching are
in packages/nikcli/src/plugin/installer.ts. TUI plugin runtime lives under
packages/tui/src/plugin.
Server hooks
Provider auth, tool hooks, event hooks, notifications, and session behavior load in the server plugin service.
TUI hooks
TUI plugins can register commands, routes, dialogs, keybinds, and sidebar features.
Installer
nikcli plugin installs a package, reads its manifest, and patches local or global config.
Built-ins
Internal auth and notification plugins always load; external built-ins load unless disabled.
Install a plugin
nikcli plugin @scope/my-plugin
nikcli plugin @scope/my-plugin --global
nikcli plugin @scope/my-plugin@1.2.3 --force The install task performs four steps:
- Resolve and install the package target.
- Read plugin metadata from
package.json. - Detect server and/or TUI targets from manifest or exports.
- Patch
nikcli.jsonand/ortui.jsonin the selected scope.
| Flag | Behavior |
|---|---|
--global | Patch global config under Global.Path.config instead of project config. |
--force | Replace an existing plugin entry for the same package. |
| version suffix | Installer preserves the requested package spec and version. |
Config patching
patchPluginConfig uses jsonc-parser edits instead of string hacks.
It can patch server config plugin and TUI config depending on detected targets.
Duplicate detection compares package names, not only the full versioned spec.
| Mode | When used |
|---|---|
add | No existing plugin entry for the package. |
noop | Same plugin spec is already configured and force is false. |
replace | Existing package entry differs and --force is set. |
{
"plugin": [
"@scope/my-plugin"
]
} Server runtime
Server plugin loading starts with internal plugins that are imported directly. Then configured
plugins plus external built-ins are loaded. If a plugin path is not file://, nikcli
installs the package before importing it.
- Build plugin input, including SDK client and runtime helpers.
- Load internal auth/notification plugins.
- Copy configured plugin specifiers from config.
- Add external built-ins unless
NIKCLI_DISABLE_DEFAULT_PLUGINSis set. - Ignore old Codex/Copilot auth plugin specs that are now first-party.
- Install and import package specifiers.
- Load v1
serverexport when present, otherwise invoke exported plugin functions. - Deduplicate duplicate function references from named and default exports.
TUI runtime
TUI plugin APIs are built in packages/tui/src/plugin/api.tsx and loaded by
plugin/runtime.ts. Plugins can add routes, commands, dialogs, keybinds, and UI
surfaces while the TUI app is running.
| API area | Capability |
|---|---|
| Route | Navigate home, session, changes, tree, graph, GitHub, or plugin routes. |
| Command | Register command palette entries and key-triggered commands. |
| Dialog | Open, clear, size, and inspect dialog stack. |
| Keybind | Match, print, and create plugin keybind definitions. |
| Slots/features | Register sidebar or system plugin manager UI where supported. |
| Storage | api.storage.memory(key, { initial }) keeps per-plugin state in memory across hot reloads; api.storage.store(...) persists it to disk and syncs it across TUI instances. |
A plugin that throws while rendering is contained: the slot or route renders nothing and the crash surfaces as a single error toast instead of taking the TUI down.
TUI plugin discovery and hot reload
Local TUI plugins are discovered from plugin/tui/ and plugins/tui/
inside every config root — the project .nikcli directories, the global config dir,
NIKCLI_CONFIG_DIR, and the managed dir. Anything else is declared in
tui.json. The extra tui level matters:
{plugin,plugins}/*.{ts,js} is the server plugin loader's
territory, so a TUI plugin placed directly there is loaded as a server plugin and fails.
.nikcli/
tui.json # optional: declare plugins with options
plugin/tui/hud.tsx # discovered automatically
Editing a local plugin swaps that one plugin in the running TUI, typically within ~100 ms. Other
plugins — including built-ins — are never touched, in-memory state kept in
api.storage.memory survives, and a broken save keeps the last working version alive
with one error toast until the file is fixed. npm package plugins do not hot reload: their
entrypoints resolve into the package cache and are immutable for the session.
| Change on disk | Effect on the running TUI |
|---|---|
| Edit a local plugin file | That plugin is disposed and re-initialized from the fresh module. |
Add a file to plugin/tui/ | The plugin is loaded and activated. |
Add or remove a tui.json entry | The plugin is loaded, or torn down. |
| Change plugin options | That plugin restarts with the new options. |
Flip plugin_enabled | The plugin is disposed or initialized. Plugin-manager toggles are stored in KV and still win. |
NIKCLI_DISABLE_PLUGIN_RELOAD=1 to load plugins once
at startup; --pure / NIKCLI_PURE skips external TUI plugins entirely.
Built-in plugins
Internal built-ins are directly imported and do not depend on package installation. They include Codex auth, GitHub Copilot auth, xAI auth, Cursor auth, Cloudflare Workers/Gateway auth, and the notification plugin. External built-ins are appended from the built-in list unless disabled.
| Built-in | Purpose |
|---|---|
| Codex auth | First-party Codex authentication support. |
| GitHub Copilot auth | Copilot and enterprise provider auth. |
| xAI auth | xAI provider auth integration. |
| Cursor auth | Cursor ACP/provider auth integration. |
| Cloudflare auth | Cloudflare Workers and AI Gateway auth flows. |
| Notify plugin | Session idle/error, permission, question, Slack, Discord, and macOS notifications. |
NIKCLI_DISABLE_DEFAULT_PLUGINS=1 nikcli Internal TUI feature plugins
Beyond the auth and notification plugins, the TUI ships a set of internal feature plugins
that ship inside packages/tui/src/feature-plugins/. They run in-process and don't
need to be installed:
| Plugin | Capability |
|---|---|
home | Rotating tip line in the home.bottom slot. |
sidebar | Six slot plugins: context/cost, MCP, LSP, todo, modified files, footer. |
system | Plugin manager (list / toggle / install) and OpenRouter Fusion presets. |
background | Paints a real image behind the TUI; owns /background. |
loops | Loops manager, creation wizard and live sidebar. |
mission | Missions manager, planning wizard and live sidebar. |
brain | Arms the Brain consolidation scheduler; /brain runs a pass on demand. |
browser | Browser-use control surface for the browser tool. |
chatbot | ChatBot control panel for Discord / Slack / Teams / GChat / Linear / GitHub webhooks. |
computer | Probes the host for the computer tool's screenshot and input capabilities. |
connectors | First-party connector health, cache refresh, and credential removal. |
observability | Live OpenTelemetry spans and OTLP endpoint dialogs. |
island | Toggles the macOS Island notch integration. Registered only under --island. |
Each one — its commands, slash aliases, KV keys and internals — is documented in TUI feature plugins, which doubles as the reference for the plugin API since the internal plugins use exactly the API an npm plugin gets.
Plugin manifest
The installer reads package metadata with readPluginPackage. Target detection
accepts explicit plugin target metadata and also detects packages that expose
./server and/or ./tui exports. A package with only main
or string exports is treated as a server plugin.
{
"name": "@scope/my-plugin",
"version": "1.0.0",
"exports": {
"./server": "./dist/server.js",
"./tui": "./dist/tui.js"
},
"oc-plugin": ["server", "tui"]
} Target entries may also be tuples with target options, such as a TUI target plus plugin options. The patcher preserves target options when adding config.
Skills
Skills are related but not the same as plugins. Skills are prompt/context assets discovered by
skill/skill.ts. The skill glob scans skill/**/SKILL.md and
skills/**/SKILL.md under config directories, plus external sources unless disabled.
| Feature | Plugin | Skill |
|---|---|---|
| Runtime code | Yes, imported and executed. | No, prompt/context instructions and assets. |
| Config field | plugin | Discovered from directories and external skill locations. |
| TUI manager | System plugin manager and plugin APIs. | Skills dialog and skill install/search UI. |
| Disable flag | NIKCLI_DISABLE_DEFAULT_PLUGINS for default external plugins. | NIKCLI_DISABLE_EXTERNAL_SKILLS for external skills. |
Notifications
Notifications are implemented as an internal plugin created by createNotifyPlugin.
It reads notifications.notify and notifications.todo, applies rate
limits, retry/backoff, circuit breaker behavior, quiet hours, and connector-backed Slack or
Discord delivery.
{
"notifications": {
"notify": {
"enabled": true,
"events": {
"sessionIdle": true,
"sessionError": true,
"permissionAsked": true,
"questionAsked": true
},
"slack": { "enabled": true, "connector": "slack", "channel": "#builds" }
}
}
} Failure modes
| Symptom | Likely cause | Fix |
|---|---|---|
| Install failed | Package resolution, registry auth, or unavailable version. | Check the error detail from Process.RunFailedError and npm registry settings. |
| No plugin targets found | Package lacks recognized manifest targets and exports. | Add oc-plugin, ./server, ./tui, main, or string exports. |
| Invalid JSON while patching | Target config file is not valid JSONC. | Fix reported line/column and rerun install. |
| Plugin loads twice | Package exports same function as named and default export. | Runtime deduplicates identical function references; check distinct functions if duplicates remain. |
| Built-in plugin install fails | External built-in package could not be installed. | Server publishes a session error and continues without that built-in. |
| TUI plugin route missing | Plugin route id was not registered or runtime disposed. | Check TUI plugin runtime status and route registration. |
Source anchors
| Need | File |
|---|---|
| Server plugin runtime | packages/nikcli/src/plugin/index.ts |
| Plugin install and patching | packages/nikcli/src/plugin/installer.ts |
| Plugin package parsing | @nikcli-ai/util/plugin-shared |
| CLI command | packages/nikcli/src/cli/cmd/plug.ts |
| TUI plugin API | packages/tui/src/plugin/api.tsx |
| TUI plugin runtime | packages/tui/src/plugin/runtime.ts |
| System plugin manager | packages/tui/src/feature-plugins/system |
| Home, sidebar, background, loop, mission, brain, browser, chatbot, computer, connectors and observability plugins | packages/tui/src/feature-plugins/ |
| Internal plugin registry | packages/tui/src/plugin/internal.ts |
| Island file bridge | @nikcli-ai/util/island-bridge |
| Island TUI plugin | packages/tui/src/feature-plugins/island/index.tsx |
| Plugin contracts package | packages/plugin |
| Skills | packages/nikcli/src/skill/skill.ts |