Platform: Linux / WSL. macOS may work but hasn't been tested. Windows is not supported.
Pi Guard is a high-agency, OS-level sandbox for Pi. Let your Agent work freely where it should, block it where it shouldn’t — with real boundary enforcement, interactive permission prompts, and no heavy workflow overhead.
- 🧠 High-agency: full freedom inside the workspace, hard stops only at the boundary
- 🪶 Clean: minimal setup, intuitive config, low-friction daily use
- 🛡️ Hardened: bash runs in a real sandbox, not string-matching theater
- 🤝 Composable: coexists with
pi-tool-displayand other bash-overriding extensions - 🎯 One package, done: no need to stitch together a stack of guardrail tools
- 0.2.1 — Sandbox now inherits host environment variables and uses the real
HOME. Fixes tools that read config files or API keys from~/.paths (e.g. Tavily). - 0.2.0 — Network toggle:
/guard non//guard noffto allow or block all outbound network. Default open. Footer shows· network: open|blocked. - 0.1.0 — Initial release: write-boundary protection, read-only / workspace-write modes, sandboxed bash, dangerous command blocking.
| Tool | Purpose | Install |
|---|---|---|
bwrap |
Linux process sandbox | sudo apt install bubblewrap |
socat |
Sandbox network proxy | sudo apt install socat |
rg |
File scanning | sudo apt install ripgrep |
pi install npm:pi-guard-sandbox # global — all projectspi install -l npm:pi-guard-sandbox # project-local onlyAfter installation, enter your project and run /guard i to initialize.
If you've cloned this repository, the extension is already at .pi/extensions/pi-guard/:
cd .pi/extensions/pi-guard && npm installStart Pi, then run /guard i.
For a global install from this repo: copy
.pi/extensions/pi-guard/to~/.pi/agent/extensions/pi-guard/and runnpm installthere.
Know what you're getting into.
| Item | Description |
|---|---|
.pi/pi-guard.json |
Created on init — all Guard configuration |
| footer status line | Persistent mode indicator at the bottom of Pi |
| sandboxed bash | All Agent bash commands run in a sandbox, not directly on the host |
vendor/ directory |
~1.8 MB — sandbox runtime (forked from @anthropic-ai/sandbox-runtime) |
.pi/extensions/pi-guard/ |
The extension code itself |
Delete
.pi/pi-guard.jsonand run/reloadto disable Guard.
Start Pi in your project directory:
/guard i → initialize — creates config
/guard r → switch to read-only mode
/guard w → switch to workspace-write (default)
Guard takes effect immediately after initialization. The footer shows the current mode.
| Command | Shortcut | Purpose |
|---|---|---|
/guard |
— | Show status and configuration |
/guard init |
/guard i |
Create .pi/pi-guard.json and enable Guard |
/guard read-only |
/guard r |
Switch to read-only |
/guard workspace-write |
/guard w |
Switch to workspace-write |
/guard network on |
/guard non |
Allow all outbound network (default) |
/guard network off |
/guard noff |
Block all outbound network |
Note: Even with network open,
ping(ICMP) is unavailable inside the sandbox. Bubblewrap dropsCAP_NET_RAWby default. HTTP/HTTPS (curl, wget, git, etc.) work normally.
| read-only | workspace-write | |
|---|---|---|
| Read inside workspace | ✅ | ✅ |
| Read outside workspace | ✅ (sensitive paths excluded) | ✅ (sensitive paths excluded) |
| Write inside workspace | ❌ | ✅ |
| Write outside workspace | ❌ | ❌ (requires approval) |
| Bash commands | ✅ (no persistent writes) | ✅ (workspace + /tmp writable) |
| Bash writes outside workspace | ❌ | ❌ |
| Dangerous commands | blocked + approval | blocked + approval |
~/.ssh ~/.aws ~/.gnupg ~/.git-credentials
~/.npmrc ~/.pypirc ~/.netrc ~/.env ~/.env.*
User-typed !cmd / !!cmd are not guarded. Guard only covers Agent-initiated tool calls.
| Status | Cause | Action |
|---|---|---|
Guard: uninitialized |
Not yet initialized | Run /guard i |
Guard: invalid-config |
JSON syntax error | Fix .pi/pi-guard.json, then /reload |
Guard: sandbox-unavailable |
Missing system deps or npm install skipped | Follow Section 1 — check bwrap, socat, rg |
/guard init generates this file. You can edit it by hand (requires /reload to take effect).
{
"mode": "workspace-write",
"network": "open",
"sensitiveReadDeny": [
"~/.ssh",
"~/.aws",
"~/.npmrc"
],
"protectedPaths": {
"block": [
".git",
"node_modules"
],
"approval": [
".env",
".env.*",
".pi/pi-guard.json"
]
},
"bashPolicy": {
"directBlock": [
"sudo",
"su",
"dd"
],
"requireApproval": [
"rm-rf",
"git-reset-hard",
"git-clean-fd"
]
}
}| Field | Description |
|---|---|
mode |
"readonly" or "workspace-write". Switch with /guard r / /guard w |
network |
"open" (outbound allowed) or "blocked" (all outbound denied). Switch with /guard non / /guard noff |
sensitiveReadDeny |
Paths blocked from all Agent reads. Supports ~ and globs |
protectedPaths.block |
Paths where write / edit are rejected outright |
protectedPaths.approval |
Paths where write / edit trigger an approval prompt |
bashPolicy.directBlock |
Bash commands rejected immediately |
bashPolicy.requireApproval |
Bash commands requiring approval |
"sensitiveReadDeny": [
"~/.ssh",
"~/.aws",
"~/my-project/secrets.yml"
]"bashPolicy": {
"directBlock": [
"sudo",
"docker-host-root-bind"
],
"requireApproval": [
"rm-rf",
"bash-c"
]
}Entries in
bashPolicyare policy IDs, not raw regex. See the default config generated byinitfor the full list.


