The sandbox is an enforcement floor independent of autonomy and permission rules: autonomy decides whether a command may run without asking; the sandbox decides what that spawned command can physically do if it runs. It confines writes to approved roots and (by default) denies network egress. Reads stay broad so toolchains can inspect SDKs and system files — protecting secret reads is redaction’s job.
The sandbox confines only the child command, never the bonsai process itself
(which must keep writing ~/.bonsai). It is independent of yolo: enabling
yolo does not turn the sandbox off; leaving confinement is always an explicit
/sandbox off.
| Platform | Backend | Mechanics |
|---|---|---|
| macOS | Seatbelt | /usr/bin/sandbox-exec -p <profile> with a generated SBPL profile: allow default, deny file-write* except the writable roots (+ /dev/null, /dev/tty, pty devices), optionally deny network*. sandbox-exec execs into the shell, so process-group signals reach the real child. |
| Linux | Bubblewrap | /usr/bin/bwrap --unshare-all --die-with-parent --ro-bind / /, re-binding each writable root read-write; network allowed only by adding --share-net. A startup probe actually spawns a bwrap sandbox to confirm namespace creation works; a second probe checks whether network isolation is supported (containers often block it, degrading to “network deny unenforced” with a visible warning). |
| Other | none | /sandbox on reports that no backend is available. Autonomy and permission rules still apply, but no OS confinement is claimed. |
Resolved once at startup, canonicalized and de-duplicated:
bonsai-session-*
tempdir), exported to children as $TMPDIR, $TMP, and $TEMP — so
concurrent sessions never share scratch space. npm, XDG, pip, and Go build
caches are redirected below it (npm_config_cache, XDG_CACHE_HOME,
PIP_CACHE_DIR, GOCACHE).CARGO_HOME (default ~/.cargo) and an explicitly configured
GOMODCACHE. This is the deliberate compatibility exception to
per-session cache isolation — cargo and go mix immutable dependencies
with resolver locks in one directory. rustup stays read-only, so
toolchain installation requires an approved sandbox escape.BONSAI_SANDBOX_WRITABLE_ROOTS (colon-separated) and
writable_roots in the [sandbox] config section
(unioned).Denied by default. Seatbelt appends (deny network*); Bubblewrap simply
omits --share-net from the unshared namespace. /sandbox net on denies,
/sandbox net off allows. When the Linux backend cannot isolate networking,
the status and command output say the denial is unenforced rather than
silently claiming confinement.
A confined command that legitimately needs to step outside (e.g.
rustup update) can request escape_sandbox: true on the bash tool. This
is a single audited step-past:
The shared enabled-flag is untouched by an escape — every other command stays confined.
/sandbox or /sandbox status — status modal (backend, posture, writable
roots)./sandbox on / /sandbox off — toggle confinement./sandbox net on — deny network; /sandbox net off — allow it./settings persist confinement and network
preferences (interactive sessions restore them at startup; headless reads
posture from config/env only).Environment defaults:
| Variable | Values | Default |
|---|---|---|
BONSAI_SANDBOX |
1/on/true/yes/enabled vs 0/off/false/no/disabled |
on when a backend is available |
BONSAI_SANDBOX_NETWORK |
deny/denied/block/off vs allow/allowed/on |
denied |
BONSAI_SANDBOX_WRITABLE_ROOTS |
colon-separated paths | empty |
Env wins over the [sandbox] config section, per the normal
precedence.
auto-accept autonomy level
honors its high-risk ceiling only while the sandbox is active; otherwise
it behaves as balanced. See
Autonomy and permissions.bonsai doctor proves enforcement: its sandbox check performs a
control write inside a writable root (must succeed) and a write outside
every root (must be blocked), plus a network-denial probe — it verifies the
backend actually enforces, not just that it exists.| Concern | Location |
|---|---|
| Shared sandbox handle & env defaults | src/sandbox/mod.rs |
| Seatbelt profile | src/sandbox/macos.rs |
| Bubblewrap wrapper & probes | src/sandbox/linux.rs |
| Writable-root policy & escapes | src/sandbox/policy.rs |
| Doctor enforcement probe | src/doctor.rs |