pi-sandbox

OS-level sandboxing for pi with interactive permission prompts

Package details

extension

Install pi-sandbox from npm and Pi will load the resources declared by the package manifest.

$ pi install npm:pi-sandbox
Package
pi-sandbox
Version
0.4.1
Published
May 3, 2026
Downloads
1,090/mo · 544/wk
Author
chrisarderne
License
MIT
Types
extension
Size
1.7 MB
Dependencies
1 dependency · 1 peer
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-sandbox

Sandbox for pi.

Sandboxes pi like this:

  • read/write/edit: direct control using allow/deny lists
  • bash: uses @carderne/sandbox-runtime to control network and file system access

When a blocked action is attempted, the user is prompted to allow it temporarily or permanently rather than silently failing.

demo

Notes

There is an example config at sandbox.json. It was quite a few things added to get this extension to work with agent-browser and other common tools.

These open significant security loopholes, so shouldn't be used in a sensitive context or when you don't need browser support.

You may need to trial and error to find additional things you need to allow.

Quickstart

Prerequisites

pi-sandbox delegates the OS-level bash sandbox to @carderne/sandbox-runtime, published from the fork at https://github.com/carderne/sandbox-runtime, which is forked from Anthropic's anthropic-experimental/sandbox-runtime. The sandbox runtime checks for ripgrep (the rg binary) on both macOS and Linux at sandbox-init time. If rg is not on the PATH that pi was launched with, sandbox initialization fails with:

Sandbox initialization failed: Sandbox dependencies not available: ripgrep (rg) not found

Install ripgrep before enabling the extension:

Platform Install
macOS (Homebrew) brew install ripgrep
macOS (MacPorts) sudo port install ripgrep
Linux (Debian/Ubuntu) sudo apt install ripgrep
Linux (Fedora/RHEL) sudo dnf install ripgrep
Linux (Arch) sudo pacman -S ripgrep
From source / other https://github.com/BurntSushi/ripgrep#installation

If which rg succeeds in your shell but pi still reports rg not found, pi is being launched from a parent process whose PATH does not include the directory containing rg (common when GUI launchers inherit a minimal non-login PATH). On macOS, /opt/homebrew/bin and /usr/local/bin are the usual culprits — make sure your launcher's environment includes whichever one your install uses.

Install

pi install npm:pi-sandbox

Configure

Add a config like this either to ~/.pi/agent/sandbox.json (global) or to .pi/sandbox.json (local). Local config takes precedence over global.

Note below that the order of precedence for filesystem read and write are opposite.

{
  "enabled": true,
  "allowBrowserProcess": true,     // If you want to use agent-browser or similar Chrome setup
  "network": {
    "allowLocalBinding": true,     // ditto
    "allowAllUnixSockets": true,   // ditto
    "allowedDomains": ["github.com", "*.github.com"],
    "deniedDomains": []
  },
  "filesystem": {
    // For READS:
    // - ANY read is prompted unless the path is already in allowRead
    // - Granting a prompt adds to allowRead, which overrides denyRead
    // - denyRead is not a hard-block; it just marks regions as denied by default
    "denyRead": ["/Users", "/home"],
    "allowRead": [".", "~/.config", "~/.local", "Library"],

    // For WRITES:
    // - empty ALLOW means no write access at all
    // - DENY takes precedence and is never prompted
    "allowWrite": [".", "/tmp"],
    "denyWrite": [".env", ".env.*", "*.pem", "*.key"]
  }
}

Usage

pi --no-sandbox          disable sandboxing for the session
/sandbox                 show current configuration and session allowances

What it does

Bash commands are wrapped with sandbox-exec (macOS) or bubblewrap (Linux) to enforce network and filesystem restrictions at the OS level.

Read, write, and edit tool calls are intercepted before execution and checked against the same filesystem policy. The OS-level sandbox cannot cover these tools because they run directly in the Node.js process rather than in a subprocess.

When a block is triggered, a prompt appears with four options:

  • Abort (keep blocked)
  • Allow for this session only
  • Allow for this project — written to .pi/sandbox.json
  • Allow for all projects — written to ~/.pi/agent/sandbox.json

Session allowances are held in memory only. They are never written to disk and the agent has no way to read or modify them. They are reset when the extension reloads or pi restarts.

What is prompted vs. hard-blocked

Rule Behaviour
Domain not in allowedDomains Prompted (bash and !cmd)
Path not in allowRead Prompted (read tool); granting adds to allowRead
Path not in allowWrite Prompted (write/edit tools and bash write failures)
Path in denyWrite Hard-blocked, no prompt
Domain in deniedDomains Hard-blocked at OS level, no prompt

If a path is added to allowWrite via a prompt but is also present in denyWrite, it remains blocked. A warning is shown explaining which config files to check.

allowedDomains supports *.example.com wildcards. It also supports "*" to allow all domains; pi-sandbox shows a warning when this is configured because it removes per-domain prompts and can be easy to add accidentally. allowWrite uses prefix matching, so . covers the entire current working directory.

⚠️ Read and write have different precedence rules:

  • Read: Every read is prompted unless the path is already in allowRead. denyRead is not a hard-block — it marks regions as denied by default, but granting a prompt adds the path to allowRead, overriding denyRead.
  • Write: denyWrite takes precedence over allowWrite and is never prompted. A path in denyWrite is always blocked, even if it matches allowWrite.

If neither file exists, built-in defaults apply (see above for the defaults).

The footer shows a lock indicator while the sandbox is active.

Ackowledgements

Based on code from badlogic/pi-mono by Mario Zechner, used under the MIT License.