Pi pi.dev ↗
Mario Zechner's minimal terminal coding harness, positioned as the main open-source competitor to Claude Code. Stance: no built-in permission popups, no built-in MCP, no built-in sandbox. Hardening is the operator's responsibility.
Use Sessions as Your Audit Trail
Pi writes every message, tool call, and tool result as JSONL into ~/.pi/agent/sessions/ (tree-structured, full history). This is the only built-in audit surface — there is no separate audit log.
Tip: back the sessions directory with append-only storage or ship it to your SIEM; use /export for HTML review; avoid /share for sensitive work (it uploads to a private GitHub gist).
Keep the Harness Off Shared/Public Surfaces
Pi is a local TUI; there is no built-in web server or remote UI to expose. Risk comes from running it inside reachable environments (dev containers exposed via port-forward, shared SSH hosts, CI runners with inbound access).
Tip: run Pi only on workstations or ephemeral containers you control; never run as root; never expose the host's working directory over SMB/NFS while a session is live.
Authenticate via Env Vars or OAuth, Not Committed Files
Pi reads provider credentials from environment variables (ANTHROPIC_API_KEY, etc.) or from OAuth via /login. Custom providers live in ~/.pi/models.json.
Tip: store keys in your OS keychain or a secrets manager and inject at shell-init; never put raw keys in .pi/settings.json. Add .pi/ and ~/.pi/ artifacts to .gitignore globally.
Isolate Execution — Pi Does Not Sandbox Bash
The bash tool runs with the user's full privileges. Maintainers explicitly recommend: "Run in a container, or build your own confirmation flow."
docker run --rm -it \
-v "$PWD":/work -w /work \
--network=none \
-e ANTHROPIC_API_KEY \
pi-runtime piTip: run Pi inside a rootless container or VM with a bind-mounted project dir, dropped capabilities, and --network restricted to the model endpoint only.
Restrict the Tool Surface Explicitly
Pi exposes flags for tool scoping: --tools <list> / -t (allowlist), --no-builtin-tools / -nbt, --no-tools / -nt. Built-ins are read, write, edit, bash, grep, find, ls.
pi -t read,grep,find,ls # review-only session, no writes, no bash
pi --no-builtin-tools # only extension-provided toolsTip: default to the smallest set for the task — read,grep,find,ls for code review, add edit,write for refactors, only enable bash when needed and a sandbox is active.
Lock Down Settings and Config Directories
Pi reads global settings from ~/.pi/agent/settings.json and project overrides from .pi/settings.json. PI_CODING_AGENT_DIR can relocate the global dir. Project settings override global — a malicious .pi/ in a cloned repo can change behavior.
Tip: chmod 600 ~/.pi/agent/settings.json; before opening any third-party repo, find . -path ./.git -prune -o -name '.pi' -print and inspect; treat .pi/extensions/ in a foreign repo as untrusted code.
Treat Extensions and Skills as Arbitrary Code
The README is blunt: "Pi packages run with full system access. Extensions execute arbitrary code, and skills can instruct the model to perform any action including running executables." Extensions load from path, npm, or git via -e, --extension <source>.
Tip: pin extension versions, vendor them into the repo, code-review every update, run with --no-extensions when triaging unknown projects. Maintain an internal allowlist of vetted pi packages.
Defend Against Prompt Injection in Tool Output
Pi has no built-in prompt-injection mitigations — the four-tool design means model-read content (file contents, bash output, fetched pages) flows directly back into context. A poisoned README or web page can instruct the agent to exfiltrate keys or run destructive bash.
Tip: combine tool-restriction (section 5) with network egress filtering (section 4); avoid pointing the agent at untrusted URLs; use --offline mode (PI_OFFLINE=1) when working on sensitive code.
Control Updates and Telemetry
Pi checks https://pi.dev/api/latest-version for updates and reports installs to https://pi.dev/api/report-install.
{
"enableInstallTelemetry": false
}Environment equivalents: PI_SKIP_VERSION_CHECK=1, PI_TELEMETRY=0, PI_OFFLINE=1.
Tip: in regulated environments set all three; pin Pi to a known-good version (npm --save-exact) and gate upgrades through your normal package-review process.
Monitor Sessions and Dangerous Calls
Because permission gating is opt-in via extensions, observability is your primary control. Session JSONL captures every tool call with arguments.
Tip: write a small wrapper extension that streams tool-call events to your log pipeline and blocks high-risk commands (rm -rf, curl | sh, anything touching ~/.ssh, ~/.aws, ~/.pi, .env*). Alert on bash invocations outside the project working directory; rotate provider API keys regularly.