Files
docker-docs/data/sbx_cli/sbx_env.yaml
T
David Karlsson c64e3927ef docs: update Sandboxes for the v0.48.0 CLI refactor (#26314)
## Summary

Update the Sandbox documentation for the v0.48.0 CLI refactor: renamed
flags, settings commands, terminal output, structured output, and
non-interactive confirmations. Add a migration reference for scripts and
CI workflows, with a [**Copy as prompt**
button](https://deploy-preview-26314--docsdocker.netlify.app/ai/sandboxes/workflows/automation/#update-scripts-for-v0480)
that copies agent instructions and the section Markdown.

This PR targets `main` independently of the other PRs in the sbx/v0.48.0
milestone. It keeps the generated reference import separate from
documentation edits:

- Vendor the 120 generated CLI YAML files
- Update command examples and guidance. Historical release notes retain
their original command spellings.

The other milestone PRs cover separate release features; this PR covers
the CLI migration.

@netlify /ai/sandboxes/workflows/automation/

Generated by Codex
2026-10-13 17:18:50 +02:00

245 lines
13 KiB
YAML

name: sbx env
synopsis: |
Manage sandboxes declaratively from an sbxenv.yaml file
experimental: true
description: |
Manage a sandbox environment declared in an sbxenv.yaml file.
The file describes the agent, optional mixin kits, workspace mounts,
environment variables, secrets to provision, and per-service credential
bindings. Secrets are provisioned at the environment's sandbox scope so
`sbx env rm` can remove everything it created.
A secret with `command` or `ref` can set `snapshot: true` to resolve on
the host after approval and store the result as a literal. This works locally
and with --cloud. Snapshots do not refresh; recreate the environment to rotate
them. A snapshot cannot set refresh or noVerify.
Command secrets run from a fresh temporary directory on the host during
verification and refresh. The host temporary directory must be absolute and must
remain outside writable sandbox mounts. Relative references such as ./helper or
cat token no longer resolve against the project or daemon working directory. Use an absolute
helper path outside shared workspaces. sbx does not copy helpers, inspect their
dependencies, or confine their execution. Helpers and any code or configuration
they load must remain outside writable sandbox mounts. Explicit paths into shared
workspaces and broad mounts exposing host configuration or the host temporary
directory remain unsafe, including mounts added later with sbx mount.
secrets:
github:
command: gh auth token
snapshot: true
A file may declare its own inputs in an `args:` block, each with a default or
`required: true` and an optional description, enum, or pattern. Reference one
as `${{ env.args.NAME }}` anywhere a value appears and supply it with
`--env-arg NAME=VALUE`.
A `kits:` entry is either a bare reference or a mapping carrying the
arguments that kit declares, which `--kit-arg` overrides per invocation:
kits:
- ./mixins/base
- source: ./mixins/tool
args:
version: ${{ env.args.channel }}
A kit source written as an explicit relative path — `./…`, `../…`, `.`, `..`, or one
ending in `.zip` — is resolved against the directory of the file that declares
it, so a checked-in file reaches the same kits from wherever `sbx` is run. Write a
local kit that way: a bare `kits/tool` is as much a registry reference as a
directory, so it is left as written and resolves from the current directory.
A `workspace:` names the directory mounted read/write into the sandbox. A
relative path resolves against the directory of the file that declares it — as
a relative kit source does — so `workspace: .` mounts the directory the file
sits in. ${{ env.projectDir }} names the project directory (the one holding the
first PATH, or the current directory when none is named) and ${{ env.fileDir }}
the declaring file's own, for a value that spells its anchor out. Declaring
none mounts nothing — as omitting PATH does for `sbx create` — and the agent
works in the container's own filesystem instead of on your files. Unless the file sets `name:` or --name overrides it,
the sandbox is named after the mounted directory, or after the project directory
when nothing is mounted, so an environment that mounts nothing is still the same
sandbox every time.
A `lifecycle:` block declares commands that run on the host — outside
the sandbox, with your own privileges — around the sandbox's life:
lifecycle:
initialize:
- command: test -d app || git clone https://github.com/acme/app
postCreate:
- command: ./scripts/seed-fixtures.sh
preRemove:
- command: ./scripts/archive-state.sh
Each runs through your shell from the project directory — the one holding the
first PATH, or the current directory when none is named; ${{ env.projectDir }}
names the same place, and commands merged in from a file elsewhere share it.
Change it per command with `workdir:`, and cap a command's runtime with
`timeout:`.
"initialize" runs on every "create" and every "run", including one that only
attaches, so it can produce the workspace the sandbox mounts; write it to be
repeatable. "postCreate" runs once the sandbox exists, and "preRemove" after
"sbx env rm" is confirmed but before it deletes anything. Whatever stops
preRemove is only a warning, so a teardown that cannot run still cannot make an
environment unremovable; what one adds to the environment instead — a stored
credential, an approved domain — stops the removal, since what follows would
delete it without a plan row ever naming it. "sbx env exec" runs no commands at
all.
Commands appear in the environment plan with the directory each runs in, and are
approved with it before the invocation does any work. An environment that declares
any of them asks on every invocation, whether or not this one is what runs them,
since approving a command also trusts whatever it invokes, including a script
whose contents change after the answer. Use --skip-host-commands to run none of
them.
Everything an environment sets up — host commands, credentials, bindings, MCP
registrations, directories, published ports, the sandbox itself and the
variables it runs with — is shown as a plan and approved before anything runs:
ENVIRONMENT
Name: claude-proj
File: /Users/me/proj/sbxenv.yaml
SECRETS
+ anthropic
ref: op://vault/anthropic/key
refresh: 55m
LIFECYCLE
~ initialize: make setup && make seed
command: make setup -> make setup && make seed
workdir: /Users/me/proj
1 to add · 1 to change · 0 to destroy
Approve this plan? (y/N)
The plan groups resources by the block of the file that declares them, in the
order the blocks are declared, so a row is looked up where it was written. The
mark in front of a row is what applying does to the resource, and the totals
name every mark a plan can carry: "+ to add" and "~ to change" above,
"- to destroy" for what "sbx env rm" takes away, "> to run" for a command that
runs again — a command converges to nothing, so it runs on every apply that
reaches it — and "! to forget" for a resource this environment applied and no
longer declares. Where the file has nothing to say, the text after the row's name does:
that a resource is missing, or that the work waits for the next create, since a
port, a credential, a kit or a postCreate command comes with the sandbox, so
attaching to one that already exists leaves it for the next one that is built. A
resource that is as it was, and already approved, is left out: what is on screen
is what there is to read.
The lines under a row are the attributes the environment declares, so an edited
kit argument or variable reads as what it was against what it becomes, and a
"command:" or "ref:" secret shows where the credential comes from — a command
that resolves one runs on this machine. A secret's literal "value:" is the one
exception: a plan is both shown here and written to state, so it is named and
stands in as a "sha256:" digest.
KITS
~ ./mixins/tool
args.version: 1.2.3 -> 1.2.4
ENV
~ GOFLAGS
value: -mod=mod -> -mod=readonly
What an attribute was is what this environment last applied here, or — for one it
approved and never applied, such as a binding or a port answered for while
attaching to a sandbox that already exists — what was approved. Either way an
edit shows the value the question is about, whatever the row itself does.
An environment file that a mount would hand over read-write — which is what
mounting the project directory holding it does — is bound read-only at its own
path inside that mount, leaving the rest of it writable. The file decides what a
later invocation runs on this machine, so an agent able to edit it decides what
the next plan asks about. Declare "sandboxOptions.writableEnvFiles: true" where an
agent is meant to edit it; the plan then says the file is writable, as it says
when a file sits below a mount's own directory, where renaming that directory
reaches it again.
What was approved is recorded per environment under sbx's state directory, not
next to the file, so a later invocation asks only about what moved — and applies
silently when nothing did. An environment that declares commands running on this
machine is asked about on every invocation, changed or not: the answer is about
the invocation, and what a command does depends on what the project holds when it
runs rather than on the text approved before. "sbx env plan" prints the plan and
changes nothing.
Use --force (-f) where there is no terminal to answer on. Where an
environment's commands are your own and run many times a day,
"sbx settings set env.rememberHostCommands true" asks about them only when
they change.
With --cloud, create, run, exec, rm and plan manage a cloud sandbox from the same
file. Supported declarations are agents and kits, sandbox environment variables,
CPU and memory sizing, literal or snapshot secrets and bindings for supported providers, and
host lifecycle commands. Kits can publish TCP ports through cloud endpoints.
Stored cloud secrets are inherited as with cloud create/run; sandbox-scoped secrets
override account defaults, and secrets declared in the file override both. The plan
shows inherited credentials. Removal deletes only secrets provisioned by this environment.
Bindings merge into the same global credentials.yaml as local environments and
are retained on removal unless --prune-bindings is passed. Cloud must advertise
kit credential support. Third-party kit domains must be approved by the binding;
creation refuses implicit provider-default routing for a bound secret. Bindings
and secrets are provisioned at creation; editing them requires recreating the sandbox.
Snapshot references use the host's supported CLI resolvers (such as op:// and AWS
Secrets Manager ARNs); the sdk backend is unsupported. An interrupted secret
upload reuses the saved value in the host credential store. If that value is
unavailable, resolution is not repeated: follow the recovery error before cleanup.
workspace, additionalWorkspaces and clone name host directories, which a cloud
sandbox cannot mount; remove them and clone the project inside the sandbox from a
kit instead. Host port bindings, registry credentials, MCP definitions, custom
credential providers, local sandbox options and dynamic secret sources are also
rejected before host commands or provisioning. Initialize commands may prepare
local kit sources; kit validation follows initialization and precedes cloud baking.
State belongs to this machine, the selected cloud endpoint, Docker identity and
ordered environment files. Use the same target and files for subsequent commands.
DOCKER_ACCESS_TOKEN uses a token-specific state scope: changing the token starts
with separate state. Use sbx login for state that survives token refresh.
If creation is interrupted, retry the same command and declaration within 23 hours.
Removal waits for unresolved writes to be recovered. Older unresolved attempts
retain their journal; the error names its path. Before deleting that journal,
confirm the original requests have finished and remove their sandbox and secrets
using ordinary cloud commands in the same account and endpoint. If the outcome
cannot be confirmed, retain the journal and contact support.
Lifecycle commands inherit the cloud endpoint and expose SBX_SANDBOX_ID after
creation. Sandbox env values apply to new sessions; rejoining a live agent keeps
that process's existing environment.
sbx --cloud env plan ./sbxenv.yaml
sbx --cloud env run --force --detach ./sbxenv.yaml
sbx --cloud env exec ./sbxenv.yaml -- git status
sbx --cloud env rm --force ./sbxenv.yaml
usage: sbx env COMMAND
options:
- name: help
shorthand: h
default_value: "false"
usage: help for env
inherited_options:
- name: cloud
default_value: "false"
usage: |
Dispatch to Docker Cloud Sandboxes API instead of local sandboxd (supported by a growing set of verbs — run 'sbx --cloud --help' for the current list)
- name: debug
shorthand: D
default_value: "false"
usage: Enable debug logging
see_also:
- sbx - Manage AI coding agent sandboxes.
- sbx env create - Create a sandbox environment from sbxenv.yaml
- sbx env exec - Execute a command inside a sandbox environment
- sbx env plan - Show what an environment would change outside the sandbox
- sbx env rm - Remove a sandbox environment and its scoped resources
- sbx env run - Create (if needed) and attach to a sandbox environment