pi-os-guard
OS-sandboxed read-only / restricted execution for pi (bubblewrap on Linux, sandbox-exec on macOS).
Package details
Install pi-os-guard from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:pi-os-guard- Package
pi-os-guard- Version
0.1.2- Published
- Aug 3, 2026
- Downloads
- 469/mo · 20/wk
- Author
- oxel40
- License
- MIT
- Types
- extension
- Size
- 46.4 KB
- Dependencies
- 0 dependencies · 3 peers
Pi manifest JSON
{
"extensions": [
"./index.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
pi-guard
Distributed as the npm/git package
pi-os-guard(the namepi-guardwas already taken on npm). The extension, its/guardcommand, and its config keys all keep thepi-guardname internally.
OS-sandboxed read-only / write-restricted execution for pi. Routes the
write-capable built-in tools (write, edit, bash) and ! commands through a
per-command OS sandbox — bubblewrap (bwrap) on Linux, sandbox-exec on
macOS — so the operating system, not a heuristic, enforces the write boundary
on the real host filesystem. No container, no image: the sandboxed shell
shares your installed binaries and environment.
Toggle the mode live during a session with /guard.
Why the OS, not a heuristic
An in-process guard can only block or rewrite a tool call; it can't change what a command is allowed to do, so "read-only for bash" degenerates into guessing whether a command writes. That guess is unsound. Here, commands run under a read-only view of the filesystem, so writes fail at the syscall for any command — including ones no heuristic would catch.
This is a real write boundary, but not a hardened sandbox: it does not confine reads (your whole filesystem is readable), and (by default) the process keeps network access. Use it to make a session safely "look but don't touch" and confine writes — not to run actively malicious code. For stronger isolation add a VM/micro-VM.
Modes
| Mode | Filesystem | Writes |
|---|---|---|
off |
host tools (pi default) | normal |
readonly |
whole FS readable | everything fails at the syscall |
restricted |
whole FS readable | only cwd + allow dirs (and scratch) succeed; rest fails |
Identity paths. The sandbox shares the host filesystem at the same paths —
/Users/you/project is the same path inside and out — so absolute paths, $PWD,
and tool output line up with the host. There is no /workspace remapping.
Home is readable, not writable. Your $HOME is readable in every mode, so
skills (~/.agents/skills), git (~/.gitconfig), and gh
(~/.config/gh) work against your real config. The trade-off: guard confines
writes, not reads — the model can read anything you can (including
~/.ssh), so this is not a secrets boundary. The sandbox inherits your shell
env (tokens included), matching that posture.
Reads run on the host. read, ls, find, and grep are pi's normal
host tools — a read can't breach a write boundary, so there's nothing to
sandbox, and they stay fast.
Session scratch. Each session gets one writable scratch dir, pinned as
TMPDIR in every command, so temp files created by one command are visible to
the next. It's removed when the session ends (not persisted across reboots).
In readonly mode the scratch (and TMPDIR) is the only writable path.
Fail-closed: in readonly/restricted with no backend available, tools
error out. The extension never silently falls back to host execution.
Backends
- Linux — bubblewrap (
bwrap). Read-only bind of/plus read-write binds for the writable dirs (cwd + allow-list + scratch). Fresh/tmp,/proc(--unshare-pid), and/dev; network left on. Install withapt install bubblewrap/dnf install bubblewrapif missing. - macOS —
sandbox-exec(Seatbelt). An(allow default)/(deny file-write*)profile that re-allows writes only under the writable dirs (canonicalized withrealpath) plus the usual devices. Always present at/usr/bin/sandbox-exec. (Apple markssandbox-execdeprecated, but it still works and needs no entitlements/signing.)
What's not provided vs a container: no PID-namespace cutoff on macOS and no network isolation — this is a write boundary by design.
Install
pi install npm:pi-os-guard
# or
pi install git:github.com/Oxel40/pi-os-guard
No npm install needed — it uses only pi's bundled APIs and Node built-ins.
Requires bubblewrap on Linux; macOS works out of the box. Windows is not
supported (yet).
Commands
/guard # status (backend, mode, workspace, allow, scratch)
/guard readonly # switch to read-only (rebuilds sandbox)
/guard restricted # switch to restricted (rebuilds sandbox)
/guard off # use host tools
/guard allow <dir> # add an extra read-write dir (restricted) and rebuild
/guard backend <name> # bwrap | sandbox-exec | auto
/guard rebuild # force-rebuild the sandbox
Default startup mode is readonly. Override at launch with pi --guard off,
pi --guard readonly, or pi --guard restricted.
Configuration
Merged from global then project, with env-var overrides on top:
~/.pi/agent/extensions/pi-guard.json(global)<cwd>/.pi/pi-guard.json(project-local, requires project trust)
{
"backend": "auto",
"mode": "readonly",
"allow": []
}
backend:auto|bwrap|sandbox-exec(envPI_GUARD_BACKEND)mode: default startup mode (readonlyby default; envPI_GUARD_MODE)allow: extra read-write dirs forrestrictedmode
Concurrent Subagents (spawn_agents)
pi-guard provides a spawn_agents tool that spawns multiple pi subagents
concurrently, each inheriting the same guard mode. In TUI mode, it shows a
non-blocking status widget above the input box — the session remains
usable while it runs, and the widget never takes keyboard focus.
Features
Live status updates: Each agent shows its current state with colored icons:
○pending (dim)◔starting (muted)- spinner (braille frames) running (accent)
✓completed (success)✗failed (error)
Event tracking: See what each agent is doing in real-time:
Calling: bashwhile a tool call is in flight,✓ bash/✗ bash (error)once it finishesThinking.../Generating response...during LLM calls
Progress summary: Bottom bar shows
Completed: X | Running: Y | Failed: ZAbort support: Ctrl+C cancels the tool call via pi's standard tool-cancellation mechanism (stops all in-flight subagents)
Graceful degradation: Falls back to simple mode when not in TUI (print, JSON, or RPC mode)
Visual Example
When spawning 3 concurrent agents:
Spawning 3 subagents
✓ [1/3] COMPLETED Analyze the error logs in /var/log/app.log...
⠹ [2/3] RUNNING Fix the failing unit test in test_auth.py...
└─ Calling: bash
○ [3/3] PENDING Update the README with new installation steps...
Completed: 1 | Running: 1 | Failed: 0
Working... (Ctrl+C to cancel)
Usage
The agent automatically uses spawn_agents when appropriate, or you can request it:
# In a pi session
Please use spawn_agents to run these 3 tasks concurrently:
1. Check system logs for errors
2. Run the test suite
3. Update the documentation
Each subagent runs in its own pi process with the same guard mode (readonly/restricted), so they can work in parallel while respecting the write boundary.
Lifecycle
Each session builds the sandbox lazily on first use and creates one scratch dir. There is no long-lived process to reap: the scratch dir is removed on session shutdown (quit/new/resume/fork/reload). A dir leaked by a hard crash is small and reaped by the OS temp cleaner.