pi-bash-readonly
v0.3.0
Published
Sandboxed read-only bash for Pi agents via bwrap
Maintainers
Readme
pi-bash-readonly
Sandboxed read-only bash for Pi agents via bwrap.
Install
pi install npm:pi-bash-readonlyWhat it does
Every bash tool call is wrapped in a bwrap sub-sandbox where the entire filesystem is mounted read-only (--ro-bind / /). By default, nothing is writable and network is isolated via --unshare-net.
This uses Linux mount and network namespaces. Unlike regex-based command filtering, writes are blocked at the filesystem level and TCP/UDP network access is blocked via namespace isolation — from any language runtime (Python, Perl, dd, etc.).
Note: Network isolation blocks TCP/UDP but Unix domain sockets on the mounted filesystem may still be reachable. See limitations for details.
User bash commands (! and !! in the TUI) are also sandboxed when read-only mode is active.
Configuration
Agent frontmatter (recommended)
Set sandbox behavior per-agent in the agent's .md file:
---
name: scout
bash-readonly: true
bash-readonly-locked: true
---| Key | Default | Description |
|-----|---------|-------------|
| bash-readonly | — | Initial sandbox state. true = sandboxed, false = unrestricted. |
| bash-readonly-locked | false | When true, disables the /readonly toggle command. |
The extension reads the agent file using the PI_AGENT environment variable. It searches .pi/agents/ and any paths configured in .pi/agents.json agentPaths.
Config file
Configure via .pi/pi-bash-readonly.json (project) or ~/.pi/agent/pi-bash-readonly.json (user). Project config takes priority.
{
"writable": ["/tmp"],
"enabled": true,
"network": false
}| Key | Default | Description |
|-----|---------|-------------|
| writable | [] | Paths to mount writable inside the sandbox. /tmp gets an isolated tmpfs (not the host /tmp). Other paths are bind-mounted read-write. |
| enabled | true | Initial sandbox state. Overridden by agent frontmatter. |
| network | false | Allow network access inside the sandbox. Default is false (network isolated via --unshare-net). Set to true if agents need to fetch packages, clone repos, or make HTTP requests. |
Without "/tmp" in writable, commands like sort on large inputs will fail since they need temp space. Add it if your agents run commands that need scratch space.
Resolution order
- Agent frontmatter
bash-readonlyfield (ifPI_AGENTis set and agent file found) - Config file
enabledfield - Default:
true(sandboxed)
Usage
Add to an agent's extensions:
extensions:
- pi-bash-readonlyUse the /readonly command in an interactive session to toggle:
/readonly # 🔒 bash: read-only (bwrap)
/readonly # 🔓 bash: full accessIf bash-readonly-locked: true is set in the agent's frontmatter, the toggle shows a "locked" notification and does nothing.
Visual indicator
When the sandbox is active, bash tool calls display a 🔒 icon in the tool header:
🔒 bash ls -laThe status bar also shows 🔒 ro when sandboxed.
How it works
- Registers a custom
bashtool usingcreateBashToolwith aspawnHook - The
spawnHookwraps commands in bwrap viabash -cwith shell escaping (no temp files) - Intercepts
user_bashevents to sandbox!and!!commands too - Reads agent frontmatter via
PI_AGENTenv var for per-agent configuration
Requirements
- Linux with bwrap in
PATH- Debian/Ubuntu:
sudo apt install bubblewrap - Fedora:
sudo dnf install bubblewrap - Arch:
sudo pacman -S bubblewrap
- Debian/Ubuntu:
- Falls back gracefully to unrestricted bash with a warning if bwrap is not found
License
MIT
