Limitations
Linux only
bwrap uses Linux-specific kernel features (namespaces, bind mounts). It does not work on macOS or Windows.
On non-Linux systems, the extension falls back to unrestricted bash with a warning.
Only protects bash
The extension only intercepts the bash tool. Pi's edit and write tools are separate and not affected — they go through Pi's own file operations, not through bwrap.
If your agent has edit or write tools, those can still modify files. To make an agent truly read-only, don't give it those tools:
tools:
- read
- grep
- find
- ls
- bash # sandboxed by pi-bash-readonly
# no edit, no write
Writable paths are real
If you configure writable paths other than /tmp, those are actual read-write bind mounts of the host filesystem. Changes made inside the sandbox to those paths persist after the command exits.
/tmp is the exception — it gets an isolated tmpfs that's destroyed when the command exits.
Network isolation caveats
By default, the sandbox uses --unshare-net to isolate network access. TCP/UDP connections (curl, wget, etc.) are blocked inside the sandbox.
To allow network access, set "network": true in .pi/pi-bash-readonly.json.
However, --unshare-net only creates a new network namespace — it does not block all host communication:
- Unix domain sockets on the mounted filesystem are still reachable if permissions allow (e.g.
docker.sock-like surfaces). - Other IPC channels (shared memory, signals) are not affected by network namespace isolation.
For most use cases (blocking HTTP requests, preventing data exfiltration over the network), --unshare-net is sufficient.
Config is loaded once
Configuration and writable paths are resolved when the extension loads. Changing .pi/pi-bash-readonly.json mid-session requires restarting Pi.
Nested bwrap
If Pi itself is already running inside a bwrap sandbox (or similar container), nested bwrap may not work depending on the outer sandbox's permissions. bwrap needs the ability to create new mount namespaces.