跳转到内容

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).


TypeWhat it isWhen to useNeeds TS/SDK hooks?
ExtensionTypeScript module exporting default (pi: ExtensionAPI) => …Tools, commands, shortcuts/flags, providers, event handlers, TUIYes — runs in-process
SkillDirectory with SKILL.md (+ scripts/refs/assets)On-demand Agent Skills instructions; progressive disclosureNo (model loads via read / /skill:name)
Prompt templateMarkdown → /filename slash commandReusable prompts with $1 / $@ argsNo
ThemeJSON palette (name, colors, optional vars)Interactive TUI + HTML export colorsNo
Pi packagenpm/git/local bundle of any of the aboveShare via pi install; gallery keyword pi-packageOnly if it includes extensions
Custom providerExtension calling pi.registerProvider(…)Unsupported wire protocol, OAuth /login, live discoveryYes
Compatible endpointEntry in ~/.pi/agent/models.jsonOpenAI-/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.


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 themes

Without a pi key, Pi discovers those conventional roots.

{
"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.

Put in…What
dependenciesThird-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).

ResourceUser (agent dir)ProjectAlso
Extensionsextensions/.pi/extensions/settings.extensions[]; package sources; -e
Skillsskills/.pi/skills/~/.agents/skills/, .agents/skills/ (walk up to repo root); settings.skills[]; --skill
Promptsprompts/.pi/prompts/settings.prompts[]; --prompt-template
Themesthemes/.pi/themes/settings.themes[]; --theme
Package declarationssettings.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 / authmodels.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.


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):

CapabilityAPI
Toolspi.registerTool() / defineTool; activate with pi.setActiveTools()
Slash commandspi.registerCommand()
Shortcuts / CLI flagspi.registerShortcut() / pi.registerFlag()
Providerspi.registerProvider() / unregisterProvider()
Lifecyclepi.on(event, handler) — unsubscribe returned
System promptPrefer mutating systemPromptOptions sections/tools in before_agent_start; systemPrompt / forceSystemPrompt replaces whole prompt
Cross-extensionpi.events
Extra resource rootsresources_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.

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.

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”
NeedMechanismLives where
Compatible HTTP APImodels.json providers.{id} (baseUrl, api, models / modelOverrides)~/.pi/agent/models.json (user-owned; not auto-copied from package)
Custom protocol / OAuth / refreshExtension 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
Composemodels.json overlays apply above a registered native providerDocument 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).


Terminal window
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@v1
pi install ./local-package # no copy; path relative to settings file
pi install -l npm:@scope/pkg # project .pi/settings.json (+ trust)
pi -e npm:@scope/pkg # one-shot, do not persist
pi list | pi remove <source> | pi config [-l]
pi update --extensions # reconcile installed packages
pi update --all # CLI + packages
pi update npm:@scope/pkg # one package

Declarations 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.

  1. Conventional dirs or pi manifest; keyword pi-package.
  2. Host libs in peerDependencies: { "@earendil-works/pi-coding-agent": "*", … }.
  3. Runtime deps in dependencies; publish tarball includes them.
  4. npm publish / git tag; users pi install …@version.
  5. Document trust/security: packages run extension code; review before install / before granting project trust.

If installs break under mise/asdf/fnm, set in agent settings:

{ "npmCommand": ["mise", "exec", "node@20", "--", "npm"] }

TopicNote
Pinned versionLatest 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 depsHost 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 trustProject packages/extensions/skills load only after trust (-a / UI).
Extension API churn0.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.
jitiLocal TS extensions need no separate build; distribute via packages when you need dependency installs.

ExampleSource
Package layout + pi manifestpackages docs
Hello command / tool extension~/.pi/agent/extensions/hello.ts pattern in extensions; repo packages/coding-agent/examples/extensions/ (defineTool + registerTool)
Skill SKILL.mdskills
Prompt /review templateprompt templates
Provider registrationcustom-provider (GitLab Duo example referenced in docs)
SDK resource overridessdk.md examples 04-skills, 06-extensions, 08-prompt-templates, 12-full-control
Gallery packagespi.dev/packages (e.g. web-access, vision-handoff, provider helpers)

  • Exact on-disk layout under ~/.pi/agent/npm/ (lockfile / nested node_modules naming) is implied by CLI + issues, not exhaustively diagrammed in packages.md — treat pi list paths 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.json fragment 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.