Pi agent package development — extensions, skills, install
Pi agent package development — extensions, skills, install
Section titled “Pi agent package development — extensions, skills, install”Related: 2026-09-28 Pi SDK v2 abilities boundary and data model · 2026-09-28 Pi SDK sessions worktrees and TS coordinator · 2026-09-28 Pi Agent SDK bash PATH and Nix flake · 2026-09-28 Opinionated skill packs pstack shape
Developer-facing packaging surface (how to build and distribute packs), not end-user “how to use Pi.” Complements the SDK digests: those cover embedding createAgentSession; this covers the resource types, manifests, pi install workflow, and provider/auth implications.
Pinned: npm @earendil-works/pi-coding-agent 0.87.1 (2026-09-22). Docs: Packages · Extensions · Skills · Custom providers · Models · Configuration · SDK · Changelog. Repo: earendil-works/pi (packages/coding-agent/docs/packages.md).
Package types (what you can ship)
Section titled “Package types (what you can ship)”| Type | What it is | When to use | Needs TS/SDK hooks? |
|---|---|---|---|
| Extension | TypeScript module exporting default (pi: ExtensionAPI) => … | Tools, commands, shortcuts/flags, providers, event handlers, TUI | Yes — runs in-process |
| Skill | Directory with SKILL.md (+ scripts/refs/assets) | On-demand Agent Skills instructions; progressive disclosure | No (model loads via read / /skill:name) |
| Prompt template | Markdown → /filename slash command | Reusable prompts with $1 / $@ args | No |
| Theme | JSON palette (name, colors, optional vars) | Interactive TUI + HTML export colors | No |
| Pi package | npm/git/local bundle of any of the above | Share via pi install; gallery keyword pi-package | Only if it includes extensions |
| Custom provider | Extension calling pi.registerProvider(…) | Unsupported wire protocol, OAuth /login, live discovery | Yes |
| Compatible endpoint | Entry in ~/.pi/agent/models.json | OpenAI-/Anthropic-/Google-compatible proxies (Ollama, vLLM, …) | No — config only, not a package resource |
Official framing (pi.dev packages): packages install and distribute extensions, skills, prompt templates, and themes as one unit. Providers are extensions (or static models.json), not a fifth resource directory.
Layout and manifests
Section titled “Layout and manifests”Conventional directories (zero-config discovery)
Section titled “Conventional directories (zero-config discovery)”my-pi-package/├── package.json # name + keywords: ["pi-package"]├── extensions/ # .ts / .js; dirs with index.ts|js├── skills/ # recursive SKILL.md trees (+ top-level .md skills)├── prompts/ # .md → slash commands└── themes/ # .json themesWithout a pi key, Pi discovers those conventional roots.
Explicit pi manifest
Section titled “Explicit pi manifest”{ "name": "my-pi-package", "keywords": ["pi-package"], "pi": { "extensions": ["./src/extension.ts"], "skills": ["./resources/skills"], "prompts": ["./resources/prompts/*.md"], "themes": ["./resources/themes/*.json"] }}Paths are relative to package root; arrays accept globs and exclusions. Optional pi.image / pi.video for gallery previews.
Dependencies (gotcha)
Section titled “Dependencies (gotcha)”| Put in… | What |
|---|---|
dependencies | Third-party runtime imports used by extensions |
peerDependencies with "*" | Host-provided: @earendil-works/pi-ai, pi-agent-core, pi-coding-agent, pi-tui, typebox — do not bundle / do not list in dependencies |
Bundling host packages can duplicate classes/registries under compiled ESM; Pi warns. Installed packages get separate module roots — do not assume shared dependency instances across packs. Local path packages are not npm install’d by Pi; author owns their tree.
Discovery paths (CLI + DefaultResourceLoader)
Section titled “Discovery paths (CLI + DefaultResourceLoader)”Agent dir defaults to ~/.pi/agent (PI_CODING_AGENT_DIR / SDK agentDir). Project dir is .pi/ under cwd (loads only after project trust).
| Resource | User (agent dir) | Project | Also |
|---|---|---|---|
| Extensions | extensions/ | .pi/extensions/ | settings.extensions[]; package sources; -e |
| Skills | skills/ | .pi/skills/ | ~/.agents/skills/, .agents/skills/ (walk up to repo root); settings.skills[]; --skill |
| Prompts | prompts/ | .pi/prompts/ | settings.prompts[]; --prompt-template |
| Themes | themes/ | .pi/themes/ | settings.themes[]; --theme |
| Package declarations | settings.json → packages | .pi/settings.json → packages | -l / --local on install |
| Installed npm packs | ~/.pi/agent/npm/ | .pi/npm/ | managed node_modules under that root |
| Installed git packs | ~/.pi/agent/git/ | .pi/git/ | pinned @ref skipped by bulk update |
| Models / auth | models.json, auth.json | — | Not package resource dirs; compose with extension providers |
SDK (sdk.md): createAgentSession uses DefaultResourceLoader unless you pass a custom ResourceLoader. Overrides (skillsOverride, extensionFactories, additional*Paths, noExtensions, …) are for host embedders; published packs still go through the same discovery once declared in settings / conventional dirs.
resources_discover extension event can return extra skillPaths / promptPaths / themePaths after session_start.
SDK hooks vs CLI-only packs
Section titled “SDK hooks vs CLI-only packs”Extensions (executable)
Section titled “Extensions (executable)”Minimal tool registration (official examples/extensions pattern):
import { Type } from "@earendil-works/pi-ai";import { defineTool, type ExtensionAPI } from "@earendil-works/pi-coding-agent";
export default function (pi: ExtensionAPI) { pi.registerTool(defineTool({ /* name, parameters, execute */ })); pi.registerCommand("hello", { description: "…", handler: async (args, ctx) => { … } }); pi.on("session_start", async (event, ctx) => { /* start long-lived resources here, not in factory */ }); pi.registerProvider("my-api", { /* Provider or ProviderConfig */ });}Key ExtensionAPI integration points (extensions):
| Capability | API |
|---|---|
| Tools | pi.registerTool() / defineTool; activate with pi.setActiveTools() |
| Slash commands | pi.registerCommand() |
| Shortcuts / CLI flags | pi.registerShortcut() / pi.registerFlag() |
| Providers | pi.registerProvider() / unregisterProvider() |
| Lifecycle | pi.on(event, handler) — unsubscribe returned |
| System prompt | Prefer mutating systemPromptOptions sections/tools in before_agent_start; systemPrompt / forceSystemPrompt replaces whole prompt |
| Cross-extension | pi.events |
| Extra resource roots | resources_discover |
Factory may be async (Pi awaits before startup — needed for providers). Do not start processes/watchers/timers in the factory; use session_start / session_shutdown.
0.87.x extension boundaries (authors must handle): actionable turn_end / agent_before_settle (can append entries + continue: true); context_with_system for full-transcript transforms; SessionManager is canonical for provider context (do not assign session.agent.state.messages to rewrite history). See 2026-09-28 Pi SDK v2 abilities boundary and data model.
CLI-only packs (no register*)
Section titled “CLI-only packs (no register*)”Skills + prompt templates + themes are enough for many opinionated workflows (cf. 2026-09-28 Opinionated skill packs pstack shape). They need no peerDependencies on Pi packages unless an extension is present. Still ship as a Pi package so pi install + gallery discovery work.
Embedder path (not a publishable pack)
Section titled “Embedder path (not a publishable pack)”Hosts can pass extensionFactories / resource overrides into DefaultResourceLoader or a fully custom ResourceLoader without writing files — that is SDK wiring, not something end users pi install.
Auth / models.json implications for packaged providers
Section titled “Auth / models.json implications for packaged providers”| Need | Mechanism | Lives where |
|---|---|---|
| Compatible HTTP API | models.json providers.{id} (baseUrl, api, models / modelOverrides) | ~/.pi/agent/models.json (user-owned; not auto-copied from package) |
| Custom protocol / OAuth / refresh | Extension pi.registerProvider (native Provider preferred over legacy ProviderConfig) | Inside package extensions/ |
| Credentials | /login, env vars, or auth.json ($ENV / !command) | ~/.pi/agent/auth.json — never ship secrets in the package |
| Compose | models.json overlays apply above a registered native provider | Document expected models.json snippets in skill/README |
Credential resolution order (models docs): runtime --api-key → auth.json → models.json apiKey → env / ambient cloud. Packaged providers that add /login store tokens in auth.json like built-ins.
Packaging implication: a provider package ships the extension; operators still configure keys/endpoints locally. Optional companion docs or a skill can describe required models.json / env vars (e.g. community better-custom-provider, pi-models-discovery on pi.dev/packages).
Versioning, publish, install workflow
Section titled “Versioning, publish, install workflow”Commands
Section titled “Commands”pi install npm:@scope/pkg@1.2.3 # pinned exact (preferred for reproducibility)pi install npm:@scope/pkg@^1.2.3 # range — resolved at install; loads if installed version satisfies (fixed post-#5695)pi install git:github.com/user/repo@v1pi install ./local-package # no copy; path relative to settings filepi install -l npm:@scope/pkg # project .pi/settings.json (+ trust)pi -e npm:@scope/pkg # one-shot, do not persistpi list | pi remove <source> | pi config [-l]pi update --extensions # reconcile installed packagespi update --all # CLI + packagespi update npm:@scope/pkg # one packageDeclarations land in packages inside settings. Object form can filter resources:
{ "packages": [{ "source": "npm:@example/pi-tools", "extensions": ["extensions/*.ts", "!extensions/legacy.ts"], "skills": [], "prompts": ["prompts/review.md"] }]}Identity dedupe: npm by package name, git by repo URL (sans ref), local by absolute path. Project entry normally replaces personal; with autoload: false it acts as a filter delta.
Publish checklist
Section titled “Publish checklist”- Conventional dirs or
pimanifest; keywordpi-package. - Host libs in
peerDependencies: { "@earendil-works/pi-coding-agent": "*", … }. - Runtime deps in
dependencies; publish tarball includes them. - npm publish / git tag; users
pi install …@version. - Document trust/security: packages run extension code; review before install / before granting project trust.
npmCommand
Section titled “npmCommand”If installs break under mise/asdf/fnm, set in agent settings:
{ "npmCommand": ["mise", "exec", "node@20", "--", "npm"] }Gotchas on / near 0.87.x
Section titled “Gotchas on / near 0.87.x”| Topic | Note |
|---|---|
| Pinned version | Latest npm 0.87.1 (2026-09-22). 0.87.0 focused on session/extension boundaries, not a packages-format rewrite. |
| Semver ranges | #5695 (fixed ~0.79.x): ranges like @^1.2.7 used to fail discovery; still prefer exact pins for team lockfiles. |
| Peer deps | Host packages must be peers with "*"; putting them in dependencies risks duplicate registries. Managed installs suppress auto peer install. |
| Git pins | @tag/@commit skipped by pi update --extensions; bump with a new pi install …@new-ref. |
| Project trust | Project packages/extensions/skills load only after trust (-a / UI). |
| Extension API churn | 0.87: agent_before_settle, context_with_system, ContextEditEntry, canonical SessionManager. 0.86: user_bash fail-closed; custom streams use TranscriptContext + getCurrentSystemPrompt/getCurrentTools. 0.84: native provider refreshModels → context.publish. Re-check types against 0.87.1. |
| Reload | /reload after editing discovered resources; factory code after await ctx.reload() must not reuse old runtime state. |
| jiti | Local TS extensions need no separate build; distribute via packages when you need dependency installs. |
Concrete official examples
Section titled “Concrete official examples”| Example | Source |
|---|---|
Package layout + pi manifest | packages docs |
| Hello command / tool extension | ~/.pi/agent/extensions/hello.ts pattern in extensions; repo packages/coding-agent/examples/extensions/ (defineTool + registerTool) |
Skill SKILL.md | skills |
Prompt /review template | prompt templates |
| Provider registration | custom-provider (GitLab Duo example referenced in docs) |
| SDK resource overrides | sdk.md examples 04-skills, 06-extensions, 08-prompt-templates, 12-full-control |
| Gallery packages | pi.dev/packages (e.g. web-access, vision-handoff, provider helpers) |
Gaps / thin spots
Section titled “Gaps / thin spots”- Exact on-disk layout under
~/.pi/agent/npm/(lockfile / nestednode_modulesnaming) is implied by CLI + issues, not exhaustively diagrammed in packages.md — treatpi listpaths as authoritative. - No first-party “package generator” CLI beyond “ask Pi to bundle”; scaffolding is convention + docs.
- Whether a package may ship a sample
models.jsonfragment that Pi auto-merges: not documented — assume operators merge manually; packages register providers via extensions only. - Community gallery package quality varies; always review extension source before install.