# Extension points — earendil-works/pi

> Canonical page: https://codevetter.com/unpack/pi/extension-points

# Extension points — earendil-works/pi

Scanned commit 95fbc04997eaee961eb673fa7923e9220609ebd5 (2026-09-22). Generated by codevetter codevetter 1.12.0 on 2026-09-22.

Pi's core is deliberately minimal — CONTRIBUTING.md says features that don't belong in core should be extensions. The main seam is the ExtensionAPI: TypeScript modules loaded by jiti from user/project dirs, CLI -e, settings, or npm/git packages, which can register tools, slash commands, providers, CLI flags, keybindings, UI widgets/renderers, and ~35 lifecycle event handlers. Lower-level seams: pluggable tool Operations (e.g. BashOperations for remote execution), Provider registration in pi-ai, Chord facets/services for the experimental stack, skills/prompt-templates/themes as data resources, and custom session entries for extension persistence.
- ExtensionAPI is the central registry: on() subscribes to ~35 typed events (project_trust, session_start, session_compact, context, before_provider_headers, after_provider_response, agent_start/end, turn_start/end, message_*, tool_execution_*, tool_call, tool_result, user_bash, input, model_select, thinking_level_select, ui_prompt_start/end, agent_settled, session_tree, session_shutdown, session_info_changed). — [packages/coding-agent/src/core/extensions/types.ts#L1349-1424](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/core/extensions/types.ts#L1349-L1424)
- Extensions register LLM-callable tools via registerTool (typebox-schema params, execute callback, optional renderers), user commands via registerCommand, and providers via registerProvider(name, ProviderConfig)/unregisterProvider — with doc-commented examples for corporate proxies. — [packages/coding-agent/src/core/extensions/types.ts#L1426-1435](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/core/extensions/types.ts#L1426-L1435) [packages/coding-agent/src/core/extensions/types.ts#L1567-1620](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/core/extensions/types.ts#L1567-L1620)
- Extensions are discovered from: ~/.pi/agent paths, project .pi/extensions, settings extensions[] arrays, CLI -e, package-managed npm/git sources, and InlineExtension factories passed programmatically; loading uses jiti with module aliases or embedded virtual modules in compiled-binary mode. — [packages/coding-agent/src/core/extensions/loader.ts#L40-121](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/core/extensions/loader.ts#L40-L121) [packages/coding-agent/src/core/resource-loader.ts#L30-52](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/core/resource-loader.ts#L30-L52)
- Built-in tools accept pluggable Operations interfaces — BashOperations.exec can delegate to SSH or a micro-VM (the Gondolin example extension does exactly this), and EditOperations/ReadOperations etc. follow the same pattern. — [packages/coding-agent/src/core/tools/bash.ts#L55-78](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/core/tools/bash.ts#L55-L78) [packages/coding-agent/src/core/tools/index.ts#L107-116](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/core/tools/index.ts#L107-L116)
- ~70 example extensions under packages/coding-agent/examples/extensions demonstrate every seam: tools.ts, commands.ts, subagent/, plan-mode/, permission-gate.ts, sandbox/, gondolin/, ssh.ts, custom-provider-anthropic/, todo.ts, handoff.ts, confirm-destructive.ts, protected-paths.ts — doubling as living documentation. — [packages/coding-agent/examples/extensions/README.md](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/examples/extensions/README.md) [packages/coding-agent/examples/extensions/tools.ts](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/examples/extensions/tools.ts)
- Skills (Markdown + frontmatter) and prompt templates are pure-data extension points discovered from .pi/skills, .agents/skills ancestors, and configured paths; themes are JSON files with a validator hook (setThemeJsonValidator) that hosts can replace. — [packages/coding-agent/src/core/skills.ts](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/core/skills.ts) [packages/coding-agent/src/main.ts#L885-887](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/main.ts#L885-L887) [packages/coding-agent/src/core/prompt-templates.ts](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/core/prompt-templates.ts)
- Extensions can persist state in the session file via CustomEntry (customType namespaced data, excluded from LLM context) and inject context via CustomMessageEntry — documented in the session-manager type comments. — [packages/coding-agent/src/core/session-manager.ts#L118-132](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/core/session-manager.ts#L118-L132) [packages/coding-agent/src/core/session-manager.ts#L147-160](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/core/session-manager.ts#L147-L160)
- CLI flag extension: unknown flags are collected into parsed.unknownFlags and passed to the runtime as extensionFlagValues, so extensions can define their own --flags which appear in printHelp output. — [packages/coding-agent/src/cli/args.ts#L55-57](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/cli/args.ts#L55-L57) [packages/coding-agent/src/main.ts#L740](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/main.ts#L740) [packages/coding-agent/src/main.ts#L858-863](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/main.ts#L858-L863)
- pi-ai's Models registry is itself an extension point: setProvider() adds a Provider implementation to the mutable registry; the coding-agent composes configured, extension-registered, and remote-catalog providers through provider-composer. — [packages/ai/src/models.ts#L239-281](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/ai/src/models.ts#L239-L281) [packages/coding-agent/src/core/provider-composer.ts](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/core/provider-composer.ts)
- The agent loop exposes hooks for hosts: transformContext, convertToLlm, prepareRequest, prepareNextTurn(WithContext), beforeToolCall, afterToolCall, finishTurn, getSteeringMessages, getFollowUpMessages — Agent maps these to public constructor options. — [packages/agent/src/agent.ts#L114-140](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/agent/src/agent.ts#L114-L140) [packages/agent/src/agent-loop.ts#L184-238](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/agent/src/agent-loop.ts#L184-L238)
- In the experimental stack, Chord facets/plugins declare provided/required services that a host validates and activates in dependency order; pi-server's RoutedSessionHandle.invokeService routes opaque service envelopes so new application services plug in without server-side schema changes. — [packages/chord/README.md](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/chord/README.md) [packages/server/README.md](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/server/README.md) [packages/coding-agent/src/experimental/plugins](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/experimental/plugins)
- Stream function is injectable: setDefaultStreamFn lets hosts install a default StreamFn for Agent/agentLoop without pi-agent-core depending on a provider catalog; AgentSession wires ModelRuntime's stream through this seam. — [packages/agent/src/stream-fn.ts](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/agent/src/stream-fn.ts) [packages/agent/src/agent.ts#L195](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/agent/src/agent.ts#L195)
- An experimental plugin entry (./experimental/plugin export) plus experimental/ sources (session-worker, coordinator, client-tui, radius-relay, services/) form the in-progress multi-process/plugin architecture — explicitly exported as unstable. — [packages/coding-agent/package.json](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/package.json) [packages/coding-agent/src/experimental/plugin.ts](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/experimental/plugin.ts) [packages/coding-agent/src/experimental/session-worker.ts](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/experimental/session-worker.ts)

Every claim links to its cited files at the pinned commit. Citations identify source evidence; they do not establish runtime correctness. Independent CodeVetter scan — not reviewed by upstream maintainers.

## Public product links

- [CodeVetter](https://codevetter.com/)
- [Download](https://codevetter.com/download)
- [Documentation](https://codevetter.com/docs/)
- [Source](https://github.com/Codevetter/codevetter)
