# Extensions and project preparation

Read for finding, installing or maintaining an Extension, or preparing a new Extension/technical project. Resolve links from this packaged file. Use the customer's actual goal, the current host's public Pi contracts and the smallest suitable existing means.

## 1. Choose the operation and owner

Simple explicit reusable Markdown slashprompt with arguments → native prompt template through [direct authoring](pi-authoring.md#4-author-the-selected-native-artifact). Richer instruction workflows with references → Skill. Executable Commands, Tools, events or UI inside Pi → Extension. An application that must own/embed the conversation needs the public SDK; an external client may instead use native print/JSON/RPC. Do not invent another agent loop.

For an existing package's installation, configuration, update or removal, follow [native packages](packages.md) under the actual action grant. Pi owns external versions and updates. A package operation is not permission to edit its source or run its examples.

For creating/changing executable Extension code or a new project, Workbench prepares a usable handoff; the receiving agent owns detailed planning, implementation and tests. Offer that transfer explicitly rather than claim the project was built.

**Done when** the required outcome, actual source/project, operation, owner and grant are clear. Inspect authorized reality before proposing a destination.

## 2. Describe the smallest native path

Give each required entry an input → action → output and name the meaningful failure/stop case. Pick only needed capabilities:

| Need | Native path and contract |
| --- | --- |
| Human command | `registerCommand` receives string arguments and a Command context. Preserve real supplied input. Returning from the handler does not itself start a model turn. Command-only session controls do not belong in event handlers. |
| Model operation | `registerTool` with a precise description, TypeBox parameters and `execute`. Use `defineTool` for native type inference when useful, not a custom wrapper. |
| Result | Return model-facing `content` and `details` (undefined if unnecessary). Data results use `outputSchema` with matching `structuredContent`. Throw for failure or use `isError: true` when keeping structured error data; error-looking prose alone is not native failure. Bound large outputs and disclose omissions. |
| Authored guidance | `sendMessage` preserves custom provenance. Choose visibility and native steer/follow-up/next-turn delivery deliberately. It is not system authority or a new human decision. Use `sendUserMessage` only for intended user-role input; explicit command/template expansion is a separate native option. |
| Event | Identify the exact event and permitted effect: notification, transformation, gate or continuation. A notification return cannot act as a gate. |
| Nested tool work | Use `ctx.executeTool` so native validation/hooks remain in force; inspect its `isError` outcome. Let native tool results continue the model; no extra resume loop. |

Choose tool callers/exposure deliberately. Active declarations and programmatic reachability are different; respect the user's native restrictions rather than activate everything. Annotations are hints, not a security boundary.

**Done when** the receiver can trace the public path and understand provenance, continuation and failure behavior without an API inventory masquerading as a design.

## 3. Set ownership only where needed

- **Lifecycle:** keep module/factory registration passive. Pi awaits an async factory; it is not a background launcher. Start owned work at the justified session event or explicit operation. Pass supplied signals to cancellable work, release operation resources normally, and await idempotent session-owned cleanup at `session_shutdown`. Use fresh contexts after reload/replacement.
- **Parallelism:** sibling tool calls may overlap. Choose native sequential execution for shared mutable memory and `withFileMutationQueue` for the complete same-file read-modify-write operation. This is not a cross-process lock or multi-file transaction; add no scheduler for hypothetical needs.
- **State:** distinguish branch, session and external durable data. Reconstruct branch state from `getBranch()`, not abandoned file entries. Use result `details`, `appendEntry`, authored messages or external storage for their actual purpose.
- **Modes:** name needed TUI/RPC/JSON/print behavior. `hasUI` can include RPC; terminal features require TUI. Use native UI first and keep the functional core independent of rendering. Missing UI must not silently approve an action. Keep diagnostics out of protocol stdout.
- **Paths:** resolve bundled resources from the module/package, project files from the intended `ctx.cwd`, and user data from an authorized external location such as a native agent-directory subfolder. Package updates must not replace user data.

For final completion use the native host's completion contract; `agent_end` can precede further retries/queued work, while `agent_settled` is final and notification-only. Continue only at an actionable boundary when actually required.

**Done when** each needed resource/state/effect has an owner, start/use/end and relevant check. State explicitly when none is needed instead of adding empty lifecycle machinery.

## 4. Deliver a usable handoff

Choose the intended folder with the user from inspected context. Propose one entry file and only required resources; Pi loads local TypeScript natively, so loading alone needs no build layer. Public imports only. SDK defaults can use real settings, credentials and persistent sessions: specify intended resource/model/storage boundaries before any later execution.

Deliver one compact artifact with confirmed goal/evidence; requirements and exclusions; public inputs/results/failure cases; native choices above; folder/bootstrap proposal; actual grants/open blockers; relevant original paths and receiving owner. Identify applicable Skills by purpose and reading trigger, not a compulsory starter pack. For distribution, reference [package authoring](packages.md#package-authoring-and-publication) rather than duplicate it.

Name later checks appropriate to the design: public types/native loading, argument/error cases, cancellation and awaited shutdown, relevant concurrency/branch/mode behavior, resource resolution from another cwd, complete package assets, and real-model behavior separately. Official examples illustrate selected patterns; inspect the chosen file against current contracts, especially errors, subprocesses and cleanup.

Offer a visible start only when the environment is observed and reliable. Otherwise ask one route-critical question. An offer does not create a folder, launch a process/pane, install code or prove visibility. Do not automatically create topology.

**Done when** the receiver can take over and the customer knows exactly what was prepared, what remains and who owns the next action. A handoff is not implementation, installation or future test success.

## Native sources

Source review on Pi 1.3.0 and live official pages on 2026-10-21; not a version pin or runtime guarantee. At a concrete question use PiQuickDoku and the actual host's complete relevant `docs/extensions.md`, `docs/sdk.md`, `docs/message-types.md`, `docs/packages.md`, public declarations and smallest matching example. Custom TUI, providers/OAuth and MCP registration need their own relevant public docs only when selected.

- [Official Extensions documentation](https://pi.dev/docs/latest/extensions)
- [Official examples](https://github.com/earendil-works/pi/tree/main/packages/coding-agent/examples/extensions)
- [Official SDK documentation](https://pi.dev/docs/latest/sdk)

Resolve material host/source differences before acting. No private-API workaround, parallel runtime or copied handbook.
