@khimaros/pi-sandbox0.1.0
pi extension that runs built-in tools inside a local micro-VM with deny-by-default network egress
Untested on omp
This is a pi package. No one has reported whether it works on omp yet. If you try it, add your result below.
Reports 0
No reports yet.
Readme
pi-sandbox
a pi extension that runs pi's built-in tools inside a local micro-VM instead of on the host, with a deny-by-default outbound network policy.
the host working directory is mounted at /workspace in the guest. writes under
/workspace pass through to the host; every other guest filesystem change stays
inside the VM and is discarded when the session ends.
requirements
host software:
- linux or macOS
- node >= 23.6.0 (required by
@earendil-works/gondolin) - QEMU (
brew install qemuon macOS,apt install qemu-system-x86on debian)
hardware and resources for the micro-VM:
- x86_64 or arm64. the guest is built for the host architecture; a mismatch forces software emulation
- CPU virtualization, strongly recommended. on linux this means read and write
access to
/dev/kvm, normally by joining thekvmgroup:sudo usermod -aG kvm $USER(log out and back in). macOS uses the hypervisor framework and needs no setup - without it the VM still boots, under QEMU's
tcgsoftware emulation, which is slow enough to be painful for real work - ~1GB RAM per VM (the guest default) plus host overhead, and 2 vCPUs
- ~300MB disk for the cached guest image, plus a copy-on-write overlay per running VM
the guest image is fetched on first run and cached in
~/.cache/gondolin/images/.
install
install from npm:
pi install npm:@khimaros/pi-sandbox
pi install also accepts a git source, and -l writes to project settings
rather than user settings:
pi install git:github.com/khimaros/pi-sandbox
installing from npm or git runs npm install for you.
to work from a checkout instead, note that the extension has a runtime
dependency on @earendil-works/gondolin, so the package needs its
node_modules before pi can load it:
git clone https://github.com/khimaros/pi-sandbox
cd pi-sandbox
npm install --ignore-scripts
pi install /path/to/pi-sandbox
--ignore-scripts skips native build steps that the QEMU backend does not need.
a local path is added to settings without copying and without installing, which
is why npm install has to be run by hand.
for a one-off test without registering anything:
cd /path/to/project
pi -e /path/to/pi-sandbox
pi -e also does no dependency installation.
what gets routed
these tools execute in the guest rather than on the host:
read write edit bash ls find grep
user bash (the ! prefix) also runs in the guest, and the system prompt is
rewritten so the model is told its working directory is /workspace.
network egress
outbound HTTP and HTTPS are intercepted host-side and checked against an allowlist. the allowlist starts empty, which denies everything -- no package installs, no API calls, no git over HTTPS -- until you permit a host.
/sandbox allow api.github.com
/sandbox allow *.npmjs.org
patterns support * as a wildcard, so *.npmjs.org matches any subdomain.
changes apply to the next request; the VM is not restarted.
two things hold regardless of the allowlist:
- private and loopback IP ranges are always blocked, even if the hostname that resolves to them is allowed
- SSH and raw TCP have no default path out of the guest; neither is configured by this extension
secrets are supported by the underlying library but are not wired up here yet.
commands
| command | effect |
|---|---|
/sandbox |
open a picker with the subcommands below |
/sandbox status |
VM id, workspaces, shell, allowlist, config path |
/sandbox enable |
run tools in the VM (starting it if needed) |
/sandbox disable |
run tools directly on the host, stop the VM |
/sandbox allow <pattern> |
add a host pattern to the allowlist |
/sandbox deny <pattern> |
remove a host pattern |
/sandbox hosts |
list the current patterns |
allow and deny prompt for a pattern when called with no argument. current
state is shown in the footer as sandbox: <id> (/workspace, N host(s)), or
sandbox: disabled (host).
disabling
/sandbox disable is a full bypass: tools run on the host with no VM and no
egress filtering. the setting persists, so a repo left disabled stays disabled
on the next session.
configuration
state is stored per repository in ~/.pi/agent/sandbox.json, keyed by absolute
repo path, in the same shape as the agent dir's own trust.json:
{
"/home/you/src/my-project": {
"enabled": true,
"allowedHosts": ["dl-cdn.alpinelinux.org"]
}
}
the repo key is the nearest ancestor directory containing .git, falling back
to the working directory. PI_CODING_AGENT_DIR is honoured, so the file follows
a relocated agent dir.
this file lives outside the repository on purpose. an allowlist committed into a project would travel with a clone and silently widen the sandbox of whoever opened it, and pi does not prompt for trust on arbitrary extension config. a malformed or unreadable file falls back to deny-all rather than to anything more permissive.
to change the built-in default for new repositories, edit ALLOWED_HOSTS in
src/extension/index.ts.
guest image
alpine linux 3.23, preinstalled with bash, curl, nodejs, npm, python3,
uv, openssh, and ca-certificates.
apk add works, with two caveats:
- it needs
/sandbox allow dl-cdn.alpinelinux.org, since that is where the configured repositories live - the root filesystem is a copy-on-write overlay that is deleted when the VM stops, so installed packages do not survive the session
put anything that must persist under /workspace.
releasing
pushing a v* tag runs .github/workflows/release.yml, which publishes
@khimaros/pi-sandbox to npm. the job fails if the tag does not match version
in package.json.
npm version patch # bumps package.json and package-lock.json, commits, tags
git push --follow-tags
the workflow authenticates with npm trusted publishing (OIDC) and stores no
token. this needs a one time setup on npmjs.com: publish the first version by
hand with npm login && make publish, then under the package's settings add a
trusted publisher for repository khimaros/pi-sandbox and workflow
release.yml.