name: pi-extension description: Create, update, and publish Pi extensions. Use when working on Pi extension packages, custom tools, commands, providers, hooks, TUI components, skills, prompts, or themes.
Pi Extension Development
Use this skill to build and maintain Pi packages. Read the reference file for the area you are changing before editing.
Package Namespace
Pi core packages are moving from @mariozechner/* to @earendil-works/*.
- Prefer
@earendil-works/*for new or migrated code once the target package exists on npm. - Keep legacy
@mariozechner/*imports when the target version is not published under the new namespace yet. - Do not mix namespaces inside one package unless you are deliberately supporting a staged migration.
Core packages provided by Pi at runtime:
@earendil-works/pi-coding-agent— extension API, types, tools, utilities.@earendil-works/pi-tui— TUI components.@earendil-works/pi-ai— AI utilities such asStringEnum.typebox— TypeBox 1.x schemas. Do not use@sinclair/typeboxin new code.
Standard Imports
import { ToolBody, ToolCallHeader, ToolFooter } from "@aliou/pi-utils-ui";
import type { AgentToolResult, ExtensionAPI, Theme } from "@earendil-works/pi-coding-agent";
import {
defineTool,
formatSize,
getMarkdownTheme,
keyHint,
truncateHead,
withFileMutationQueue,
} from "@earendil-works/pi-coding-agent";
import { StringEnum } from "@earendil-works/pi-ai";
import { Container, Markdown, Text } from "@earendil-works/pi-tui";
import { type Static, Type } from "typebox";
If using the legacy namespace, replace @earendil-works/* with the matching @mariozechner/* package.
Workflow
Creating a new extension
- Read
references/structure.mdfor layout, package metadata, config, event bus, and entry-point rules. - Create
src/config/withtypes.ts,defaults.ts,loader.ts, andmigration/. - Create
src/events.tswith event bus constants and payload types. - Create the main extension under
extensions/my-domain/(config, settings, feature discovery). - Create sub-extensions under
extensions/for each feature (tools, providers, etc.). - Read feature-specific references:
- Tools: read
references/tools.md. - Commands: read
references/commands.md. - Hooks/events: read
references/hooks.md. - Providers: read
references/providers.md.
- Tools: read
- For TUI work, read
references/components.mdand Pidocs/tui.md. - For mode-sensitive UI, read
references/modes.md. - For persistent state or custom messages, read
references/state.mdandreferences/messages.md. - For publishing, read
references/publish.mdandreferences/documentation.md.
Modifying an existing extension
- Read
package.jsonto find Pi entry points. - Read the entry point and the relevant reference file.
- Follow the extension's existing structure, even if it differs from the recommended multi-extension pattern. Do not restructure unless the user explicitly asks.
- Check the current Pi docs/changelog if changing Pi APIs.
- Update code and docs together.
- Run typecheck and lint when available.
Reference Files
| File | Content |
|---|---|
references/structure.md |
Multi-extension layout, package.json, tsconfig, config split, event bus, entry points, API-key pattern. |
references/tools.md |
defineTool, schemas, execute signature, prompt metadata, rendering, truncation, concurrency. |
references/commands.md |
Slash commands, argument completion, session methods, rich UI fallback. |
references/hooks.md |
Event lifecycle, blocking/cancelling, input transforms, system prompt hooks, bash hooks. |
references/components.md |
Pi TUI component interface, built-ins, custom UI, overlays, key handling. |
references/providers.md |
pi.registerProvider(name, config), OAuth, streaming, model metadata. |
references/modes.md |
Interactive/RPC/JSON/Print behavior and fallback patterns. |
references/messages.md |
sendMessage, registerMessageRenderer, notification choices. |
references/state.md |
Reconstructible state via tool result details, appendEntry usage. |
references/additional-apis.md |
Shortcuts, flags, exec, session control, reload, UI customization. |
references/publish.md |
npm publishing, changesets, GitHub Actions, pre-publish checklist. |
references/testing.md |
Local testing, type checking, hook tests, core-unit testing. |
references/documentation.md |
README and changelog guidance. |
Reference Extensions
pi-extension-template(/Users/alioudiallo/code/src/pi.dev/pi-extension-template/): Multi-extension pattern, event bus, nested config, autocomplete provider, settings.pi-linkup(/Users/alioudiallo/code/src/pi.dev/pi-linkup/): API tools, prompt metadata, output truncation, API-key gating.pi-synthetic(/Users/alioudiallo/code/src/pi.dev/pi-synthetic/): Provider + tools, command UI, API-key gating.pi-processes(/Users/alioudiallo/code/src/pi.dev/pi-processes/): Multi-action process tool, prompt metadata plus orchestration guidance, unit-tested core manager.pi-linear(/Users/alioudiallo/code/src/pi.dev/pi-linear/): Multi-action tool, settings UI, auth wizard, config migrations.pi-obsidian(/Users/alioudiallo/code/src/pi.dev/pi-obsidian/): CLI wrapper with separate core package andpi.exec()usage.
Critical Rules
- When modifying an existing extension, preserve its current structure. Do not migrate to the multi-extension pattern unless the user explicitly asks.
src/is Pi-agnostic in new extensions: no imports from@earendil-works/pi-*. All Pi registration code lives underextensions/.- One Pi extension entry point per domain directory under
extensions/. The main extension owns config, settings, and feature discovery. - Use the event bus (
src/events.ts) for main-sub-extension communication:domain:feature:request,domain:feature:register,domain:config:updated. - Config in
src/config/withtypes.ts,defaults.ts,loader.ts, andmigration/. Use per-feature nested sections. - Define
type MyToolParams = Static<typeof parameters>for helper/action APIs, but prefer inference insidedefineToolcallbacks. - Tool execute signature is
(toolCallId, params, signal, onUpdate, ctx). Signal comes beforeonUpdate. - Always call
onUpdate?.(...)with optional chaining. - Every tool needs
label. AddpromptSnippetwhen the tool should appear in Available tools. - Every
promptGuidelinesbullet must name the exact tool. Do not saythis tool. - Use
StringEnumfrompi-aifor model-facing string enums. Do not useType.Union([Type.Literal(...)])for enums. - Handle
renderResultpartial state first with a stable tool-scoped message. - Detect tool errors by missing expected
detailsfields orcontext.isError; thrown tools receivedetails: {}. - Use
ToolCallHeader,ToolBody, and conditionalToolFooterfor tool rendering. - Use existing TUI components before creating custom components.
ctx.ui.custom()needs RPC/print fallback. Interactive close paths must not rely ondone(undefined).- Dialog methods that gate behavior need
ctx.hasUIchecks; fire-and-forget UI methods do not. - Forward abort signals to
fetch,pi.exec, SDK clients, and long-running work. - Use
pi.exec()for normal shell commands. Do not use Nodechild_processunless a documented long-lived streaming process requires it. - File-mutating tools must normalize leading
@paths and usewithFileMutationQueue()for the full read-modify-write window. - Large output tools must truncate output, report truncation, and save full output to a temp file.
- Store branch-aware tool state in tool result
detailsand reconstruct fromctx.sessionManager.getBranch(). - After
ctx.newSession(),ctx.fork(), orctx.switchSession(), do post-switch work only inwithSession. - Treat
await ctx.reload(); return;as terminal in a command handler. - Provider dynamic model discovery belongs in an async extension factory, not
session_start. - Use SDK helpers for Pi paths instead of
homedir()when helpers exist. - No
.jsextensions in TypeScript imports. - Pi core packages you import belong in optional
peerDependencies; use"*"by default, or">=x.y.z"only when code needs an API introduced after Pi 0.74.0. Keep exact target versions indevDependencies. tsconfig.jsonmust include bothsrc/**/*.tsandextensions/**/*.ts.
Completion Checklist
-
package.jsonlists extension entry points underextensions/and package resources. -
src/has no@earendil-works/pi-*imports. - Config in
src/config/withtypes.ts,defaults.ts,loader.ts,migration/. - Event bus in
src/events.tswith domain-prefixed event names. - Main extension owns config loading, settings, and feature discovery.
- Sub-extensions register via event bus.
- Imported Pi core packages are optional peers and exact dev deps.
- Tools use
defineTool, labels, prompt metadata where appropriate, correct execute order, optionalonUpdate, and signal forwarding. -
promptGuidelinesbullets name the exact tool. - Tool renderers return components, handle partial/error states, and use compact collapsed views.
- Custom UI has RPC/print fallback and explicit sentinels.
- Providers use current provider/model fields (
name,authHeader,thinkingLevelMap, OAuth where needed). - State is reconstructible across reload/fork/compaction.
- No
child_process, nohomedir()for Pi paths, no.jsimport suffixes, no@sinclair/typebox. -
tsconfig.jsonincludes bothsrc/andextensions/. - README documents setup, tools, commands, providers, env vars, and limitations.
- Typecheck and lint pass.