bash tool, including background tasks and sub-agents. It works alongside permissions: permissions decide whether a command runs at all, and the sandbox limits what an approved command can do. A command approved in auto or bypass mode is still confined by the sandbox.
Sandbox tiers
In an interactive session the sandbox has three tiers. The default isguarded.
open: no sandbox. Commands run with your full user permissions.guarded: commands can write to the workspace,/tmp, the system temp directory, and common tool caches in your home folder (~/.cache,~/.cargo,~/.npm,~/.o4/cache, and your platform cache folder). Paths that installed plugins in~/.o4/pluginsdeclare in their manifest’spermissions.pathsare writable too, unless they overlap a protected location. Network access goes through an egress proxy that allows these hosts by default:registry.npmjs.org,registry.yarnpkg.com,crates.io,static.crates.io,pypi.org,files.pythonhosted.org,proxy.golang.org,github.com,gitlab.comandbitbucket.org. Requests to other hosts ask you first (see Network access).airlock: commands can write only inside the workspace and have no network access. Your[sandbox]config doesn’t widen it.
open, commands can still read most of the filesystem, so they can load programs and libraries. The sandbox blocks reads and writes to credential locations in your home folder: ~/.ssh, ~/.aws, ~/.gnupg, ~/.gpg, ~/.kube, ~/.docker, ~/.azure, ~/.gcloud, ~/.config/gcloud, ~/.config/gh, ~/.env, ~/.netrc, ~/.npmrc, ~/.pypirc and ~/.git-credentials, and o4’s own ~/.o4/settings.json, ~/.o4/.mcp.json, ~/.o4/trusted_workspaces.json, ~/.o4/managed and ~/.o4/plugins/.plugin-sources.json.
Package installs (such as npm install, pip install or cargo add) get a narrower profile instead. They can write only to the workspace’s dependency folders and lock files (node_modules, target, .venv, venv, package-lock.json, pnpm-lock.yaml, yarn.lock, bun.lock, bun.lockb, Cargo.lock and uv.lock), plus the tool caches in guarded, and in guarded they can reach only the package registries, not github.com, gitlab.com or bitbucket.org. In guarded this applies only when no config file has a [sandbox] table; in airlock it always applies.
Change the tier
PressAlt+S to cycle the tier: open, guarded, airlock, then back to open. The change applies to new commands right away, and a toast shows it, for example Sandbox: airlock (new commands). Moving from airlock to open removes the sandbox, so o4 asks you to confirm it first (“Switch sandbox to open?”). Press Y or Enter to switch, or N or Esc to keep airlock. You can rebind Alt+S with the cycle_sandbox_tier action in [keybindings].
o4 saves the tier you pick as default_tier in the workspace’s .o4/config.toml, so the next session in that workspace starts with it, as long as the workspace is trusted. In an untrusted workspace o4 doesn’t read that file, so the next session starts in the tier from ~/.o4/config.toml, or guarded. You can also set it yourself:
default_tier accepts open, guarded or airlock. Put it in ~/.o4/config.toml to change the default for every workspace. Project config files are read only in a trusted workspace.
You can also change the tier in /config general: selecting the Sandbox tier row and pressing Enter cycles it the same way Alt+S does, with the same confirmation and the same saved default_tier. The row’s value always reads guarded, whatever the current tier; the toast and the Sandbox policy details show the real one.
The Sandbox policy row below it is read-only. Press Enter on it to open a details view with the policy mode (the current tier), the paths commands can write to (or unrestricted in open), and a note on how your platform enforces the sandbox. Press Backspace to go back to the list. It describes the tier you pick with Alt+S, not a fixed --sandbox mode.
When you start o4 in an untrusted directory whose .git folder was created in the last 24 hours, such as a fresh clone, o4 shows the suggestion “Fresh clone: use airlock sandbox?”. Accepting it switches this session to airlock without saving it as default_tier. The suggestion appears once per workspace.
Fixed sandbox with --sandbox
In print mode without --sandbox, commands always run in guarded: o4 doesn’t apply default_tier there. It also starts no egress proxy, so commands have no network unless a [sandbox] table without allowedDomains lifts the limit (see the warning under Network access).
The same is true for commands you run yourself with ! in the prompt and for the checks o4 watch runs: they use the current tier but no egress proxy, so in guarded and airlock they have no network at all, not even to the registries on the allowlist.
Use --sandbox to fix the sandbox for a whole run, for example in scripts or print mode:
With
read-only or workspace-write, o4’s file tools also refuse paths outside the workspace and the --add-dir directories. default_tier and escape_hatch_binaries are ignored, and Alt+S has no effect on the fixed sandbox.
Extra writable directories
--add-dir makes another directory writable alongside the workspace. Shell commands can write there only with --sandbox workspace-write; without --sandbox, it affects o4’s file tools only. Repeat it for more than one:
-C (--cd) sets the working root instead of the directory you start in. o4 refuses a -C or --add-dir directory that is inside one of the protected credential locations listed above, or that contains one. So --add-dir ~ is refused, because your home folder contains ~/.ssh.
Passing -C or --add-dir also limits o4’s file tools to the working root and the added directories, even without --sandbox.
Network access
Inguarded, o4 starts a local egress proxy for each session and routes sandboxed commands through it with the HTTP_PROXY, HTTPS_PROXY and ALL_PROXY variables. Requests to allowed hosts go through. When a command connects through the proxy to any other host, o4 shows a prompt with three choices:
You can also move with the arrow keys (or
j and k) and press Enter.
If you don’t answer within 5 minutes, the request is denied. In print mode and other runs without a TUI, requests to unlisted hosts are denied without a prompt.
The same host rules apply to o4’s own fetch and web_search tools while the sandbox is guarded or airlock. In airlock they fail with a message telling you to press Alt+S.
To allow more hosts without being asked, list them in allowedDomains:
example.com also covers api.example.com. *.example.com matches subdomains only, and * matches every host.
Only programs that honor the proxy variables can reach the network. On macOS, the sandbox allows network connections only to the proxy, so a program that ignores the variables gets no network at all.
On Linux, a sandbox that limits the network cuts it off completely, and the proxy can’t be reached from inside. So on Linux, commands in
guarded and airlock have no network. o4’s own fetch and web_search tools still follow the host rules. Use open, or --sandbox danger-full-access, for commands that need the network.[sandbox.proxy] enabled = false, o4 shows a warning at startup and commands in guarded get no network. o4 starts the proxy only when a session begins in guarded or airlock, so after you switch from open to guarded with Alt+S, commands have no network until the next session.
How it’s enforced
- macOS: o4 runs each command under
sandbox-execwith a profile that denies writes outside the allowed paths and denies network except to the egress proxy. - Linux: o4 runs each command under bubblewrap (
bwrap), which it looks for only at/usr/bin/bwrapand/bin/bwrap. The root filesystem is mounted read-only, allowed paths are mounted writable, and/tmpand/runare private and empty. If bubblewrap isn’t installed, o4 refuses to run commands inguardedorairlockand tells you to install it or switch to theopentier. - Other platforms: o4 has no sandbox backend and refuses to run commands in a sandboxed tier.
O4_SANDBOXED=1 on Linux.
Checks before a command runs
In a sandboxed tier, o4 also looks at the command text before running it:- If the command contains an absolute path outside the writable paths, o4 refuses it, even if the command only reads that path. For example, in
guarded,cat /etc/hostsfails with “Path ‘/etc/hosts’ is outside the sandbox allowed paths”. Paths under/dev/are allowed. Use a relative path, or a tool such asread, instead. - If the command contains an
http://orhttps://URL whose host isn’t allowed, o4 refuses it. Without a[sandbox]table, the allowed hosts are the tier’s defaults (none inairlock). With one, inguarded, only the hosts inallowedDomainscount for this check, and if you leaveallowedDomainsout, URLs aren’t checked. So when you setallowedDomains, also list any default host, such asgithub.com, that commands name directly. - If the
bashcall sets a working directory outside the writable paths, o4 refuses it.
Before 0.2.54, any
[sandbox] config, even just default_tier, kept commands sandboxed when the tier was open. In 0.2.54 and later, open is really unsandboxed.Configure the sandbox
The[sandbox] table can go in any o4 config file. List settings add up across files; default_tier and proxy come from the highest-precedence file that sets them.
o4 drops any
allowedPaths entry that overlaps a protected credential location, even if you list it explicitly, and shows a warning at startup.
See the configuration reference for types and defaults.