-
Notifications
You must be signed in to change notification settings - Fork 0
packages coding agent extensions
Active contributors: Mario Zechner, kt, Armin Ronacher
Extensions are TypeScript modules that customize Prime Agent behavior in-process. An extension exports a default factory function that receives the ExtensionAPI and can subscribe to lifecycle events, register tools callable by the LLM, add slash commands and keybindings, and render custom UI. The reference is packages/coding-agent/docs/extensions.md, with working samples in packages/coding-agent/examples/extensions/. The implementation lives under packages/coding-agent/src/core/extensions/.
Extensions are permanently process-local: they expose executable callbacks (argument completions, tool renderers, keyboard shortcut handlers) and process state (extension bindings) that cannot cross the daemon wire. On the AgentConnection seam this surface lives on the AgentConnection.extensions sub-interface; daemon adapters throw AgentConnectionUnsupportedError.
packages/coding-agent/src/core/extensions/
├── index.ts # Public type and helper re-exports
├── loader.ts # jiti-based module loading and discovery
├── runner.ts # ExtensionRunner: event dispatch and lifecycle
├── types.ts # Extension, ExtensionAPI, events, contexts
├── wrapper.ts # Wrap registered tools into AgentTools
├── bundled-modules.ts # Virtual module map for the compiled Bun binary
└── builtin/
└── herdr-agent-state.ts # Built-in Herdr pane state reporter
packages/coding-agent/examples/extensions/
├── with-deps/ # Extension with its own npm dependency (ms)
├── custom-provider-anthropic/ # Register a custom Anthropic provider
├── custom-provider-gitlab-duo/ # Register a custom GitLab Duo provider
└── sandbox/ # Custom tool backed by the Anthropic sandbox runtime
| Type | Path | Description |
|---|---|---|
Extension |
packages/coding-agent/src/core/extensions/types.ts |
Loaded extension: paths, source info, handlers, tools, commands, flags, shortcuts, message renderers. |
ExtensionAPI |
packages/coding-agent/src/core/extensions/types.ts |
The pi object passed to the factory; registration and action methods. |
ExtensionFactory |
packages/coding-agent/src/core/extensions/types.ts |
The default-export function an extension module must provide. |
ExtensionRuntime |
packages/coding-agent/src/core/extensions/types.ts |
Shared runtime holding action methods and flag values across extensions. |
ExtensionRunner |
packages/coding-agent/src/core/extensions/runner.ts |
Dispatches events to handlers and manages extension lifecycle. |
ExtensionContext |
packages/coding-agent/src/core/extensions/types.ts |
Per-call context: UI, cwd, model, session manager, signal, abort, compact. |
ExtensionCommandContext |
packages/coding-agent/src/core/extensions/types.ts |
Command handler context with newSession, fork, switchSession, reload. |
ExtensionUIContext |
packages/coding-agent/src/core/extensions/types.ts |
TUI surface: select, confirm, input, notify, widgets, footer, header, editors. |
RegisteredTool / ToolDefinition
|
packages/coding-agent/src/core/extensions/types.ts |
A tool registered via pi.registerTool. |
LoadExtensionsResult |
packages/coding-agent/src/core/extensions/types.ts |
Extensions plus per-path load errors and the runtime. |
AgentConnectionExtensions |
packages/coding-agent/src/modes/agent-connection/types.ts |
Process-local extension surface exposed on AgentConnection. |
flowchart TD
dirs["~/.prime/agent/extensions · .prime/agent/extensions · packages · CLI paths"]
loader["loader.ts: discover + jiti import"]
factory["default export factory(pi: ExtensionAPI)"]
api["createExtensionAPI: writes tools/commands/events"]
runtime["createExtensionRuntime: shared action methods"]
runner["ExtensionRunner.bindCore/bindCommandContext"]
session["AgentSession + mode"]
dirs --> loader --> factory --> api
api --> runtime
runtime --> runner --> session
runner --> conn["AgentConnection.extensions (process-local)"]
loader.ts resolves extension entry points from files (*.ts/*.js), subdirectories with an index.ts/index.js, or a package.json with a pi.extensions field. Modules are imported with jiti so TypeScript runs without compilation. In the compiled Bun binary, imports of @earendil-works/*, typebox, and @sinclair/typebox resolve through bundled-modules.ts virtual modules so extensions share the bundle's module instances; in Node.js dev they resolve through jiti aliases.
The factory runs during loading and uses registration methods (pi.on, pi.registerTool, pi.registerCommand, pi.registerShortcut, pi.registerFlag, pi.registerMessageRenderer) that write into the Extension object, plus action methods that delegate to the shared ExtensionRuntime. The runtime starts with throwing stubs; ExtensionRunner.bindCore replaces them with real implementations once the model registry and context actions are available. Provider registrations queued during loading (pi.registerProvider) are flushed on bind.
ExtensionRunner owns lifecycle. Its emit methods walk every extension's handlers for a given event type and fold results (for example message_end transforms a message, tool_result can rewrite content, context can rewrite the message list, before_agent_start can alter the system prompt and inject messages). Command names are deduplicated into invocationNames when two extensions register the same name. Extension shortcuts are checked against reserved built-in keybindings so extensions cannot steal core editor actions.
- Tools:
pi.registerTool({ name, label, description, parameters, execute })adds a tool the model can call;wrapper.tswraps registered tools intoAgentTools that receive the runner context. - Commands:
pi.registerCommand("name", { description, handler })adds a/nameslash command. - Keybindings:
pi.registerShortcut("ctrl+x", { description, handler })adds a shortcut resolved against the client's effective keybindings. - Flags:
pi.registerFlag("my-flag", { type, default })adds a CLI flag read throughpi.getFlag. - Events:
pi.on("event_name", handler)subscribes to lifecycle events (session, agent, tool, model, input, message, resource discovery). - UI:
ctx.uiprovidesselect,confirm,input,notify,setStatus,setWidget,setFooter,setHeader,setTitle, editors, autocomplete providers, andctx.ui.custom()for full custom TUI components. - Message/tool rendering:
pi.registerMessageRendererand tool renderer definitions control how custom messages and tool calls appear. - Session persistence:
pi.appendEntry(customType, data)writes session entries that survive restarts. - Providers:
pi.registerProviderregisters a custom LLM provider (used by the custom-provider examples).
The AgentConnection seam (packages/coding-agent/src/modes/agent-connection/types.ts) exposes AgentConnection.extensions, whose members are permanently process-local: getArgumentCompletions, getCommandDiagnostics, getShortcutDiagnostics, getShortcuts, getKeyboardShortcuts, getMessageRenderer, getToolRendererDefinition, and bindExtensions. These carry executable callbacks and process state that cannot cross a network boundary, so daemon-backed adapters throw AgentConnectionUnsupportedError. bindExtensions(bindings) wires the extension runner's actions into the session and mode; extension context is invalidated after session replacement or reload so captured contexts cannot be used across a newSession, fork, switchSession, or reload.
packages/coding-agent/src/core/extensions/builtin/herdr-agent-state.ts is the in-tree equivalent of the extension that herdr integration install pi writes. It reports agent lifecycle state (working/blocked/idle) to the Herdr terminal workspace manager over a Unix socket. It is a no-op unless HERDR_ENV=1 with HERDR_SOCKET_PATH and HERDR_PANE_ID set. It defers to Herdr's own file-based integration when that file actually loads (checked via the resource loader's loaded paths), reports with a monotonic per-source sequence, and releases the pane on a real quit rather than on session replacement.
-
with-deps: a tool (parse_duration) that imports themsnpm package, proving jiti resolves dependencies from the extension's ownnode_modules. Requiresnpm installin that directory. -
custom-provider-anthropic: registers a custom Anthropic provider viapi.registerProvider. -
custom-provider-gitlab-duo: registers a custom GitLab Duo provider; includes atest.ts. -
sandbox: a custom tool backed by the Anthropic sandbox runtime (@anthropic-ai/sandbox-runtime).
-
DefaultResourceLoader.reload()inpackages/coding-agent/src/core/resource-loader.tscallsloadExtensions, runs inlineextensionFactories, detects tool/flag name conflicts, and attachesSourceInfo. -
wrapper.tsconverts extension tools intoAgentTools consumed by the session. - The interactive mode and
bindExtensionswire runner actions into the session, model registry, and TUI. - Extensions can contribute skills, prompts, and themes through the
resources_discoverevent, whichemitResourcesDiscoverin the runner aggregates into resource paths for the loader.
- To add a new event type or change dispatch, edit
packages/coding-agent/src/core/extensions/types.ts(event union) andpackages/coding-agent/src/core/extensions/runner.ts(emitmethods). - To change discovery or module loading, edit
packages/coding-agent/src/core/extensions/loader.ts. - To change how the shared runtime and action stubs behave, edit
packages/coding-agent/src/core/extensions/loader.ts(createExtensionRuntime,createExtensionAPI). - To add a built-in extension, add a module under
packages/coding-agent/src/core/extensions/builtin/and re-export it fromindex.ts.
| File | Role |
|---|---|
packages/coding-agent/src/core/extensions/index.ts |
Public re-exports of extension types and helpers. |
packages/coding-agent/src/core/extensions/loader.ts |
jiti loading, discovery, runtime and API creation. |
packages/coding-agent/src/core/extensions/runner.ts |
Event dispatch, lifecycle, context creation. |
packages/coding-agent/src/core/extensions/types.ts |
Extension, API, event, context, and UI types. |
packages/coding-agent/src/core/extensions/wrapper.ts |
Tool wrapper into AgentTool. |
packages/coding-agent/src/core/extensions/bundled-modules.ts |
Virtual modules for the compiled binary. |
packages/coding-agent/src/core/extensions/builtin/herdr-agent-state.ts |
Built-in Herdr reporter. |
- Package overview, SDK surface for the coding-agent package
-
Session runtime, how
bindExtensionsintegrates with the session - Slash commands, extension-registered commands
- Patterns and conventions, repo rules