Nick Nisi's pi extensions — a pnpm monorepo of independently installable pi packages. Each package under packages/ is a self-contained pi extension (or shared library) with its own pi manifest; install only the ones you want.
Packages are private (not on npm). Install from a local checkout:
git clone <this-repo> ~/Developer/pi-extensions
pi install ~/Developer/pi-extensions/packages/statusline # absolute
pi install ../pi-extensions/packages/btw # relative to the settings fileLocal paths are added to pi's settings without copying — edits in the repo are live on next pi start. Remove with pi remove <path>.
| Package | What it does | Adds |
|---|---|---|
| answer | Extracts questions from the last assistant message via a side LLM call, answers them in a tab-through overlay, sends one formatted reply | /answer, ctrl+., Q&A overlay |
| btw | Side-channel LLM chat in a floating window — sees branch context, never touches the main agent's context; promote or fork the thread | /btw, overlay, btw-answer entry type |
| codemode | Model-written TypeScript orchestrates subagents compositionally (Promise.all fan-out, pipelines) — executed in-process, returns the module result; = console prefix and /cx named snippets run the same runtime inline |
codemode tool, = prefix, /cx command |
| handoff | Transfers context to a new linked session with a model-generated, editable prompt instead of compacting | /handoff <goal> |
| llm-council | Multiple models answer in parallel as in-process child sessions; a chairman synthesizes | llm_council tool with live inline progress |
| relay | Brokerless session-to-session messaging — file mailbox that outlives the process; drop-in pi-intercom replacement | relay tool, /relay |
| subagents | First-party subagent dispatch + fleet: fan out parallel hermetic child agents, inspect live/persisted runs — no pi-subagents dependency | dispatch and fleet tools, /fleet |
| orchestrate | /goal keeps working until a condition holds; /loop re-runs a prompt on a timer |
/goal, /loop |
| workflows | Model-facing front door to the first-party workflow engine: run JS workflow scripts over the subagent runtime with the old third-party tool's globals (agent, parallel, pipeline, phase, log, args, budget, cwd) — evicts @quintinshaw/pi-dynamic-workflows |
workflow tool, /wf |
| save-md | Export the latest assistant response to a markdown file | /save-md <name> |
| Package | What it does | Adds |
|---|---|---|
| compact-tools | Two-line tool displays with original rendering on Ctrl+O or fullscreen click | compact tool display |
| composer | Config-driven boxed input editor; paste-again-to-expand for collapsed paste markers; tmux focus-aware border | custom editor component |
| header | Animated dashboard header (GIF-compiled truecolor frames or ASCII art) with session info, on fresh sessions | /nicknisi-header, custom header |
| mg | Severance-style "100% File Completion" animation starring a pixelated Michael Grinich, with macOS audio | /mg [name] |
| pin-last-prompt | Sticky bar pinning the owning user prompt while scrolled back in fullscreen (pi ≥ 0.84) | scrollback overlay bar |
| recap | LLM "where was I" card injected into the transcript after idle minutes | /recap, /recap-idle, recap entry type |
| spinner | ~1000 rotating joke/meme phrases for the working spinner | — |
| statusline | Footer: model, cost, context bar, lines changed, usage limits, git PR link; writes tmux status files | custom footer, ~/.cache/pi-status/ |
| turn-timer | Dim per-turn elapsed-time row below each response | turn-duration entry type |
| Package | What it does | Adds |
|---|---|---|
| agent-urls | agent:// / history:// URIs for pi-subagents runs; list and read run outputs/transcripts |
/agent, list_agent_runs, read_agent_url tools |
| artifacts | artifact tool: render markdown/HTML to styled browser pages from a lazy localhost server, with live reload |
artifact tool, /artifacts |
| auto-theme | Sync pi theme with macOS system appearance (dark↔light pairs) | — |
| claude-compat | Claude Code compatibility: CLAUDE_PLUGIN_ROOT path shimming + !`command` dynamic SKILL.md placeholders (allowlisted) |
two extension entry points |
| claude-design | Claude Design (claude.ai/design) in pi: design skill over the official MCP server, plus login commands and auth CLI |
design skill, /design-login, claude-design-auth CLI |
| cloak | Redact secrets from read tool results before they reach model context, via glob-scoped regex rules |
/cloak-status, cloak.json |
| fast | Toggle premium faster inference for supported Anthropic Claude and OpenAI Codex models | /fast, footer status |
| model-switch | Cycle or fuzzy-pick from a machine-local, sectioned model list, skipping missing or unauthenticated entries | /model-cycle, configurable shortcuts |
| session-name | Auto-name sessions (heuristic or LLM), mirror to terminal title, name-focused session picker | /sn, /sessions |
| stash | ctrl+shift+s parks the prompt draft on a LIFO stack; pop or auto-restore |
ctrl+shift+s, stash widget |
| Package | What it does |
|---|---|
| shared | @nicknisi/pi-shared — helper library (not an extension): getModelProvider for one-off LLM calls, TUI utilities (gradient text, tree section removal, two-column layout, escape sanitization, render dispatcher), SearchableSelectList, the in-process subagent runtime (createSubagentRuntime), and the declarative workflow engine (runWorkflow). Consumed via workspace:* by 7 packages. |
pnpm install
pnpm typecheck # tsgo (TypeScript 7 native preview)
pnpm build # compile each package to packages/<name>/dist/
pnpm lint # oxlint
pnpm fmt # oxfmtLayout: one directory per package in packages/, each with index.ts + package.json carrying a pi manifest ("pi": { "extensions": ["./index.ts"] }). @earendil-works/* packages are peer dependencies: pi's runtime aliases them to its own modules at load time, and the root devDependencies provide one canonical copy for typechecking (autoInstallPeers: false keeps it that way).
Each package publishes its TypeScript sources and compiled JS, and they are used by different consumers:
| Field | Points at | Used by |
|---|---|---|
pi.extensions |
./index.ts |
pi, which transpiles extensions through jiti |
exports |
./dist/index.js + ./dist/index.d.ts |
everyone else — bundlers, and anything tsc-built |
The split exists because Node refuses to strip types inside node_modules (ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING), so a tsc-built consumer importing raw .ts from a package crashes at runtime. Keeping pi.extensions on the sources means local path installs (pi install ../pi-extensions/packages/statusline) still need no build step, which is the point of the rapid-testing loop.
Consequences worth knowing:
dist/is git-ignored, sopnpm buildruns in CI before publish (seerelease.yml) and from the rootpreparescript afterpnpm install. That hook is load-bearing for local path installs: six packages depend on@nicknisi/pi-shared, which now resolves through its ownexportsintodist/, so a fresh clone with no build would fail to load them in pi. If you ever deletedist/by hand, runpnpm build— a no-oppnpm installwill not re-runprepare.- Relative imports use
.js, never.ts(import { x } from './config.js'), the normal NodeNext convention —allowImportingTsExtensionsis deliberately off so the typecheck catches any regression. pathsin the root tsconfig maps@nicknisi/pi-sharedto its source, so a fresh clone typechecks without building first. The build turns that off (paths: {}) and resolves siblings through their realexportsinstead, which is what proves the declaration output is actually usable.
Cross-package helpers go in packages/shared, consumed as "@nicknisi/pi-shared": "workspace:*".
- Runtime configs live outside the repo:
~/.pi/agent/configs/<name>.jsonfor most packages. Example configs ship with the packages that need them. - Several extensions lean on pi internals (component tree shapes, editor privates, fullscreen renderer state) — each README's caveats section calls these out; a pi upgrade can break them.
- macOS-centric: auto-theme, statusline's tmux integration, and btw's fork-to-window all assume macOS/tmux/ghostty.