[sandbox.os.command_tools]
Each entry is either a bare bundle-name string like "git" (shorthand for the bundle’s defaults) or a table { tool = "<name>", … } that overrides per-bundle knobs.
Bundles
Section titled “Bundles”git — read binds for ~/.gitconfig, ~/.config/git, /etc/gitconfig; forwards GITHUB_TOKEN + GIT_AUTHOR_* / GIT_COMMITTER_* to git:* patterns.
default_domains
Section titled “default_domains”domains
Section titled “domains”gh_creds
Section titled “gh_creds”wrappers
Section titled “wrappers”gh — read bind for ~/.config/gh; forwards GH_TOKEN + GITHUB_TOKEN to gh:*.
default_domains
Section titled “default_domains”domains
Section titled “domains”wrappers
Section titled “wrappers”jj — read binds for ~/.config/jj, ~/.jjconfig.toml; forwards JJ_USER / JJ_EMAIL / JJ_EDITOR to jj:*.
default_domains
Section titled “default_domains”domains
Section titled “domains”gh_creds
Section titled “gh_creds”wrappers
Section titled “wrappers”gt — Graphite CLI (gt). RW bind for ~/.config/graphite (gt auth --token writes user_config there; subsequent gt invocations read AND rewrite it on startup — updateAutomatically is bumped on version change. The same dir holds aliases); RW bind for ~/.local/share/graphite/debug (per-invocation debug log dir that gt feedback ships to Graphite support); project-relative RW bind for .git (gt writes its per-repo metadata to <repo>/.git/.graphite_repo_config). gt submit shells out to git push over HTTPS, so the bundle also consumes gh auth git-credential via [CredentialSource::GhAuth] — same auto-wire as git / jj. Default network = github (*.github.com) + graphite (*.graphite.com, *.graphite.dev — graphite’s CLI talks to both api.graphite.com for stack metadata and historically api.graphite.dev during the .com → .dev migration).
default_domains
Section titled “default_domains”domains
Section titled “domains”gh_creds
Section titled “gh_creds”wrappers
Section titled “wrappers”linear
Section titled “linear”linear — read bind for ~/.config/linear-cli; forwards LINEAR_API_KEY to linear:*.
default_domains
Section titled “default_domains”domains
Section titled “domains”wrappers
Section titled “wrappers”cargo — read bind for ~/.cargo/config.toml; RW or RO for ~/.cargo/registry/{cache,src,index} depending on the fetch knob (RW by default to let in-sandbox builds populate the registry cache on a miss). Forwards CARGO_* env vars to cargo:*.
default_domains
Section titled “default_domains”domains
Section titled “domains”install
Section titled “install”sccache
Section titled “sccache”Tri-state knob for the cargo bundle’s sccache support.
Off(default): no sccache binds, no env passthrough, no daemon supervision.Manual: bundle adds the~/.cache/sccacheRW bind +RUSTC_WRAPPER/SCCACHE_*env passthrough. seal-daemon does NOT supervise the host sccache daemon — user runssccache --start-serverthemselves (or accepts first-shell-start latency).On: same bundle surface asManual, PLUS opts seal-daemon into supervising the host sccache daemon. The first session withontriggers a process-wide latch — seal-daemon ensuressccache --start-serveris running until daemon shutdown. Hard-fails session start if sccache is missing or refuses to start.
Schema break vs the older sccache = true bool. The new enum’s custom [Deserialize] impl rejects bool values with a migration message naming the three valid string variants. true ≈ "manual" historically; false ≈ "off". The break is intentional: the new "on" semantics didn’t exist before, and silent coercion of true → "manual" would hide it from users who actually want supervision.
| Value | Meaning |
|---|---|
"off" | No sccache surface added by the bundle. Default. |
"manual" | Bundle adds binds + env. User supervises sccache themselves. |
"on" | Bundle adds binds + env. seal-daemon supervises sccache. |
wrappers
Section titled “wrappers”node — read binds for ~/.npmrc, ~/.node_modules, plus ~/.nvm and ~/.fnm (for nvm / fnm version managers, which the node shim on PATH consults to pick a toolchain at exec time). Forwards NODE_OPTIONS, NODE_PATH, NODE_ENV, NVM_DIR, FNM_* to node:*. No write binds — node itself doesn’t manage caches. Default network = npm registry so dynamic import('npm:...') and fetch() to the registry work.
default_domains
Section titled “default_domains”domains
Section titled “domains”wrappers
Section titled “wrappers”npm / npx — read bind for ~/.npmrc and ~/.config/npm; RW bind for ~/.npm (the install cache); forwards NPM_TOKEN, NPM_CONFIG_*, NODE_AUTH_TOKEN to npm:* and npx:*. Default network = npm registry.
default_domains
Section titled “default_domains”domains
Section titled “domains”wrappers
Section titled “wrappers”bun / bunx — read bind for ~/.bunfig.toml; RW bind for ~/.bun/install/cache (bun’s dep cache); forwards BUN_INSTALL, BUN_CONFIG_*, NPM_TOKEN, NODE_AUTH_TOKEN to bun:* and bunx:*. Default network = npm registry + bun.sh (for runtime self-update probes).
default_domains
Section titled “default_domains”domains
Section titled “domains”install
Section titled “install”wrappers
Section titled “wrappers”yarn — read binds for ~/.yarnrc (classic), ~/.yarnrc.yml (berry), ~/.config/yarn; RW binds for ~/.yarn and ~/.cache/yarn (the install + content caches). Forwards YARN_*, NPM_TOKEN, NODE_AUTH_TOKEN to yarn:*. Default network = npm registry + registry.yarnpkg.com.
default_domains
Section titled “default_domains”domains
Section titled “domains”wrappers
Section titled “wrappers”pnpm / pnpx — read binds for ~/.npmrc and ~/.config/pnpm; RW bind for ~/.local/share/pnpm (the content-addressable store). Forwards PNPM_HOME, NPM_*, NODE_AUTH_TOKEN to pnpm:* and pnpx:*. Default network = npm registry.
default_domains
Section titled “default_domains”domains
Section titled “domains”wrappers
Section titled “wrappers”direnv
Section titled “direnv”direnv — read bind for ~/.config/direnv; RW bind for ~/.local/share/direnv (the per-.envrc allow-store direnv writes the first time it sees a body). Forwards DIRENV_*, XDG_DATA_HOME, XDG_CONFIG_HOME. The bundle is the user-facing opt-in for sandboxed direnv exec wrapping — without it, [command_run] envrc_mode = "trust" (or any approved .envrc) used to bypass the sandbox entirely; with it, the wrapped spawn runs inside bwrap and direnv has the RW it needs to record allow-store entries. No curated domains (direnv itself doesn’t network); workspaces that use flake etc. add upstream cache hosts via { tool = "direnv", domains = [...] }.