Create, update, and publish Pi extensions. Use when working on extensions in this repository.
Guide for creating and maintaining Pi extensions. Read the relevant reference files before implementing.
// Core types
import type { ExtensionAPI, ExtensionContext, ToolDefinition, ProviderDefinition } from "@mariozechner/pi-coding-agent";
// Schema (TypeBox)
import { Type } from "@mariozechner/pi-coding-agent";
// TUI components
import type { Component, Theme } from "@mariozechner/pi-tui";
import { Text, Box, Container, SelectList } from "@mariozechner/pi-tui";
// Utilities
import { truncateHead, highlightCode, getLanguageFromPath, DynamicBorder, BorderedLoader } from "@mariozechner/pi-coding-agent";
references/structure.md for the project layout and package.json template.src/index.tsreferences/tools.md.references/commands.md.references/providers.md.references/hooks.md. Includes both tool_call blocking hooks and spawn hooks for transparent command rewriting via createBashTool.references/modes.md for mode-awareness guidelines. Every extension must handle Interactive, RPC, and Print modes.references/components.md for TUI components and references/messages.md for message display patterns.references/state.md.references/additional-apis.md.references/publish.md and references/documentation.md.index.ts to understand its structure.references/modes.md if adding any UI interaction.| File | Content |
|---|---|
references/structure.md | Project layout, package.json, tsconfig, entry point, API key pattern, imports |
references/tools.md | Tool registration, execute signature, parameters, streaming, rendering, naming, renderCall/renderResult UI guidelines |
references/hooks.md | Events, blocking/cancelling, input transformation, system prompt modification, bash spawn hooks (command rewriting) |
references/commands.md | Command registration, three-tier pattern, component extraction |
references/components.md | TUI components (pi-tui + pi-coding-agent), custom(), theme styling, keyboard handling |
references/providers.md | Provider registration, model definition, compat field, API key gating |
references/modes.md | Mode behavior matrix, ctx.hasUI, dialog vs fire-and-forget, three-tier pattern |
references/messages.md | sendMessage, registerMessageRenderer, notify, when to use each |
references/state.md | appendEntry, state reconstruction, appendEntry vs sendMessage |
references/additional-apis.md | Shortcuts, flags, exec, sendUserMessage, session name, labels, model control, EventBus, theme, UI customization |
references/publish.md | npm publishing, changesets, versioning, pre-publish checklist |
references/testing.md | Local development, type checking, manual testing, debugging |
references/documentation.md | README template, what to document, changelog |
When implementing, look at these existing extensions for patterns:
Standalone repos (recommended structure):
pi-linkup (/Users/alioudiallo/code/src/github.com/aliou/pi-linkup/): Tools wrapping a third-party API. Has tools, a command, custom message rendering, API key gating.pi-synthetic (/Users/alioudiallo/code/src/github.com/aliou/pi-synthetic/): Provider + tools. Has a provider with models, a command with custom() component, API key gating, async entry point.Monorepo extensions (simpler structure):
extensions/defaults/ in this repo: Simple tool registration (get_current_time).extensions/guardrails/ in this repo: Event hooks (tool_call blocking). Has hooks/, commands/, components/, utils/ directories with config types in config.ts.extensions/toolchain/ in this repo: Bash spawn hooks (command rewriting via createBashTool) combined with tool_call blockers. Has blockers/, rewriters/, commands/, utils/ directories.extensions/processes/ in this repo: Multi-action tool with StringEnum parameters.(toolCallId, params, signal, onUpdate, ctx). Signal before onUpdate.onUpdate?.(): Optional chaining. The parameter can be undefined..js in imports: Use bare module paths (./tools/my-tool, not ./tools/my-tool.js).ctx.ui.custom() call needs an RPC fallback (use select/confirm/notify -- they work in RPC). Every tool_call hook with dialogs needs a ctx.hasUI check.models() function.linkup_web_search). No prefix for internal tools (get_current_time).renderCall consistent: first line [Tool Name]: [Action] [Main arg] [Option args], extra lines for long args. Use display names, not raw tool IDs.>=CURRENT_VERSION range, not *.pi-tui or pi-coding-agent already exports one that fits.signal through to fetch(), child processes, and API client methods. A tool that ignores its signal prevents cancellation from reaching the underlying operation. Never prefix with _signal unless the tool truly has no async work to cancel.homedir() for pi paths: Use the SDK helpers from @mariozechner/pi-coding-agent instead. They respect the PI_CODING_AGENT_DIR env var which is used for testing and custom setups. Key functions: getAgentDir(), getSettingsPath(), getSessionsDir(), getPromptsDir(), getToolsDir(), getCustomThemesDir(), getModelsPath(), getAuthPath(), getBinDir(), getDebugLogPath(). All exported from the main package entry point.Before considering an extension complete:
onUpdate calls use optional chaining..js file extensions in imports.renderCall uses a consistent first-line pattern (tool, action if any, main arg, options).ctx.ui.custom() calls have RPC fallback (undefined check).tool_call hooks check ctx.hasUI before dialog methods.signal is forwarded to all async operations (fetch, child processes, API clients). No unused _signal.pnpm run check:public-deps if available).pnpm typecheck passes.homedir() calls for pi paths -- uses SDK helpers (getAgentDir(), etc.).