Omnibox: OS Sandbox
Omnibox is Omnigent's secure OS sandbox for any agent. It restricts filesystem and network access at the OS level, and it hides credentials from the agent and brokers access to them. Run agents with minimal permissions, or lock them down for unattended YOLO-mode execution.
The OS sandbox restricts what commands and file operations your agent can perform. It controls which files the agent can read and write, whether it can access the network, and which environment variables it sees.
This is different from the cloud sandbox host, which controls where the runner executes. The OS sandbox controls what the agent can access, regardless of where it runs.
The OS sandbox applies to the built-in OS tools (sys_os_read, sys_os_write,
sys_os_edit, sys_os_shell) and any terminals you declare in the agent config.
Requirements: Linux: install bubblewrap (apt install bubblewrap or
dnf install bubblewrap). macOS: sandbox-exec ships with stock macOS. If you ask for a
sandbox and the backend isn't available, Omnigent errors rather than running unsandboxed.
Minimal config
The smallest useful OS sandbox. Make the working directory writable and let Omnigent pick the backend for your platform:
os_env:
type: caller_process
cwd: .
sandbox:
write_paths: [.] # cwd is read-only by default; opt it back in
allow_network: true
On Linux, Omnigent uses bubblewrap (bwrap). On macOS, it uses Seatbelt
(sandbox-exec). Omit type to auto-detect.
| Platform | Backend | Mechanism |
|---|---|---|
| Linux | linux_bwrap | Bubblewrap namespaces + seccomp |
| macOS | darwin_seatbelt | sandbox-exec SBPL profiles |
| Other | none | No sandboxing (explicit opt-out) |
What you can restrict
Filesystem
By default, cwd is read-only on hardened backends. You opt in to writes explicitly.
sandbox:
read_paths: [~/.gitconfig, ~/.ssh] # read-only access outside cwd
write_paths: [.] # writable directories
write_files: [~/.ssh/known_hosts] # individual writable files
cwd_allow_hidden: [.venv, .git, .env] # dotfiles to allow (rest are masked)
mask_paths: [config/production.key] # hide specific paths by name/depth
Dotfiles under cwd and read_paths are hidden by default unless
listed in cwd_allow_hidden. This makes broad read grants safe: granting
~ doesn't expose ~/.aws/credentials or ~/.ssh/id_rsa. On macOS, ~/Library is also
denied by default.
By default the dotfile mask is non-recursive — it scans only the top level of
cwd and each read_paths root. Top-level secrets (.env, .git/, .aws/,
.ssh/) are still hidden, but a dotfile nested below the first level (for example
services/api/.env) stays visible. This is the scalable default: a recursive walk of
a medium or large tree visits enormous numbers of entries and routinely trips
cwd_hidden_scan_max_entries.
For untrusted source trees where a deeply nested credential file would be an
unacceptable leak, set cwd_hidden_scan_recursive: true to walk the whole tree. The
cwd_hidden_scan_max_entries and cwd_hidden_scan_overflow knobs then bound the cost
of the full walk.
sandbox:
cwd_hidden_scan_recursive: true # mask dotfiles at any depth
To hide a specific file or directory the name-based masker won't catch — a named
secret like config/production.key, or a single deeply nested dotfile without turning
on full recursion — list it under mask_paths. Entries are resolved like read_paths
(~ is expanded, relative paths are taken against cwd, $VAR is not expanded) and
are hidden regardless of name or depth, on top of the dotfile mask. A directory is
masked as an empty view, a file as an empty file.
sandbox:
mask_paths:
- config/production.key
- ~/.config/private
Network
sandbox:
allow_network: true # basic on/off
egress_rules: # optional HTTP(S) allow-list
- "GET api.github.com/repos/myorg/**" # GET only, one org
- "* pypi.org/**" # any method
- "* *.github.com/**" # wildcard subdomain
When egress_rules is set, all HTTP(S) traffic goes through a MITM proxy with
default-deny. Only requests matching a rule are allowed. Requires a hardened backend
(linux_bwrap or darwin_seatbelt).
Each rule is "METHODS host/path-glob": comma-separated HTTP verbs (or
* for any), a hostname (or *.domain for subdomains), and a path
glob where ** matches any depth.
By default, the proxy also blocks connections to private IPs (RFC1918, loopback, cloud
metadata like 169.254.169.254). Set
egress_allow_private_destinations: true if your agent needs to reach internal services.
Environment
sandbox:
env_passthrough: [GH_TOKEN, AWS_PROFILE] # only these vars reach the agent
Agent CLIs are spawned with a deny-by-default environment. Only two things are
inherited automatically: the shared base (HOME, PATH, proxy/TLS settings, locale,
TMPDIR, and the Omnigent session marker) and the running harness's own variable
family. Everything else — including a host secret that belongs to some other
provider — is stripped, and only reaches the agent if you name it in
env_passthrough.
An ambient key that used to reach the CLI implicitly now has to be declared. Two cases are worth knowing:
- A generic ACP agent (
type: acp) gets no vendor family at all, because Omnigent cannot know which vendor an arbitrary agent belongs to. Gemini via ACP needsenv_passthrough: ["GEMINI_API_KEY"]. - Goose owns
GOOSE_*only. Goose configured through Omnigent's provider/gateway routing is unaffected, but a goose set up against an ambient provider key (OPENAI_API_KEY,ANTHROPIC_API_KEY, …) needs that name declared here.
If an agent fails during its initialize handshake for no obvious reason, check this
field first — the ACP executor logs a hint pointing back at it.
Credentials (secretless proxy)
credential_proxy lets sandboxed tools authenticate to external hosts without the
real secret ever entering the sandbox: the mandatory L7 egress proxy attaches the
credential on the way out, swapping a synthetic placeholder for the real value. It
requires egress_rules and a hardened, network-isolating backend (linux_bwrap or
darwin_seatbelt).
Each entry has a type. The host-keyed types — https_bearer, https_basic,
git_https, and gh_basic — bind a credential to a target/targets host and
resolve the secret from a source.
sandbox:
egress_rules:
- "* api.github.com/**"
credential_proxy:
- type: https_bearer
target: api.github.com
source: { env: GH_TOKEN }
Databricks CLI
The databricks_cli type proxies the Databricks CLI.
Unlike the host-keyed types, it is profile-keyed: list the profiles to proxy
(and an optional default). Only the listed profiles are materialized into the
sandbox — as a placeholder .databrickscfg whose tokens are synthetic oa_cred_*
values — and swapped by the proxy; every other profile is invisible to the agent.
Omnigent points DATABRICKS_CONFIG_FILE at the placeholder file, and sets
DATABRICKS_CONFIG_PROFILE when default is given.
os_env:
type: caller_process
cwd: .
sandbox:
type: linux_bwrap
egress_rules:
- "* pypi.org/**" # your other egress needs
- "* dbc-adb7b1a3-9097.cloud.databricks.com/**" # the proxied workspace
credential_proxy:
- type: databricks_cli
profiles: [dbc-adb7b1a3-9097, oss]
default: dbc-adb7b1a3-9097 # optional; sets DATABRICKS_CONFIG_PROFILE
Inside the sandbox, databricks --profile dbc-adb7b1a3-9097 current-user me works;
the sandbox holds only oa_cred_* placeholders, never a live token.
As with every credential-proxy type, you must list each workspace host in
egress_rules yourself — the proxy never widens egress on its own. OAuth profiles
(auth_type = databricks-cli) are refreshed for the life of the session, so long
sessions survive the ~1h token expiry. databricks_cli requires the databricks
extra (pip install omnigent[databricks]) and only works on linux_bwrap — the Go
CLI ignores SSL_CERT_FILE on macOS, so darwin_seatbelt is rejected.
Sharing a policy
Declare the sandbox once and reuse it with a YAML anchor:
os_env:
type: caller_process
cwd: .
sandbox: &shared
write_paths: [.]
read_paths: [~/.gitconfig, ~/.ssh]
allow_network: true
terminals:
zsh:
command: zsh
os_env:
type: caller_process
cwd: .
sandbox: *shared # same policy as sys_os_* tools
Or use os_env: inherit on a terminal or sub-agent to inherit the parent's
full environment including its sandbox.
In a multi-harness setup, each sub-agent defines its own sandbox in its own
config.yaml file in the agents/ subdirectory. Agent entries
in tools.agents are just names (strings), not inline config blocks.
# Parent config.yaml
tools:
agents:
- researcher
- coder
# agents/researcher/config.yaml
os_env:
sandbox:
write_paths: [./research]
allow_network: true
# agents/coder/config.yaml
os_env:
sandbox:
write_paths: [./src]
allow_network: false
What is and isn't sandboxed
The OS sandbox applies to sys_os_* tool calls and terminals that reference the
policy. It does not apply to:
- MCP servers. The runner spawns MCP subprocesses outside the sandbox. Constrain an MCP server at its own configuration site.
- The Omnigent supervisor process. It runs the model loop and dispatches tools. Only the commands it issues through OS tools run inside the sandbox.
If you ask for a sandbox (explicitly or via the default) and it can't be provided,
Omnigent errors instead of quietly running unsandboxed. The only opt-out is
sandbox.type: none.
Field reference
os_env
| Field | Type | Default | Description |
|---|---|---|---|
type | string | caller_process | OS environment backend |
cwd | string | . | Working directory |
sandbox | block | platform default | Sandbox policy (see below) |
start_in_scratch | bool | false | Start in a writable scratch tmpdir instead of cwd. Workspace bound read-only. Requires an active sandbox. |
os_env.sandbox
| Field | Type | Default | Description |
|---|---|---|---|
type | string | auto-detect | linux_bwrap, darwin_seatbelt, or none |
write_paths | string[] | [] | Writable directories. cwd is read-only by default. |
write_files | string[] | [] | Individual writable files |
read_paths | string[] | none | Read-only grants outside cwd |
allow_network | bool | true | Network access on/off |
cwd_allow_hidden | string[] | [".venv"] | Dotfile basenames to allow |
cwd_hidden_scan_recursive | bool | false | Recurse subdirectories when masking dotfiles. false scans top level only. |
mask_paths | string[] | none | Explicit files/dirs to hide by any path/name, on top of the dotfile mask |
cwd_hidden_scan_max_entries | int | 50000 | Max entries for dotfile mask walk (recursive mode) |
cwd_hidden_scan_overflow | string | warn | error, warn, or unlimited |
env_passthrough | string[] | minimal set | Env vars the agent can see |
egress_rules | string[] | none | HTTP(S) allow-list. Default-deny when set. |
egress_allow_private_destinations | bool | false | Allow connections to private/metadata IPs |
credential_proxy | block[] | none | Secretless auth entries; requires egress_rules |