Personal configuration for the Pi coding agent: a custom theme, five local TypeScript extensions, governed procedural skills, and a few installed pi packages.
~/.pi/
βββ README.md # this file
βββ agent/
β βββ settings.json # global settings (provider, model, packages, theme)
β βββ pix.json # pix extension state/config
β βββ heimdall.example.json # portable example; real heimdall.json is OS-local
β βββ agents/ # custom routed roles (Mechanic, Bugtester, β¦)
β βββ npm/
β β βββ package.json # installed pi package manifest
β β βββ package-lock.json # installed pi package lockfile
β βββ package.json # editor-only devDependencies (see "Editor setup")
β βββ tsconfig.json # editor-only TS config (see "Editor setup")
β βββ pi-hermes-memory/
β β βββ skills/ # global reusable Pi skills (published)
β βββ projects-memory/
β β βββ <project>/skills/ # project-scoped reusable Pi skills (published)
β βββ extensions/ # auto-discovered local extensions (*.ts)
β β βββ alarm-sound.ts
β β βββ pi-autoupdate.ts
β β βββ skill-governor/ # lifecycle governance, routing, audit, quarantine
β β βββ stargate-header.ts
β β βββ token-speed.ts
β βββ skill-governor/
β β βββ config.json # tracked policy; candidates/evidence stay local
β βββ themes/
β βββ stargate-sg1.json # custom theme
Extensions placed in ~/.pi/agent/extensions/*.ts are auto-discovered for all
projects and can be hot-reloaded with /reload.
Wraps Pi's own update mechanism so updates can be triggered from inside a session (by you or by the model).
It delegates to the pi CLI rather than calling npm directly, because Pi
packages are not global npm installs β they live under ~/.pi/agent/npm/,
.pi/npm/, and ~/.pi/agent/git/β¦ and are managed by pi update.
Command:
/updateβ update Pi and all packages/update selfβ update Pi only/update extensionsβ update packages only/update checkβ report whether a Pi (self) update is available
Tool (pi_update, callable by the model):
scope:"all"(default),"self", or"extensions"check: only check the Pi version, don't installconfirm: deprecated compatibility field; ignored (authority is derived from the direct request)force: reinstall Pi even if current (only withscope: "self")
A direct natural-language request such as βPi und die Extensions aktualisierenβ
authorizes exactly that scope for one model-tool call without a second popup.
βNur Piβ and βnur die Extensionsβ cannot silently escalate to the other scope;
forced reinstall additionally requires explicit wording. Quoted examples,
meta-questions, conditional requests, and negations grant no authority. An
unrequested model update is blocked automaticallyβeven if the model requests a
confirmation popup. Typing a valid /update ... command is itself explicit
authority; typos show usage instead of defaulting to a full update.
Version-pinned npm specs and pinned git refs are skipped automatically by
pi update, so the extension does not special-case them.
On Windows, package updates pause pi-intercom's detached broker and hold its
respawn lock while npm replaces packages. Cancellation propagates through
network checks and child processes; the broker working-directory patch is
re-applied before the lock is released, including after partial failures or
user cancellation. It also preserves a Windows compatibility patch for
pi-subagents: async workflows use an independent UUID for their runtime
directory because Pi 0.84 tool-call IDs may contain the Windows-invalid |
character. The tracked agent/npm/patches/postinstall.cjs applies this fix
while Pi installs package dependencies, before the package is first loaded;
the update extension re-checks it only during an explicitly requested later
update. Merely starting Pi performs no package-source or OS-config mutation.
Occasionally a package is published to npm with an unresolved workspace:*
dependency (a pnpm/yarn monorepo protocol that plain npm cannot resolve). When
that happens, pi update's internal npm install β¦@latest fails with
EUNSUPPORTEDPROTOCOL, which aborts the entire package update β so one
broken upstream release blocks every other package too.
Before running pi update, the extension pre-flights the latest version of
each declared npm package against the public registry. Any package whose latest
version still carries a workspace: dependency is treated as "do not update":
the extension updates the remaining packages individually (pi update npm:<pkg>) and skips the broken one, keeping its currently-installed (good)
version. This is self-healing β once the author publishes a fixed version the
pre-flight finds nothing broken and the normal bulk update resumes. The
pre-flight is fail-open (offline / custom-registry / errors never block
updates). It was added after @xynogen/pix-optimizer@1.1.14 shipped
"@xynogen/pix-data": "workspace:*".
Plays the configured MP3 when Pi finishes, ask_user_question waits for input,
or any extension opens a yes/no confirmation. Permission selectors such as
MCP/RTK allow-or-deny dialogs are detected as well; ordinary menus do not ring.
The wrapper is shared across extensions and deduplicates an already-running
alarm. Use /alarm-sounds on|off|test|status to control, test, or diagnose it.
Replaces the startup header with an open Stargate Command console banner (chevron crown, rounded gate ring with an event-horizon beam, A-frame stand). Width-adaptive and re-rendered live on theme, model, skill, and extension changes.
Commands:
/headerβ toggle between full and quiet mode/refresh-headerβ re-scan skills and extensions
Custom footer showing context usage with a progress bar, measured generation speed (tokens/second), the active thinking level, and estimated thinking and output token counts, with the model and git branch right-aligned.
Applies lifecycle governance to procedural skills without patching package
extensions. Per task it exposes at most five positively matched automatic skill
descriptions; unmatched auto skills stay lazy-searchable. Manual/canary text is
read-only and can be loaded without a popup; the actions described inside remain
separately guarded. It blocks direct skill_manage mutations, writes new
procedures to an undiscovered candidate store, and requires three distinct
recurring observations before automatic generation. Generator/critic calls stay
on the current provider by default; static audit, independent criticism,
subtractive repair, digest-bound evidence, canary, qualified activation,
retirement, and rollback form separate lifecycle gates.
Commands:
/skill-governor status|candidatesβ inspect the current library/candidate state/skill-governor audit <name>β run the paper-derived static triage/skill-governor evolveβ force a candidate proposal from the latest task/skill-governor evidence <id> <json-file>β import digest-bound paired evidence/skill-governor promote <id> [canary|active] [--override]β explicit promotion; incomplete active qualification needs the deliberate override flag/skill-governor retire <name> <reason>/rollback <id>β reversible removal/skill-governor allow-write <path>β authorize exactly one ordinary edit/write
The v2.5 low-noise policy confines runtime interception to actual file-tool or
shell mutations of governor-owned paths. Opaque inputs for Todo, web research,
subagents, memory, MCP, and Intercom are never reinterpreted as filesystem
paths; Windows containment also rejects cross-volume path.relative() results
instead of treating another drive as part of ~/.pi. Test names and prose that
mention the governor remain usable.
Ordinary repository commandsβincluding requested dependency and release workβ remain bounded by the user's task and by the dedicated tool executing them; skill-governor no longer acts as a second global shell permission system. A direct request to edit skills or the governor is still scope-bound, survives informational follow-ups, and can be explicitly revoked. If a genuine decision could cause irreversible loss, credential exposure, or effects outside the requested scope, the agent asks one plain-language question instead of exposing a raw command approval dialog.
The skill_route and skill_governor model tools expose controlled lazy
routing and candidate submission. Runtime candidates, evidence, snapshots, and
retired copies stay local under agent/skill-governor/; only config.json is
tracked. On Windows this is strong tool-layer defense-in-depth, not an OS
security boundary, because Pi and extensions still run as the logged-in user.
Declared in settings.json (and/or user settings). See each package upstream
for details:
npm:pi-llama-cppβ local llama.cpp provider integrationnpm:pi-mcp-adapterβ MCP server adapternpm:pi-web-accessβ web access tools
The current installed package manifest is also tracked in
agent/npm/package.json / agent/npm/package-lock.json so the repository
reflects the package set managed by pi update.
agent/heimdall.json is intentionally not tracked. Heimdall's sandbox uses
Linux bubblewrap, so the bundled pi-autoupdate.ts extension keeps the real
local config aligned with the current OS:
- Linux:
sandbox.enabled = true - Windows:
sandbox.enabled = false - macOS:
sandbox.enabled = falseuntil Heimdall supports a macOS sandbox
This prevents Windows/Linux/macOS checkouts from constantly dirtying Git with an
OS-specific config flip. agent/heimdall.example.json documents the portable
shape of the config.
Other local runtime files are ignored too, including generated Heimdall defaults,
agent/models-store.json, mission indexes, run history, intercom/session state,
SQLite lock databases (including WAL/SHM sidecars), Hermes memory databases, and
project MEMORY.md files. Credential files, private keys, certificates, tokens,
and environment files are excluded defensively as well.
Reusable Pi skills are intentionally tracked because they can help other users even on different systems:
agent/pi-hermes-memory/skills/**/SKILL.mdβ global skillsagent/projects-memory/*/skills/**/SKILL.mdβ project-scoped skills
Only the skill files are published; private memory files and session databases remain ignored.
stargate-sg1 β an amber/orange SGC terminal palette. Selected via
"theme": "stargate-sg1" in settings.json. The theme file references a
remote $schema; VS Code may warn that the schema URL is "untrusted" and skip
download. That is cosmetic and does not affect Pi, which validates themes
itself.
Key fields in agent/settings.json:
defaultProvider/defaultModelβ the provider and model used on startuppackagesβ installed pi packagesthemeβ active theme namecompactionβ context compaction thresholdsthinkingBudgets/defaultThinkingLevelβ reasoning token budgets per levelsubagentsβ central role-to-model routing and local fallback policy
The parent orchestrator stays on GPT-5.6 Sol High. Child roles use the cheapest appropriate tier without per-run model overrides:
| Tier | Intended work | Roles |
|---|---|---|
| GPT-5.3 Codex Spark Low (128k) | Mechanical repo scans, targeted reproductions, tiny obvious fixes | scout, context-builder, delegate, bugtester, mechanic |
| GPT-5.6 Luna Low | Lightweight non-mechanical evidence synthesis | web-searcher |
| GPT-5.6 Terra Low | Substantial implementation and research | worker, researcher |
| GPT-5.6 Sol High | Leadership, planning, critical review, architecture judgment | teamleiter, advisor, oracle, planner, reviewer |
Spark is also the subagent default, so unclassified roles do not silently inherit
the expensive parent model. Local llama-server fallbacks are intentionally omitted
while the provider/local alias is absent from Pi's active model registry:
pi-subagents validates every fallback before launch, so a configured offline alias
would block even a healthy cloud primary. Add the exact registered
llama-server=http://127.0.0.1:1234/local candidate only while /v1/models
actually exposes it. Tasks that may exceed Spark's 128k window or require
non-mechanical judgment must be escalated upward.
Out of the box, opening this folder in VS Code shows errors such as
Cannot find module '@earendil-works/pi-coding-agent', Cannot find name 'process', and several "implicitly has an 'any' type" warnings.
These are editor-only. Pi loads extensions through jiti, which resolves TypeScript and the pi packages at runtime with its own bundled copies β the extensions run fine regardless of what the editor reports.
To give the TypeScript language server the types it needs, install the editor-only dependencies once:
cd ~/.pi/agent
npm installOn Windows:
cd %USERPROFILE%\.pi\agent
npm installThis installs @types/node (fixes process and node:*), the pi packages
(@earendil-works/pi-coding-agent, @earendil-works/pi-tui,
@earendil-works/pi-ai), the modern typebox package, and TypeScript. The
tsconfig.json ties it together. Once types resolve, the implicit-any errors
disappear too, because the callback parameter types are inferred from the pi
API.
For a clean checkout, also restore the tracked Pi runtime manifest; its postinstall hook applies required package compatibility patches before loading:
npm --prefix npm installValidate both the local extensions and runtime dependency set with:
npm run typecheck
npm test
npm audit --omit=dev
npm --prefix npm audit --omit=devThese are devDependencies and are not used by Pi at runtime. If you prefer not
to add a local node_modules, the errors are safe to ignore.
Update everything (Pi and packages) from a shell:
pi update --allOr from inside a session with the bundled command:
/update
