{"slug": "sbx-env-consistent-and-shareable-ai-sandbox-configurations", "title": "SBX env: consistent and shareable AI sandbox configurations", "summary": "The experimental `sbx env` command lets developers capture a sandbox's agent, tools, resources, and credentials in a shareable `sbxenv.yaml` file, with `schemaVersion: \"1\"` as the current format version. Running `sbx env run` from a directory containing `sbxenv.yaml` shows an environment plan for approval, then creates a sandbox named `web-app`, installs Playwright and Chromium, and publishes sandbox port 3000 on the host. The documentation warns that the command interface and file format may change, and advises keeping the environment file outside mounted workspace directories.", "body_md": "# Sandbox environment files\n\nA sandbox environment file captures the setup for a local or cloud sandbox in a\n`sbxenv.yaml` file. Share the file with project contributors so they use the\nsame agent, tools, resources, and credentials without reproducing CLI flags and\nsetup steps.\n\nNote\n`sbx env` is experimental. The command interface and file format may change.\n\nThe examples on this page use local sandboxes unless stated otherwise. For\ncloud configuration and lifecycle differences, see\n[Use a cloud environment](#use-a-cloud-environment).\n\n## [Start an environment](#start-an-environment)\n\nKeep the environment file outside the directories you mount into the sandbox.\nThat includes the primary workspace and every `additionalWorkspaces` mount.\nFor example, place it beside your project:\n\n```\nweb-app-env/\n├── sbxenv.yaml\n└── web-app/\n```\n\nCreate `web-app-env/sbxenv.yaml`. This example gives the agent a shared\nenvironment variable and the Playwright browser-testing tools. It also\npublishes the application's development port:\n\n```\nschemaVersion: \"1\"\nname: web-app\nagent: claude\nworkspace: ./web-app\n\nkits:\n  - docker.io/sbx/playwright-kit:latest\n\nenv:\n  NODE_ENV: test\n\nports:\n  - sandbox: 3000\n    host: 3000\n```\n\nFrom `web-app-env`, run the environment:\n\n``` bash\n$ sbx env run\n```\n\n`sbx` shows an environment plan and asks you to approve it. If you approve the\nplan, the `web-app` directory becomes the workspace, while `sbxenv.yaml` remains\noutside the sandbox. If the environment doesn't exist, `sbx` creates a sandbox\nnamed `web-app`, installs Playwright and Chromium, and publishes sandbox port\n`3000` on the host. It then attaches to the agent. Later runs attach to the\nexisting sandbox.\n\nThis placement keeps the environment file outside the agent's writable\nworkspace. If you later add `additionalWorkspaces`, keep `sbxenv.yaml`\noutside those directories too. See the [`workspace` guidance](#workspace)\nfor details.\n\n## [Commands](#commands)\n\n| Command | Description | \n|---|---|\n| `sbx env plan [PATH...]` | Shows what applying the environment would change without changing or approving it | \n| [`sbx env run`](https://docs.docker.com/reference/cli/sbx/env/run/)`[PATH...]` | Applies the approved plan, creates the environment if needed, and attaches | \n| [`sbx env create`](https://docs.docker.com/reference/cli/sbx/env/create/)`[PATH...]` | Applies the approved plan and creates the environment without attaching | \n| [`sbx env exec`](https://docs.docker.com/reference/cli/sbx/env/exec/)`[PATH...] -- COMMAND [ARG...]` | Runs a command in an existing environment without running lifecycle commands | \n| [`sbx env rm`](https://docs.docker.com/reference/cli/sbx/env/rm/)`[PATH...]` | Shows a destroy plan, then removes the sandbox and resources named in the plan | \n\nTo use an environment file, pass its path to `sbx env`. If you pass a\ndirectory, `sbx` looks for `sbxenv.yaml` inside it. If you don't pass a path,\n`sbx` looks in the directory you run the command from and loads your\n[user defaults](#set-user-defaults), if present.\n\nEvery `sbx env` subcommand accepts `--name`. This flag sets the sandbox name\nfor that command, overriding the `name` field in the file or the automatically\ngenerated name:\n\n``` bash\n$ sbx env create --name web-app-test\n$ sbx env exec --name web-app-test -- npm test\n$ sbx env rm --name web-app-test\n```\n\nUse the same file paths for each command. If you set `--name`, use that same\nname for every command that manages the sandbox.\n\n### [Set user defaults](#set-user-defaults)\n\nCreate `~/.sbxenv.yaml` to share settings across your projects. For example,\nthis file selects Claude as the agent and mounts the directory you run\n`sbx env` from:\n\n```\nschemaVersion: \"1\"\nagent: claude\nworkspace: ${{ env.projectDir }}\n```\n\nWith this file saved in your home directory, run:\n\n``` bash\n$ cd /projects/web-app\n$ sbx env run\n```\n\nThe sandbox mounts `/projects/web-app` as its workspace. Run the same command\nfrom `/projects/api`, and it mounts `/projects/api` instead. You don't need a\nseparate `sbxenv.yaml` in either project.\n\nIf the project has a `sbxenv.yaml`, `sbx` combines it with your user defaults.\nProject settings override individual default values. Lists such as `ports`\nand `mcp.servers` combine entries from both files. If you pass a file or\ndirectory path to the command, `sbx` skips `~/.sbxenv.yaml`.\n\nIn `~/.sbxenv.yaml`, you can set `workspace` to `${{ env.projectDir }}` or a\nsubdirectory such as `${{ env.projectDir }}/src`. Other workspace paths\naren't accepted in this file.\n\nThe user defaults file cannot set `name`. Set the sandbox name in a project\nenvironment file or with `--name`.\n\n### [Reference directories](#reference-directories)\n\nYou can use `${{ env.projectDir }}` and `${{ env.fileDir }}` in environment\nfiles to insert absolute directory paths. They refer to directories on the\nhost.\n\n#### [Project directory](#project-directory)\n\n`${{ env.projectDir }}` is the absolute path to your project directory.\n`sbx` chooses this directory from the command you run:\n\n- `sbx env run` : the directory you run the command from.\n- `sbx env run /projects/web-app` :`/projects/web-app` .\n- `sbx env run /projects/web-app/custom.yaml` :`/projects/web-app` , the\ndirectory containing the file.\n\nIf you pass several paths, the first one sets the project directory. Every\nfile loaded by that command uses the same value for `env.projectDir`.\n\nUse this reference in shared settings that need to point to each project's\nfiles. For example, `workspace: ${{ env.projectDir }}/src` mounts the `src`\ndirectory in whichever project you select.\n\n#### [File directory](#file-directory)\n\n`${{ env.fileDir }}` is the absolute path to the directory containing the\nenvironment file where you write the reference. For example, inside\n`/shared/environment.yaml`, its value is `/shared`.\n\nUse this reference when an environment file needs to locate files stored\nalongside it. For example, suppose your setup script is\n`/shared/scripts/setup.sh`. Add this [lifecycle command](#lifecycle) to\n`/shared/environment.yaml` to run the script from `/shared`:\n\n```\nlifecycle:\n  initialize:\n    - command: ./scripts/setup.sh\n      workdir: ${{ env.fileDir }}\n```\n\nThe command runs from `/shared`, even if you use this environment file with\na project in another directory.\n\nRelative workspace paths already use the directory containing the environment\nfile. For example, `workspace: ./src` in `/shared/environment.yaml` mounts\n`/shared/src`.\n\nBoth directory references can appear in YAML values, but not in field names\nor inside the `args` block.\n\n### [Parameterize an environment](#parameterize-an-environment)\n\nDeclare inputs in a top-level `args` block when values need to vary between\nuses of the same environment file. Each argument must have exactly one of\n`default` or `required: true`:\n\n```\nschemaVersion: \"1\"\nname: web-app\nagent: claude\n\nargs:\n  channel:\n    default: stable\n    description: Release channel\n    enum:\n      - stable\n      - beta\n  endpoint:\n    required: true\n    description: API endpoint\n  cpus:\n    default: \"4\"\n    pattern: \"[1-9][0-9]*\"\n\nenv:\n  RELEASE_CHANNEL: ${{ env.args.channel }}\n  API_ENDPOINT: ${{ env.args.endpoint }}\n\nsandboxOptions:\n  cpus: ${{ env.args.cpus }}\n```\n\nReference a declared argument as `${{ env.args.NAME }}` anywhere a YAML value\ncan appear. References can't be used in field names or within the `args` block.\nAn unquoted reference is interpreted as a YAML value after substitution, so\nthe `cpus` value in this example becomes an integer. Quote a reference to\npreserve it as a string.\n\nAll `sbx env` commands accept repeatable `--env-arg NAME=VALUE` flags. Values\nprovided with a flag replace defaults from the environment file:\n\n``` bash\n$ sbx env run --env-arg endpoint=https://api.example.com --env-arg channel=beta\n```\n\nUse `--env-args-file` to load values from a file. Each non-empty, non-comment\nline must have the form `NAME=VALUE`:\n\n```\n# production.args\nchannel=beta\nendpoint=https://api.example.com\nbash\n$ sbx env run --env-args-file production.args\n```\n\nYou can pass multiple argument files. Later files take precedence over earlier\nfiles, and `--env-arg` flags take precedence over every argument file.\nValues can contain `=`, and values in an argument file are read literally\nrather than expanded by a shell.\n\nArgument references and the two directory references are the only variable\nexpressions expanded in an environment file. Shell-style expressions such as\n`${VAR}` aren't expanded from the host environment. Other dollar signs remain\nliteral, so a value such as `$PATH:/opt/bin` is passed unchanged.\nUse `$${{ env.args.NAME }}` to produce the literal text `${{ env.args.NAME }}`. Substituted values aren't expanded a\nsecond time.\n\n## [Common workflows](#common-workflows)\n\nThe following examples combine environment file fields into configurations you can adapt for a project.\n\n### [Combine team defaults and personal settings](#combine-team-defaults-and-personal-settings)\n\nKeep the shared configuration in a version-controlled environment directory\noutside the mounted workspace. Put machine-specific settings in a file excluded\nfrom version control. For example, commit `base.sbxenv.yaml` beside the\n`web-app` directory:\n\n```\nschemaVersion: \"1\"\nname: web-app\nagent: claude\nworkspace: ./web-app\n\nenv:\n  NODE_ENV: development\n\nsandboxOptions:\n  cpus: 4\n  memory: 8g\n```\n\nAdd `local.sbxenv.yaml` to `.gitignore`, then use it for personal settings:\n\n```\nenv:\n  LOG_LEVEL: debug\n\nsandboxOptions:\n  memory: 12g\n```\n\nPass both files in merge order:\n\n``` bash\n$ sbx env run base.sbxenv.yaml local.sbxenv.yaml\n```\n\nNested mappings merge by key, lists concatenate, and values from later files replace earlier scalar values. In this example, the sandbox has four CPUs, 12 GB of memory, and both environment variables. Each relative workspace path resolves from the directory of the file that declares it.\n\n### [Work across multiple repositories](#work-across-multiple-repositories)\n\nMount related repositories alongside the primary project when the agent needs to coordinate changes or consult shared code and documentation:\n\n```\n# sbxenv.yaml in the directory above the repositories\nschemaVersion: \"1\"\nname: web-platform\nagent: codex\n\nworkspace: ./web-app\n\nadditionalWorkspaces:\n  - path: ./shared-components\n  - path: ./architecture-docs\n    readOnly: true\n```\n\nThe agent starts in `web-app`, can modify `shared-components`, and can read\n`architecture-docs` without changing it. The environment file stays outside all\nthree workspaces. Relative paths resolve from the directory of the\nenvironment file that declares them. Additional workspaces are mounted directly\neven when the primary workspace uses clone mode.\n\n### [Reuse an environment in automation](#reuse-an-environment-in-automation)\n\nUse the same committed environment for interactive development and automated\ntasks. Developers attach to the agent with `run`:\n\n``` bash\n$ sbx env run\n```\n\nAutomation can create the sandbox without attaching, run commands in it, and remove it afterward:\n\n``` bash\n$ sbx env create --auto-approve\n$ sbx env exec -- npm test\n$ sbx env rm --force\n```\n\n`--auto-approve` approves the plan for that invocation without recording\nconsent for later invocations. Use the flag for each unattended `create` or\n`run`. The `--force` flag approves the destroy plan and removes the sandbox even\nwhen it is in use.\n\nCommands and vault references under `secrets` resolve on the host, so the\nautomation runner must provide the referenced tools and authentication. The\nsecret values remain outside the environment file.\n\n### [Use a cloud environment](#use-a-cloud-environment)\n\nUse `sbx --cloud env` to manage a cloud sandbox from an environment file. For\naccount and CLI requirements, see [Cloud sandboxes](https://docs.docker.com/ai/sandboxes/cloud/).\n\nSave this as `cloud.sbxenv.yaml`:\n\n```\nschemaVersion: \"1\"\nname: cloud-project\nagent: shell\n\nenv:\n  PROJECT_NAME: example\n\nsandboxOptions:\n  cpus: 2\n  memory: 4g\n```\n\nReview the plan, create the sandbox without attaching, and run a command:\n\n``` bash\n$ sbx --cloud env plan ./cloud.sbxenv.yaml\n$ sbx --cloud env run --detached ./cloud.sbxenv.yaml\n$ sbx --cloud env exec ./cloud.sbxenv.yaml -- printenv PROJECT_NAME\n```\n\nCloud environments support agents and kits, environment variables, CPU and\nmemory limits, credentials for supported providers, and host lifecycle commands.\nResource limits must match a [cloud size](https://docs.docker.com/ai/sandboxes/cloud/usage/#choose-resources-and-platform).\nLifecycle commands still run on your machine with your privileges.\n\nRemove `workspace`, `additionalWorkspaces`, clone options, `ports`, `registries`,\nand MCP server definitions from a local file before using it in cloud mode.\nCloud environments also reject local sandbox options such as GPU, USB,\ndisplay, shared skills, templates, and governance profiles. These checks run\nbefore host commands or provisioning. Transfer project files with\n[`sbx --cloud cp`](https://docs.docker.com/ai/sandboxes/cloud/usage/#transfer-files) or clone a repository inside\nthe sandbox.\n\nThe plan shows inherited cloud credentials. Sandbox-scoped credentials override\naccount defaults, and credentials declared in `secrets` override both. Declare\nliteral values or use [`snapshot: true`](#secrets) to resolve a host command or\nvault reference once. Dynamic secret sources and custom credential providers\naren't supported. Credential bindings require cloud support for kit credentials\nand explicit approval of the kit's injection domains.\n\nChanges to secrets and bindings require recreating the sandbox. Updated `env`\nvalues apply to subsequent sessions. Rejoining a running agent keeps that\nprocess's environment.\n\nUse the same machine, Docker identity, cloud endpoint, and ordered file paths\nfor later commands. `sbx login` keeps environment state associated with your\nDocker identity. With `DOCKER_ACCESS_TOKEN`, changing the token starts a separate\nstate scope.\n\nRemove the environment when you're finished:\n\n``` bash\n$ sbx --cloud env rm ./cloud.sbxenv.yaml\n```\n\nRemoval deletes the sandbox and only the secrets provisioned by this\nenvironment. Inherited secrets remain. Global bindings remain unless you pass\n`--prune-bindings`. For unattended runs, use `--auto-approve` with `create` or\n`run`, and `--force` with `rm`.\n\nIf creation is interrupted, retry the same command and unchanged declaration within 23 hours. Unresolved requests prevent removal. Follow the recovery message and retain its journal until the original requests are resolved.\n\n## [Review an environment plan](#review-an-environment-plan)\n\n`sbx env create`, `sbx env run`, and `sbx env rm` show the changes an\nenvironment makes outside its sandbox and ask for approval before applying\nthem. The plan includes host commands, credentials, bindings, MCP\nregistrations, directories, kits, published ports, sandbox options, and\nenvironment variables.\n\nRun `sbx env plan` to inspect the apply plan without changing, approving, or\nrecording anything:\n\n``` bash\n$ sbx env plan\n```\n\nThe plan compares the environment file with the environment's last applied state and the resources on the host. It omits resources that are unchanged and already approved. Literal secret values appear as SHA-256 digests. Secret references, host commands, environment variables, ports, paths, and binding domains remain visible so you can review them.\n\nInteractive approval is recorded for the environment under the `sbx` state\ndirectory. Plans without host commands apply silently on later invocations until\nthe environment changes or a resource is missing. An approval provided with\n`--auto-approve` applies only to that invocation.\n\n## [Update an environment](#update-an-environment)\n\nFor an existing sandbox, `sbx env run` applies updated `env` values to the new\nagent session and reconciles declared MCP servers. Changes to workspaces, kits,\nports, secrets, bindings, and `sandboxOptions` take effect only when the\nsandbox is next created. Remove the environment with `sbx env rm`, then create\nit again to apply those changes.\n\n## [Remove an environment](#remove-an-environment)\n\nSecrets and registry credentials are sandbox-scoped. Credential bindings and MCP server registrations are host-global and can be shared by multiple sandboxes.\n\n`sbx env rm` builds a destroy plan from the resources on the host. The plan\nincludes all credentials stored at the sandbox's scope, including credentials\nthat the environment file no longer declares. After approval, `sbx` removes\nonly the resources named in the plan.\n\nGlobal credential bindings remain unless you pass `--prune-bindings`. MCP\nregistrations remain available to other sandboxes.\n\n### [Clean up after a failed create](#clean-up-after-a-failed-create)\n\nSecret provisioning, binding updates, and MCP server registration occur before\nthe sandbox is created. If sandbox creation fails, scoped secrets remain, and\nbindings and MCP registrations may also remain. Run `sbx env rm` with the same\npaths to remove the scoped secrets. Pass `--prune-bindings` if you also want to\nremove the declared global bindings. MCP registrations are host-global and\nremain after cleanup.\n\n## [File reference](#file-reference)\n\n### [Top-level fields](#top-level-fields)\n\n| Field | Type | Required | Default | Description | \n|---|---|---|---|---|\n| `schemaVersion` | string | Yes | None | Schema version. The supported value is `\"1\"` | \n| `name` | string | No | `<agent>-<workspace-basename>` | Sandbox name, overridden by `--name` | \n| `agent` | string | Yes | None | Built-in agent or the name of an agent kit | \n| `args` | map | No | None | Environment arguments. See [`args`](#args) | \n| `kits` | list | No | None | Kits to install at creation. See [`kits`](#kits) | \n| `workspace` | string or object | No | No host mount | Primary workspace. See [`workspace`](#workspace) | \n| `additionalWorkspaces` | list | No | None | Extra directories to mount. See [`additionalWorkspaces`](#additionalworkspaces) | \n| `env` | map of strings | No | None | Environment variables for the sandbox | \n| `sandboxOptions` | object | No | None | Creation options. See [`sandboxOptions`](#sandboxoptions) | \n| `secrets` | map | No | None | Service credentials. See [`secrets`](#secrets) | \n| `bindings` | map | No | None | Credential injection approvals. See [`bindings`](#bindings) | \n| `registries` | map | No | None | Registry pull credentials. See [`registries`](#registries) | \n| `mcp` | object | No | None | MCP servers. See [`mcp`](#mcp) | \n| `ports` | list | No | None | Port mappings. See [`ports`](#ports) | \n| `lifecycle` | object | No | None | Host commands. See [`lifecycle`](#lifecycle) | \n\n### [`args`](#args)\n\n`args`\n`args` maps argument names to their declarations. Names must start with a\nletter or underscore and can contain letters, numbers, underscores, and\nhyphens. Each declaration must set exactly one of `default` or `required: true`.\n\n| Field | Type | Default | Description | \n|---|---|---|---|\n| `default` | string | None | Value used when the command doesn't supply the argument | \n| `required` | boolean | `false` | Require the command to supply the argument | \n| `description` | string | None | Explanation shown in command output | \n| `enum` | list of strings | None | Values accepted for the argument | \n| `pattern` | string | None | Go ( `RE2` ) expression matched against the complete argument value | \n\n`enum` and `pattern` can't be used together.\n\n### [`kits`](#kits)\n\n`kits`\n`kits` accepts local directories, ZIP archives, OCI registry references, and\nGit URLs prefixed with `git+https://` or `git+ssh://`. Kits can install tools,\nconfigure the sandbox, and give the agent project-specific instructions.\nThe examples on this page pair built-in agents with v2 mixins. See\n[Kits v2](https://docs.docker.com/ai/sandboxes/customize/kits-v2/) for that format, or\n[Version compatibility](https://docs.docker.com/ai/sandboxes/customize/#version-compatibility)\nwhen selecting v3 kits.\n\nAn environment file selects kits and configures a sandbox's host resources.\nA kit descriptor defines the package itself. The environment file's\n`schemaVersion` is independent of the schema version in a kit descriptor.\n\nExplicit relative paths resolve from the directory of the environment file\nthat declares them. These include `.`, `..`, paths that start with `./` or\n`../`, and relative paths that end in `.zip`. Bare references such as\n`organization/kit` remain registry references.\n\nUse an object entry to pass arguments to a kit. Set `source` to the kit\nreference and map the kit's argument names to values under `args`:\n\n```\nkits:\n  - source: ./kits/tool\n    args:\n      version: ${{ env.args.channel }}\n```\n\nRemote kit sources must match the\n[`kit.allowedSources`](https://docs.docker.com/ai/sandboxes/configuration/settings/#kitallowedsources) setting. Docker Hub is\nallowed by default. To use Git kits from `docker/sbx-kits-contrib`, add its\nsource:\n\n``` bash\n$ sbx settings set kit.allowedSources '[\"docker.io/\",\"github.com/docker/\"]'\n```\n\nThe setting replaces the complete allowlist, so include any existing sources\nyou want to keep. For reproducible setup, pin Git kits with the `ref` URL\nparameter and OCI kits with an immutable tag or digest.\n\n### [`workspace`](#workspace)\n\n`workspace`\nWhen specified as a string, `workspace` is the path. Use the object form for\nclone mode. Omit `workspace` to create a sandbox without a host bind mount. Set\n`workspace: .` to mount the directory that contains the environment file\nthat declares it.\n\n`sbx` mounts the environment file read-only inside the sandbox. Keep the file\noutside direct-mounted workspaces or directly in a workspace root.\n\n| Field | Type | Required | Default | Description | \n|---|---|---|---|---|\n| `path` | string | Yes | None | Workspace directory. Relative paths resolve from the declaring file's directory | \n| `clone` | boolean | No | `false` | Use a private clone, equivalent to `sbx create --clone` | \n\nYou can override `workspace.clone` for one `create` or `run` invocation with\n`--clone` or `--clone=false`.\n\n### [`additionalWorkspaces`](#additionalworkspaces)\n\n`additionalWorkspaces`\nEach additional workspace is mounted after the primary workspace. Relative paths resolve from the directory of the environment file that declares them.\n\n| Field | Type | Required | Default | Description | \n|---|---|---|---|---|\n| `path` | string | Yes | None | Directory to mount | \n| `readOnly` | boolean | No | `false` | Mount the directory read-only | \n\n### [`sandboxOptions`](#sandboxoptions)\n\n`sandboxOptions`\n| Field | Type | Default | Description | \n|---|---|---|---|\n| `template` | string | None | Custom sandbox template image | \n| `memory` | string | None | Memory limit, such as `8g` or`512m` | \n| `cpus` | integer | `0` | Number of CPUs. `0` selects the host default | \n| `pullPolicy` | string | `always` | Image pull policy: `always` ,`missing` , or`never` | \n| `profile` | string | None | Governance profile name | \n| `skills` | string | Daemon default | Shared agent skills store access: `off` ,`readonly` , or`readwrite` | \n| `display` | boolean | `false` | Provision a display socket for graphical applications | \n| `gpu` | boolean | `false` | Pass the host GPU through to the sandbox | \n| `usb` | list of strings | None | USB device selectors to pass through to the sandbox | \n\nFor local sandboxes, `cpus: 0` allocates all host CPUs, except on Linux arm64\nhosts, where the default is capped at 16. Set `cpus` to an explicit count to\nrequest a larger allocation, up to the number of available host CPUs. When creating a sandbox directly with\n`sbx create` or `sbx run`, use `--cpus` for the same override. Cloud resource\nlimits must match a [cloud size](https://docs.docker.com/ai/sandboxes/cloud/usage/#choose-resources-and-platform).\n\n`skills` controls access to the shared [agent skills](https://docs.docker.com/ai/sandboxes/workflows/agent-skills/)\nstore. Set it to `off` to omit the mount, `readonly` to mount the store read-only,\nor `readwrite` to let the sandbox modify shared skills. If omitted, it uses the\ndaemon's default, which is `readonly` unless your organization overrides it.\n\n### [`lifecycle`](#lifecycle)\n\n`lifecycle`\nThe `lifecycle` block declares commands that run on the host with your user\nprivileges. Use lifecycle commands for work that must happen outside the\nsandbox, such as creating a workspace, seeding fixtures, or archiving state.\n\n```\nlifecycle:\n  initialize:\n    - name: Prepare workspace\n      command: test -d web-app || git clone https://github.com/example/web-app\n      timeout: 5m\n  postCreate:\n    - command: ./scripts/seed-fixtures.sh\n      workdir: web-app\n  preRemove:\n    - command: ./scripts/archive-state.sh\n```\n\nLifecycle phases run at the following points:\n\n| Phase | Timing | \n|---|---|\n| `initialize` | Before other create or run actions. Runs for every `create` and`run` | \n| `postCreate` | After a new sandbox is created. For `run` , before attachment. Does not run when attaching to an existing sandbox | \n| `preRemove` | After you approve removal and before `sbx` deletes resources. A failure produces a warning and removal continues | \n\n`sbx env exec` doesn't run lifecycle commands. Commands within a phase run in\norder and stop at the first failure. Make `initialize` commands safe to run\nmore than once.\n\nAfter `preRemove` commands finish, `sbx` generates the destroy plan again.\nRemoval stops if the commands introduced changes that weren't included in the\napproved plan.\n\nEach command requires `command` and accepts the following fields:\n\n| Field | Type | Default | Description | \n|---|---|---|---|\n| `name` | string | Command text | Label shown in progress and plan output | \n| `command` | string | None | Command passed to the user's shell | \n| `workdir` | string | Project directory | Host working directory. Relative paths resolve from the first file's directory | \n| `timeout` | string | None | Maximum runtime, such as `90s` or`5m` | \n\nCommands inherit the environment of the `sbx` process and receive the following\nvariables:\n\n- `SBX_LIFECYCLE_PHASE`\n- `SBX_ENV_FILE` and`SBX_ENV_FILES`\n- `SBX_ENV_DIR`\n- `SBX_SANDBOX_NAME`\n- `SBX_AGENT`\n- `SBX_WORKSPACE`\n\nThe environment file's `env` values and resolved secrets aren't passed to host\ncommands.\n\nPlans containing lifecycle commands or credential `command` sources require\napproval for every invocation by default, even when the command text hasn't\nchanged. Approve one invocation with `--auto-approve`, skip lifecycle commands\nwith `--skip-host-commands`, or turn on\n[`env.rememberHostCommands`](https://docs.docker.com/ai/sandboxes/configuration/settings/#envrememberhostcommands) to remember\napproval until the commands change:\n\n``` bash\n$ sbx settings set env.rememberHostCommands true\n```\n\n### [`secrets`](#secrets)\n\n`secrets`\n`secrets` maps service names to secret sources. Each entry must set exactly one\nof `value`, `ref`, or `command`. The secret is stored at the sandbox scope when\nthe environment is created.\n\n| Field | Type | Default | Description | \n|---|---|---|---|\n| `value` | string | None | Literal secret value | \n| `ref` | string | None | Vault URI, such as `op://Vault/Item/field` | \n| `command` | string | None | Host shell command whose standard output becomes the secret | \n| `snapshot` | boolean | `false` | Resolve `ref` or`command` once on the host and store the result as a literal | \n| `refresh` | string | None | Resolution policy for `ref` or`command` , such as`on-demand` or`55m` | \n| `backend` | string | Automatic | Resolver for `ref` :`sdk` or`cli` | \n| `noVerify` | boolean | `false` | Skip verifying that a `ref` or`command` resolves during provisioning | \n\nWarning\nA literal `value` is visible to anyone with read access to the file. Use a\nvault URI with `ref` or obtain the value at runtime with `command`.\n\n```\nsecrets:\n  anthropic:\n    ref: op://Private/Anthropic/api-key\n    refresh: 55m\n  github:\n    command: gh auth token\n```\n\nSecret commands execute from a fresh temporary directory on the host. Relative\nhelper paths resolve from that directory. Keep helpers and their dependencies\noutside writable sandbox mounts. Use an absolute path, an absolute host\n`PATH` entry, or an explicit change to the helper's private directory. See\n[dynamic secret sources](https://docs.docker.com/ai/sandboxes/configuration/credentials/#use-a-dynamic-secret-source).\n\nFor a cloud environment, set `snapshot: true` on a `ref` or `command` source:\n\n```\nsecrets:\n  github:\n    command: gh auth token\n    snapshot: true\n```\n\nThe command runs on the host after plan approval. The resolved value is stored\nas a literal secret and doesn't refresh. Recreate the environment to rotate\nit. Snapshots also work with local environments. A snapshot can't set\n`refresh` or `noVerify`. Cloud snapshots use CLI resolvers for vault references\nand don't support `backend: sdk`.\n\n### [`bindings`](#bindings)\n\n`bindings`\n`bindings` approves credential injection domains for each service. The\nenvironment merges these approvals into the user's global\n`credentials.yaml`. Each service can contain an `apiKey` block, an `oauth`\nblock, or both. Each block contains a `domains` list:\n\n```\nbindings:\n  github:\n    apiKey:\n      domains:\n        - api.github.com\n```\n\n`sbx env rm` preserves global bindings by default. Pass `--prune-bindings` to\nremove every service binding declared by the environment file.\n\nWarning\n`--prune-bindings` deletes the complete global binding entry for every\nservice declared in the environment file. This can affect other sandboxes\nthat share those service bindings.\n\n### [`registries`](#registries)\n\n`registries`\n`registries` maps registry hostnames to pull credentials. Each entry requires\n`secret` and accepts an optional `username`. Both fields accept a secret source\nwith exactly one of `value`, `ref`, or `command`.\n\nWhen `username` is omitted, `sbx` stores a token-only credential. Registries\nsuch as GHCR and GitLab accept token-only credentials.\n\n```\nregistries:\n  ghcr.io:\n    secret:\n      command: gh auth token\n```\n\n### [`mcp`](#mcp)\n\n`mcp`\nThe `mcp.servers` list registers servers with the built-in\n[MCP gateway](https://docs.docker.com/ai/sandboxes/mcp-gateway/) and adds them to the sandbox. MCP registrations\nare host-global and remain after `sbx env rm`.\n\n| Field | Type | Required | Default | Description | \n|---|---|---|---|---|\n| `name` | string | Yes | None | Server name | \n| `url` | string | No | None | Remote server URL, registry reference, or OCI reference | \n| `command` | string | No | None | Command for a local stdio server | \n| `args` | list of strings | No | None | Arguments passed to `command` | \n\nEach server must set exactly one of `url` or `command`.\n\n### [`ports`](#ports)\n\n`ports`\n`ports` publishes sandbox ports when the environment is created. Ports exposed\nby a kit but omitted from this list receive an ephemeral host port.\n\n| Field | Type | Required | Default | Description | \n|---|---|---|---|---|\n| `sandbox` | integer | Yes | None | Sandbox port from 1 through 65535 | \n| `host` | integer | No | Ephemeral | Host port from 1 through 65535 | \n| `protocol` | string | No | `tcp4` , or`tcp6` for IPv6`hostIP` | `tcp` ,`tcp4` ,`tcp6` ,`udp` ,`udp4` , or`udp6` | \n| `hostIP` | string | No | Loopback | Host interface to bind | \n\nSet `protocol: tcp` to bind both IPv4 and IPv6. Leave `hostIP` unset for a\ndual-stack binding because an explicit address binds only its own IP family.\n\nIf a port can't be published, sandbox creation fails and removes the new sandbox.", "url": "https://wpnews.pro/news/sbx-env-consistent-and-shareable-ai-sandbox-configurations", "canonical_source": "https://docs.docker.com/ai/sandboxes/configuration/environment-files", "published_at": "2026-09-28 22:28:02+00:00", "updated_at": "2026-09-28 22:47:34.453026+00:00", "lang": "en", "topics": ["ai-agents", "developer-tools", "ai-tools"], "entities": ["sbx env", "Playwright", "Chromium", "Claude", "sbx"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/sbx-env-consistent-and-shareable-ai-sandbox-configurations", "markdown": "https://wpnews.pro/news/sbx-env-consistent-and-shareable-ai-sandbox-configurations.md", "text": "https://wpnews.pro/news/sbx-env-consistent-and-shareable-ai-sandbox-configurations.txt", "jsonld": "https://wpnews.pro/news/sbx-env-consistent-and-shareable-ai-sandbox-configurations.jsonld"}}