.pi/extensions/_shared/ is installed by deploy-scenario.sh from shared/extensions/ and is not in the scenario's workspace/, so pi-diff listed it as merely "UNTRACKED in live workspace" -- no comparison at all. The file most likely to drift, because it is the one shared between scenarios, was the one the diff had nothing to say about. Now compared against shared/extensions/ and reported like any other file, with a missing source called out separately. Also fixes the counter: the new branch incremented a variable named `changed` while the summary reads `DIFFS`, so a detected difference printed a diff and then claimed the installation agreed, and exited 0. Verified by planting drift: exit 1 and "1 difference(s) found", then 0 after redeploying.
pi-agent-config
Authoritative configuration for every Pi agent on this host: the user-level Pi runtime, plus one directory per dedicated agent scenario.
The live locations (~/.pi/agent, ~/pi-workspaces/*) are runtime copies.
Changes are made here and pushed out with scripts/deploy-*.sh, never the other
way round — except for scenarios explicitly marked deploy = "mirror", which
record what a running service already does.
Verified against pi 0.84.3. Re-run the probes after every pi update.
Scenarios
| Scenario | Purpose | Service | Status |
|---|---|---|---|
curator |
Book / film / TV / music curation agent | curator.service |
target config written, not yet deployed |
memo-inbox |
Routes Telegram/WeChat messages to Calendar, Obsidian todo or journal | pi-memo-telegram.service |
mirror of live config, zero behaviour change |
pi-grok |
Interactive Grok 4.6 coding agent | none (manual) | registered only |
Start here
| Document | Contents |
|---|---|
docs/pi-runtime-notes.md |
pi 0.84.3 mechanics that the official docs understate, each verified against source or a live probe |
docs/isolation-baseline.md |
The four isolation layers and the flag set every scenario should use |
docs/personality-layering.md |
How to choose between SYSTEM.md, APPEND_SYSTEM.md, AGENTS.md, SKILL.md and the request |
docs/gateway-patterns.md |
Ten patterns for hosting an agent behind a long-running service |
docs/plans/ |
Active work plans |
The finding that motivated this repository
pi emits the <available_skills> block only when a tool named read is
active (dist/core/system-prompt.js:59,113). The Curator service ran with
--no-tools --skill … for its entire lifetime, so:
- its 64-line media policy never reached the model,
--skillwas a no-op,- and both the README and the deployment runbook described a mechanism that was not happening.
Measured on the real workspace, before and after (evidence):
| before | after | |
|---|---|---|
| system prompt | 2548 chars | 3539 chars |
expert coding assistant framing |
present | gone |
| pointer to pi's own documentation | present | gone |
| the 64-line media policy | absent | present |
<available_skills> |
absent | absent |
workspace AGENTS.md |
loaded | blocked |
parent-directory AGENTS.md |
leaked | blocked |
The prompt got larger, and that is the fix rather than its cost: of the original 2548 characters roughly 1.9 KB was pi's coding-assistant scaffolding and a pointer telling the agent to read pi's documentation and follow its cross-references — noise for a media agent, and a ready-made escalation path for injected text — while none of it was Curator's own policy. All 3539 characters now are.
A mechanism demonstration with a stub SYSTEM.md is in
docs/evidence/2026-08-27-isolation-probe.md;
its 960-character figure measures the stub, not Curator.
Reproduce either with docs/evidence/probe-harness/
— zero model tokens, because a single RPC get_state starts the agent, fires
session_start and exits without contacting the provider.
Layout
docs/ mechanics, baselines, plans, reproducible evidence
runtime/agent/ ~/.pi/agent — settings, models.json.template, extensions, prompts
shared/ cross-scenario code
lib/py/pi_rpc.py long-lived RPC client with rotation and budgets
extensions/pi-guard-base.ts path containment, restricted read, capability guard
scenarios/<name>/
profile.toml single source of truth for the launch contract
workspace/ what gets installed into the live workspace
eval/ recorded golden transcripts
scripts/ diff, deploy, backup, restore, secret guard
secrets/ host-local, untracked
Usage
# What differs between this repository and the host?
scripts/pi-diff.sh
scripts/pi-diff.sh curator
# Push configuration out (dry run first; neither restarts a service)
scripts/deploy-runtime.sh
scripts/deploy-runtime.sh --apply
scripts/deploy-scenario.sh curator --apply
# Back up the live installation (archives land outside this repository)
scripts/pi-backup.sh
scripts/pi-restore.sh --from <backup dir>
# Verify the mechanics still hold after a pi upgrade
docs/evidence/probe-harness/collect-evidence.sh
shared/extensions/tests/run-guard-checks.sh
python3 shared/lib/py/tests/test_pi_rpc_smoke.py
Secrets
Nothing real ever enters this repository. models.json, auth.json,
trust.json and every *.env are ignored; secrets/ accepts only .gitkeep,
README.md, *.example and *.template.
scripts/verify-no-secrets.sh enforces this as a pre-commit hook. Install it in
a fresh clone:
ln -sf ../../scripts/verify-no-secrets.sh .git/hooks/pre-commit
scripts/verify-no-secrets.sh --all
Backups contain plaintext credentials and are written outside the work tree;
pi-backup.sh refuses any destination that resolves inside it.
First-time setup on a new host
git clone gitea-45:kai/pi-agent-config.git && cd pi-agent-config
ln -sf ../../scripts/verify-no-secrets.sh .git/hooks/pre-commit
cp secrets/zenmux.env.example secrets/zenmux.env
chmod 600 secrets/zenmux.env && $EDITOR secrets/zenmux.env
npm install -g @earendil-works/pi-coding-agent@0.84.3
scripts/deploy-runtime.sh --apply
scripts/deploy-scenario.sh <scenario> --apply