Pi harness
Capability: capability:platform
Harness: Pi
Pi (CLI pi, npm @earendil-works/pi-coding-agent) is a minimal terminal coding agent.
Out of the box it runs every tool call without asking and has no sandbox, so Magpie ships the secure setup as a Pi extension: an action guard, permission rules, and an OS sandbox for bash.
The setup is per user, never per repository: one pi install adds the skills and the extension to the user’s ~/.pi/agent/settings.json, and the extension reads no project configuration, so a repository cannot weaken it.
The adapter is experimental: it was validated with Pi 1.4.0 on macOS; Linux and Windows have not been verified.
The integration follows the harness contract in add-a-harness and RFC-AI-0004.
Harness contract
| Magpie requirement | Pi implementation |
|---|---|
| Skill discovery | Pi reads .agents/skills/ from the working directory up to the repository root, the canonical universal row in skills/setup/agents.md. The Pi package adds the framework’s skills/. Each skill is also a /skill:<name> command. |
| Repository instructions | Pi loads AGENTS.md (and CLAUDE.md) natively, before project trust. |
| Tool bridges | Skills invoke the existing tools/* CLI adapters through the bash tool, subject to the extension’s rules and sandbox. |
| Deterministic guard | The extension sends every bash command to agent_guard/__init__.py --pi before it runs; a deny blocks the call. See agent-guard. |
| Permission rules | The extension derives them from the Claude Code baseline (expected.json): denied commands are blocked, asked ones need confirmation, and native reads and writes of credential paths, .env files, agent settings and Pi’s own configuration are refused. |
| Filesystem and network | Bash runs in @anthropic-ai/sandbox-runtime, the engine of Claude Code’s sandbox, with the baseline’s denyRead / allowRead / allowWrite and domain allowlist. |
| Credential isolation | The sandbox strips the baseline’s credential variables (GH_TOKEN, cloud keys, …) from bash; agent-iso pi launches Pi through the generic clean-environment wrapper. |
| Spec-loop | The pi profile runs pi -p headless; see Spec-loop runner. |
| MCP servers | Pi has no built-in MCP; Magpie’s skills use the tools/* CLI adapters instead. |
The extension is tools/agent-isolation/pi/magpie.ts; its decisions live in policy.ts, which reads the same baseline the Claude Code profile is linted against, so the two profiles cannot drift apart.
The repository’s root package.json makes the repository a Pi package that carries both the skills and the extension.
Install
Use Pi 1.4.0 or later and Python 3.11+ (for the guard).
On Linux the sandbox also needs bubblewrap, socat and ripgrep; use the framework’s sandbox primitive versions.
pi install git:github.com/apache/magpie
That one command is the whole install, for every repository: Pi clones the framework, installs the pinned sandbox dependency, and records the package in ~/.pi/agent/settings.json.
Pi runs npm install --omit=dev --legacy-peer-deps in its clone, which honours the committed package-lock.json: every package in the sandbox runtime’s tree is pinned to an exact version and integrity hash, and none has an install script.
To refresh the lockfile, resolve with the same flags and the repository’s 7-day cooldown, without installing or running anything:
npm install --package-lock-only --ignore-scripts --omit=dev --legacy-peer-deps \
--before="$(python3 -c 'import datetime; print(datetime.date.today() - datetime.timedelta(days=7))')"
Dependabot proposes the same updates weekly, with the same cooldown.
Never install it per project with pi install -l; the secure setup belongs to the user.
For guided setup, ask Pi: /skill:isolated-setup-install.
Then start every session through the clean-environment wrapper:
source "<framework>/tools/agent-isolation/agent-iso.sh"
agent-iso pi
Pi keeps provider credentials in ~/.pi/agent/auth.json after /login; pass an API-key variable explicitly with AGENT_ISO_ALLOW=<NAME> agent-iso pi when you use one instead.
Security model
What asks and what denies
| Requested action | Result |
|---|---|
| A bash command that matches no rule | Runs in the OS sandbox without a prompt. |
A read-only gh command from the baseline’s allow list, as plain words |
Runs outside the sandbox, with gh’s own credentials. |
git push, mutating gh commands, gh api with a method or field flag |
Asks; refused in a non-interactive run. |
Any other gh command outside the sandbox |
Asks. |
Credential and export commands, such as curl, gh auth token, cloud CLIs |
Denied. |
A command agent-guard denies (a Co-Authored-By trailer, --no-verify, …) |
Denied, with the guard’s reason. |
Native read / grep / find / ls of credential paths or .env files, or rooted above them |
Denied, symlinks resolved. |
Native write / edit of agent settings, ~/.pi/agent/ or .pi/ |
Denied. |
Native write / edit outside the working folder, symlinks resolved |
Asks; refused in a non-interactive run. |
Deny outranks ask, which outranks allow, as in Claude Code. A command leaves the sandbox only when it is plain words: quotes, escapes, expansions, redirections and operators keep it inside.
Sandbox boundaries
A probe with Pi 1.4.0 on macOS observed:
| Probe | Result |
|---|---|
cat ~/.ssh/known_hosts |
Blocked. |
test -r ~/.gitconfig |
Readable (in the baseline’s allowRead). |
touch ~/probe |
Blocked. |
A request to example.com |
Blocked by the domain allowlist. |
A request to api.github.com |
Allowed. |
| A write in the workspace | Allowed. |
echo $GH_TOKEN |
Empty. |
If the sandbox cannot start, the extension refuses bash rather than running it unsandboxed.
pi --magpie-no-sandbox runs one session without it; the guard and rules still apply.
Limits
- Native file tools and extension tools run in the Pi process, outside the sandbox; the rules above gate the built-in ones, not tools other extensions add.
- A rule for a file name anywhere (
**/.env) cannot stop a directory search from reading such a file; Pi’sgrepandfindfollow.gitignore, which usually lists them. Neither follows symlinks, so a search cannot walk through a link into a denied directory, and file tools are handed the checked path with links already resolved. - The extension’s command rules are a friction layer; the guard and the sandbox are the enforcement.
@anthropic-ai/sandbox-runtime0.0.80 pullsnode-forgeandzodversions with open advisories in its TLS-interception and validation paths, which this extension does not drive with untrusted input.
Spec-loop runner
The pi profile in tools/spec-loop/lib.sh runs pi -p, forwarding --model and --thinking when supplied.
A non-interactive run has no UI, so every command that would ask is refused: a build iteration needing a push or a mutating gh call cannot complete unattended.
See the spec-loop guide.
Verify
Ask /skill:isolated-setup-verify, or check by hand:
pi --version
pi list
pi list must show git:github.com/apache/magpie, and the startup header of an interactive session must list the magpie.ts extension.
Then make these requests to the model rather than typing the commands yourself:
| Request | Expected result |
|---|---|
Run exactly git status --short. |
Runs. |
Run exactly cat ~/.ssh/known_hosts. |
Fails inside the sandbox. |
Run exactly gh auth token --help. |
Denied by the rules. |
Run exactly git commit --dry-run --no-verify -m hook-probe. |
agent-guard[no-verify] denial. |
Run exactly git push --dry-run. |
Asks before running. |
Read ~/.ssh/config with the read tool. |
Denied. |
Inspect the actual tool results; a verbal refusal by the model does not establish enforcement.
Update
pi update --extensions pulls the framework package to its pinned ref and reinstalls its dependencies.
Ask /skill:isolated-setup-update for a read-only drift report first.
Doctor
| Symptom | Check and next step |
|---|---|
| Bash refused: “the OS sandbox could not start” | On Linux install bubblewrap, socat and ripgrep; check that pi update --extensions installed the package’s dependencies. |
| Guard never denies | Check python3 --version (3.11+) and that pi list shows the framework package. |
| A command fails only inside the sandbox | Network and most of the home directory are unavailable there. Report what it needs; do not widen the baseline without the operator’s decision. |
| A command keeps asking in a headless run | Asked commands need an interactive session. |
setup-isolated lifecycle
The four setup-isolated-setup-* skills route Pi sessions to Install, Verify, Update, and Doctor.
Uninstall is pi remove git:github.com/apache/magpie, which removes the skills, the guard and the sandbox together.