From f4802c4e75209b74af00f2e061319e861b875e16 Mon Sep 17 00:00:00 2001 From: David Karlsson <35727626+dvdksn@users.noreply.github.com> Date: Fri, 3 Jul 2026 09:04:00 +0200 Subject: [PATCH 01/11] docs(sandboxes): add sbx env experimental section to workflows page Adds a new "Sandbox environments" section documenting the declarative `.sbxenv.yaml` configuration format and `sbx env` commands (run, create, rm). Co-Authored-By: Claude Sonnet 4.6 --- content/manuals/ai/sandboxes/workflows.md | 155 ++++++++++++++++++++++ 1 file changed, 155 insertions(+) diff --git a/content/manuals/ai/sandboxes/workflows.md b/content/manuals/ai/sandboxes/workflows.md index c84e3dafabcd..d7dd7fe41741 100644 --- a/content/manuals/ai/sandboxes/workflows.md +++ b/content/manuals/ai/sandboxes/workflows.md @@ -339,3 +339,158 @@ secrets so they're available to any sandbox the CI runner creates: $ echo "$ANTHROPIC_API_KEY" | sbx secret set -g anthropic $ echo "$GITHUB_TOKEN" | sbx secret set -g github ``` + +## Sandbox environments + +> [!NOTE] +> `sbx env` is experimental. The command interface and file format may change +> in future releases. + +A sandbox _environment file_ describes a sandbox configuration in code — +agent type, kits, workspace, secrets, ports, and resource limits. Check one +into your repository and every team member can launch an identical sandbox +with a single command, without repeating the same `sbx run` flags. Kits and +environment files compose naturally: use a shared base configuration plus +kits that install the exact tools a project needs. + +The environment file doesn't need to live next to the workspace. You can +place it anywhere and point `workspace.path` at the target directory: + +```yaml +# .sbxenv.yaml +schemaVersion: "1" +name: docs-env +agent: claude + +workspace: + path: $HOME/src/github.com/docker/docs + clone: true + +kits: + - "git+https://github.com/docker/sbx-kits-contrib.git#dir=vale" + - "git+https://github.com/docker/sbx-kits-contrib.git#dir=git-ssh-sign" + - "git+https://github.com/docker/sbx-kits-contrib.git#dir=github-ssh" + +secrets: + github: + command: gh auth token + +ports: + - sandbox: 1313 + host: 1313 +``` + +### Commands + +| Command | Description | +| -------------------------- | --------------------------------------------------------------------------------- | +| `sbx env run [PATH...]` | Provisions the environment if it doesn't exist, then opens an interactive session | +| `sbx env create [PATH...]` | Provisions without attaching; for scripts and CI | +| `sbx env rm [PATH...]` | Removes the sandbox and all secrets and registry credentials scoped to it | + +`PATH` can be a directory (reads the `.sbxenv.yaml` inside it) or a direct +path to the file. With no argument, `sbx env` reads `.sbxenv.yaml` in the +current directory. Passing multiple paths merges the files in order — see +[Multiple files](#multiple-files). + +### File reference + +All fields are optional except `schemaVersion`. + +```yaml +schemaVersion: "1" # required + +name: my-project # sandbox name; defaults to - +agent: claude # agent type + +# Workspace as a string shorthand (path only): +workspace: . + +# Workspace as an object — use when the file doesn't live next to the +# workspace, or when you want clone mode: +# workspace: +# path: /path/to/workspace +# clone: true + +additionalWorkspaces: + - path: ../shared-docs + readOnly: true + +kits: + - ./kits/my-mixin # local path + - docker.io/myorg/my-kit:1.0.0 # image reference + +env: + NODE_ENV: development # environment variables injected into the sandbox + +sandboxOptions: + memory: 8g + cpus: 4 + pullPolicy: always # always | missing | never + template: docker/sandbox-templates:claude + profile: my-governance-profile + +secrets: + anthropic: + ref: op://Private/Anthropic/api-key # vault URI (e.g. 1Password) + refresh: 55m # re-fetch interval + github: + command: gh auth token # stdout becomes the secret value + my-token: + value: "s3cr3t" # not recommended; see note below + +registries: + docker.io: + username: + command: >- + echo "https://index.docker.io/v1/" | + docker-credential-desktop get | jq -r '.Username' + secret: + command: >- + echo "https://index.docker.io/v1/" | + docker-credential-desktop get | jq -r '.Secret' + ghcr.io: + secret: + command: gh auth token + +ports: + - sandbox: 8080 + host: 3000 # map sandbox port 8080 to host port 3000 + - sandbox: 5432 + protocol: tcp # expose without a fixed host port +``` + +> [!WARNING] +> Avoid `secrets..value` for real credentials. The value is plaintext +> and visible to anyone with read access to the file. Use `ref` (vault URI) +> or `command` instead. + +### Multiple files + +`sbx env run` accepts multiple paths and deep-merges them in order. Later +files override scalar values and lists concatenate, following the same +semantics as Docker Compose's multiple `-f` files: + +```console +$ sbx env run base.sbxenv.yaml local.sbxenv.yaml +``` + +A common pattern is to commit a `base.sbxenv.yaml` with shared configuration +and add `local.sbxenv.yaml` to `.gitignore` for personal overrides — a different +workspace path, additional secrets, or adjusted resource limits. + +### Variable interpolation + +The file supports shell-style variable expansion before parsing: + +```yaml +workspace: + path: $HOME/src/myproject + +secrets: + my-token: + value: ${MY_TOKEN} # fails to parse if MY_TOKEN is unset + # value: ${MY_TOKEN:-fallback} # uses "fallback" if MY_TOKEN is unset +``` + +Use `$$` to include a literal `$`. From c5e7e8fc848c3d2d14fa352142201883f6140634 Mon Sep 17 00:00:00 2001 From: David Karlsson <35727626+dvdksn@users.noreply.github.com> Date: Fri, 3 Jul 2026 09:30:47 +0200 Subject: [PATCH 02/11] docs(sandboxes): add dedicated sandbox environment files page Moves sbx env content from workflows.md into its own page (sandbox-environments.md) with a proper per-field YAML reference. Leaves a one-line pointer in workflows.md. Co-Authored-By: Claude Sonnet 4.6 --- .../ai/sandboxes/sandbox-environments.md | 209 ++++++++++++++++++ content/manuals/ai/sandboxes/workflows.md | 154 +------------ 2 files changed, 211 insertions(+), 152 deletions(-) create mode 100644 content/manuals/ai/sandboxes/sandbox-environments.md diff --git a/content/manuals/ai/sandboxes/sandbox-environments.md b/content/manuals/ai/sandboxes/sandbox-environments.md new file mode 100644 index 000000000000..772f957f85a7 --- /dev/null +++ b/content/manuals/ai/sandboxes/sandbox-environments.md @@ -0,0 +1,209 @@ +--- +title: Sandbox environment files +linkTitle: Environment files +weight: 35 +description: Use a declarative .sbxenv.yaml file to describe and share your sandbox configuration. +keywords: + - docker sandboxes + - sbx env + - sbxenv + - environment file + - sandbox configuration + - declarative +--- + +> [!NOTE] +> `sbx env` is experimental. The command interface and file format may change +> in future releases. + +A sandbox environment file (`.sbxenv.yaml`) describes a sandbox in code: +the agent, kits, workspace, secrets, ports, and resource limits. Commit one +alongside your project and every team member runs an identical sandbox with a +single command, without sharing flag combinations or setup instructions. + +The environment file doesn't need to live in the same directory as the +workspace. You can place it anywhere and point `workspace.path` at the target +directory: + +```yaml +# .sbxenv.yaml +schemaVersion: "1" +name: docs-env +agent: claude + +workspace: + path: $HOME/src/github.com/docker/docs + clone: true + +kits: + - "git+https://github.com/docker/sbx-kits-contrib.git#dir=vale" + - "git+https://github.com/docker/sbx-kits-contrib.git#dir=git-ssh-sign" + - "git+https://github.com/docker/sbx-kits-contrib.git#dir=github-ssh" + +secrets: + github: + command: gh auth token + +ports: + - sandbox: 1313 + host: 1313 +``` + +## Commands + +| Command | Description | +| -------------------------- | --------------------------------------------------------------------------------- | +| `sbx env run [PATH...]` | Provisions the environment if it doesn't exist, then opens an interactive session | +| `sbx env create [PATH...]` | Provisions without attaching; use in scripts and CI | +| `sbx env rm [PATH...]` | Removes the sandbox and all resources provisioned by the environment | + +`PATH` can be a directory (reads the `.sbxenv.yaml` inside it) or a direct +path to a file. With no argument, `sbx env` reads `.sbxenv.yaml` in the +current directory. + +Passing multiple paths merges the files in order — see +[Multiple files](#multiple-files). + +`sbx env rm` removes all secrets and registry credentials that were +provisioned when the environment was created, not just the sandbox container. + +## Multiple files + +`sbx env run` and `sbx env create` accept multiple paths and deep-merge them +in order. Later files override scalar values; lists concatenate. This follows +the same semantics as Docker Compose's multiple `-f` files: + +```console +$ sbx env run base.sbxenv.yaml local.sbxenv.yaml +``` + +A common pattern is to commit a `base.sbxenv.yaml` with shared team +configuration and add `local.sbxenv.yaml` to `.gitignore` for personal +overrides — a different workspace path, additional secrets, or adjusted +resource limits. + +## Variable interpolation + +Host environment variables are expanded before the file is parsed: + +| Syntax | Behavior | +| ------------------ | ----------------------------------------------- | +| `$VAR` or `${VAR}` | Expands to the value of `VAR`; fails if unset | +| `${VAR:-default}` | Uses `default` if `VAR` is unset or empty | +| `${VAR:?message}` | Fails with `message` if `VAR` is unset or empty | +| `$$` | Literal `$` | + +```yaml +workspace: + path: $HOME/src/myproject + +secrets: + my-token: + value: ${MY_TOKEN:?MY_TOKEN must be set} +``` + +## File reference + +### Top-level fields + +| Field | Type | Required | Default | Description | +| ---------------------- | ---------------- | -------- | ------------------------------ | ------------------------------------------------------------------------------- | +| `schemaVersion` | string | Yes | — | Schema version. Currently `"1"` | +| `name` | string | No | `-` | Sandbox name | +| `agent` | string | No | — | Agent type, e.g. `claude` | +| `workspace` | string or object | No | `.` | Workspace path or configuration; see [`workspace`](#workspace) | +| `additionalWorkspaces` | list | No | — | Extra directories to mount; see [`additionalWorkspaces`](#additionalworkspaces) | +| `kits` | list of strings | No | — | Kit references to install at sandbox creation | +| `env` | map | No | — | Environment variables to inject into the sandbox | +| `sandboxOptions` | object | No | — | Resource and image-pull settings; see [`sandboxOptions`](#sandboxoptions) | +| `secrets` | map | No | — | Service credentials; see [`secrets`](#secrets) | +| `registries` | map | No | — | Registry pull credentials; see [`registries`](#registries) | +| `ports` | list | No | — | Port mappings; see [`ports`](#ports) | + +### `workspace` + +When specified as a string, `workspace` is treated as the path. Use the +object form to enable clone mode or when the file doesn't live next to the +workspace: + +| Field | Type | Default | Description | +| ------- | ------- | ------- | ----------------------------------------------------------------------- | +| `path` | string | `.` | Path to the workspace directory | +| `clone` | boolean | `false` | Mount the workspace as a private clone, equivalent to `sbx run --clone` | + +### `additionalWorkspaces` + +A list of extra directories to mount alongside the primary workspace: + +| Field | Type | Required | Description | +| ---------- | ------- | -------- | ----------------------------- | +| `path` | string | Yes | Path to the directory | +| `readOnly` | boolean | No | Mount the directory read-only | + +### `sandboxOptions` + +| Field | Type | Default | Description | +| ------------ | ------ | --------- | --------------------------------------------------------------- | +| `memory` | string | — | Memory limit, e.g. `8g`, `512m` | +| `cpus` | number | — | CPU limit | +| `pullPolicy` | string | `missing` | When to pull the sandbox image: `always`, `missing`, or `never` | +| `template` | string | — | Custom sandbox template image | +| `profile` | string | — | Governance profile name | + +### `secrets` + +A map of secret names to secret sources. Each secret is provisioned when the +environment is created, scoped to the sandbox. `sbx env rm` removes all +secrets in this map. + +| Field | Description | +| --------- | ------------------------------------------------------------------------------------------------ | +| `ref` | A vault URI, e.g. `op://Vault/Item/field` (1Password). Resolved from the vault at creation time. | +| `command` | A shell command whose stdout becomes the secret value. | +| `value` | A plaintext secret value. | +| `refresh` | Re-fetch interval for `ref`-based secrets, e.g. `55m`. | + +> [!WARNING] +> Avoid `value` for real credentials — the plaintext is visible to anyone +> with read access to the file. Use `ref` or `command` instead. + +```yaml +secrets: + anthropic: + ref: op://Private/Anthropic/api-key + refresh: 55m + github: + command: gh auth token +``` + +### `registries` + +A map of registry hostnames to pull credentials. Each entry has `username` +and `secret` fields. Both accept the same secret source fields as +[`secrets`](#secrets) (`ref`, `command`, or `value`). + +```yaml +registries: + ghcr.io: + secret: + command: gh auth token + docker.io: + username: + command: >- + echo "https://index.docker.io/v1/" | + docker-credential-desktop get | jq -r '.Username' + secret: + command: >- + echo "https://index.docker.io/v1/" | + docker-credential-desktop get | jq -r '.Secret' +``` + +### `ports` + +A list of port mappings between the sandbox and the host: + +| Field | Type | Required | Default | Description | +| ---------- | ------- | -------- | ------- | ------------------------------------------------------------------ | +| `sandbox` | integer | Yes | — | Port number inside the sandbox | +| `host` | integer | No | — | Port number on the host. Omit to expose without a fixed host port. | +| `protocol` | string | No | `tcp` | Protocol: `tcp` or `udp` | diff --git a/content/manuals/ai/sandboxes/workflows.md b/content/manuals/ai/sandboxes/workflows.md index d7dd7fe41741..c82013276e7b 100644 --- a/content/manuals/ai/sandboxes/workflows.md +++ b/content/manuals/ai/sandboxes/workflows.md @@ -342,155 +342,5 @@ $ echo "$GITHUB_TOKEN" | sbx secret set -g github ## Sandbox environments -> [!NOTE] -> `sbx env` is experimental. The command interface and file format may change -> in future releases. - -A sandbox _environment file_ describes a sandbox configuration in code — -agent type, kits, workspace, secrets, ports, and resource limits. Check one -into your repository and every team member can launch an identical sandbox -with a single command, without repeating the same `sbx run` flags. Kits and -environment files compose naturally: use a shared base configuration plus -kits that install the exact tools a project needs. - -The environment file doesn't need to live next to the workspace. You can -place it anywhere and point `workspace.path` at the target directory: - -```yaml -# .sbxenv.yaml -schemaVersion: "1" -name: docs-env -agent: claude - -workspace: - path: $HOME/src/github.com/docker/docs - clone: true - -kits: - - "git+https://github.com/docker/sbx-kits-contrib.git#dir=vale" - - "git+https://github.com/docker/sbx-kits-contrib.git#dir=git-ssh-sign" - - "git+https://github.com/docker/sbx-kits-contrib.git#dir=github-ssh" - -secrets: - github: - command: gh auth token - -ports: - - sandbox: 1313 - host: 1313 -``` - -### Commands - -| Command | Description | -| -------------------------- | --------------------------------------------------------------------------------- | -| `sbx env run [PATH...]` | Provisions the environment if it doesn't exist, then opens an interactive session | -| `sbx env create [PATH...]` | Provisions without attaching; for scripts and CI | -| `sbx env rm [PATH...]` | Removes the sandbox and all secrets and registry credentials scoped to it | - -`PATH` can be a directory (reads the `.sbxenv.yaml` inside it) or a direct -path to the file. With no argument, `sbx env` reads `.sbxenv.yaml` in the -current directory. Passing multiple paths merges the files in order — see -[Multiple files](#multiple-files). - -### File reference - -All fields are optional except `schemaVersion`. - -```yaml -schemaVersion: "1" # required - -name: my-project # sandbox name; defaults to - -agent: claude # agent type - -# Workspace as a string shorthand (path only): -workspace: . - -# Workspace as an object — use when the file doesn't live next to the -# workspace, or when you want clone mode: -# workspace: -# path: /path/to/workspace -# clone: true - -additionalWorkspaces: - - path: ../shared-docs - readOnly: true - -kits: - - ./kits/my-mixin # local path - - docker.io/myorg/my-kit:1.0.0 # image reference - -env: - NODE_ENV: development # environment variables injected into the sandbox - -sandboxOptions: - memory: 8g - cpus: 4 - pullPolicy: always # always | missing | never - template: docker/sandbox-templates:claude - profile: my-governance-profile - -secrets: - anthropic: - ref: op://Private/Anthropic/api-key # vault URI (e.g. 1Password) - refresh: 55m # re-fetch interval - github: - command: gh auth token # stdout becomes the secret value - my-token: - value: "s3cr3t" # not recommended; see note below - -registries: - docker.io: - username: - command: >- - echo "https://index.docker.io/v1/" | - docker-credential-desktop get | jq -r '.Username' - secret: - command: >- - echo "https://index.docker.io/v1/" | - docker-credential-desktop get | jq -r '.Secret' - ghcr.io: - secret: - command: gh auth token - -ports: - - sandbox: 8080 - host: 3000 # map sandbox port 8080 to host port 3000 - - sandbox: 5432 - protocol: tcp # expose without a fixed host port -``` - -> [!WARNING] -> Avoid `secrets..value` for real credentials. The value is plaintext -> and visible to anyone with read access to the file. Use `ref` (vault URI) -> or `command` instead. - -### Multiple files - -`sbx env run` accepts multiple paths and deep-merges them in order. Later -files override scalar values and lists concatenate, following the same -semantics as Docker Compose's multiple `-f` files: - -```console -$ sbx env run base.sbxenv.yaml local.sbxenv.yaml -``` - -A common pattern is to commit a `base.sbxenv.yaml` with shared configuration -and add `local.sbxenv.yaml` to `.gitignore` for personal overrides — a different -workspace path, additional secrets, or adjusted resource limits. - -### Variable interpolation - -The file supports shell-style variable expansion before parsing: - -```yaml -workspace: - path: $HOME/src/myproject - -secrets: - my-token: - value: ${MY_TOKEN} # fails to parse if MY_TOKEN is unset - # value: ${MY_TOKEN:-fallback} # uses "fallback" if MY_TOKEN is unset -``` - -Use `$$` to include a literal `$`. +For a declarative alternative to `sbx run` flags, see +[Sandbox environment files](sandbox-environments.md). From d4bce813501b8a96ca96a29b484cfced01804efc Mon Sep 17 00:00:00 2001 From: David Karlsson <35727626+dvdksn@users.noreply.github.com> Date: Fri, 3 Jul 2026 09:33:10 +0200 Subject: [PATCH 03/11] docs(sandboxes): fix schema accuracy from source code review - agent: mark as required (Validate() enforces non-empty) - pullPolicy: correct default to "always" (pullPolicyOrDefault helper) - registries: clarify secret required, username optional; note token-only support Co-Authored-By: Claude Sonnet 4.6 --- .../ai/sandboxes/sandbox-environments.md | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/content/manuals/ai/sandboxes/sandbox-environments.md b/content/manuals/ai/sandboxes/sandbox-environments.md index 772f957f85a7..a7c255a2cb1c 100644 --- a/content/manuals/ai/sandboxes/sandbox-environments.md +++ b/content/manuals/ai/sandboxes/sandbox-environments.md @@ -110,7 +110,7 @@ secrets: | ---------------------- | ---------------- | -------- | ------------------------------ | ------------------------------------------------------------------------------- | | `schemaVersion` | string | Yes | — | Schema version. Currently `"1"` | | `name` | string | No | `-` | Sandbox name | -| `agent` | string | No | — | Agent type, e.g. `claude` | +| `agent` | string | Yes | — | Agent type, e.g. `claude` | | `workspace` | string or object | No | `.` | Workspace path or configuration; see [`workspace`](#workspace) | | `additionalWorkspaces` | list | No | — | Extra directories to mount; see [`additionalWorkspaces`](#additionalworkspaces) | | `kits` | list of strings | No | — | Kit references to install at sandbox creation | @@ -142,13 +142,13 @@ A list of extra directories to mount alongside the primary workspace: ### `sandboxOptions` -| Field | Type | Default | Description | -| ------------ | ------ | --------- | --------------------------------------------------------------- | -| `memory` | string | — | Memory limit, e.g. `8g`, `512m` | -| `cpus` | number | — | CPU limit | -| `pullPolicy` | string | `missing` | When to pull the sandbox image: `always`, `missing`, or `never` | -| `template` | string | — | Custom sandbox template image | -| `profile` | string | — | Governance profile name | +| Field | Type | Default | Description | +| ------------ | ------ | -------- | --------------------------------------------------------------- | +| `memory` | string | — | Memory limit, e.g. `8g`, `512m` | +| `cpus` | number | — | CPU limit | +| `pullPolicy` | string | `always` | When to pull the sandbox image: `always`, `missing`, or `never` | +| `template` | string | — | Custom sandbox template image | +| `profile` | string | — | Governance profile name | ### `secrets` @@ -178,9 +178,11 @@ secrets: ### `registries` -A map of registry hostnames to pull credentials. Each entry has `username` -and `secret` fields. Both accept the same secret source fields as -[`secrets`](#secrets) (`ref`, `command`, or `value`). +A map of registry hostnames to pull credentials. Each entry requires +`secret` and accepts an optional `username`. Both fields use the same secret +source forms as [`secrets`](#secrets) (`ref`, `command`, or `value`). +Omitting `username` stores the credential as token-only, which registries +like GHCR and GitLab accept. ```yaml registries: From e40a32b29ccd873bf129bf7bebf559d93b0410b5 Mon Sep 17 00:00:00 2001 From: David Karlsson <35727626+dvdksn@users.noreply.github.com> Date: Fri, 3 Jul 2026 09:42:38 +0200 Subject: [PATCH 04/11] docs(sandboxes): polish sandbox-environments page - Remove undocumented docker-credential-desktop registry example - Improve plaintext secret warning to suggest variable interpolation - Remove prose em dashes Co-Authored-By: Claude Sonnet 4.6 --- .../ai/sandboxes/sandbox-environments.md | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/content/manuals/ai/sandboxes/sandbox-environments.md b/content/manuals/ai/sandboxes/sandbox-environments.md index a7c255a2cb1c..62cd4491dfdf 100644 --- a/content/manuals/ai/sandboxes/sandbox-environments.md +++ b/content/manuals/ai/sandboxes/sandbox-environments.md @@ -79,7 +79,7 @@ $ sbx env run base.sbxenv.yaml local.sbxenv.yaml A common pattern is to commit a `base.sbxenv.yaml` with shared team configuration and add `local.sbxenv.yaml` to `.gitignore` for personal -overrides — a different workspace path, additional secrets, or adjusted +overrides: a different workspace path, additional secrets, or adjusted resource limits. ## Variable interpolation @@ -164,8 +164,10 @@ secrets in this map. | `refresh` | Re-fetch interval for `ref`-based secrets, e.g. `55m`. | > [!WARNING] -> Avoid `value` for real credentials — the plaintext is visible to anyone -> with read access to the file. Use `ref` or `command` instead. +> Avoid setting real credentials as a plaintext `value`. The plaintext is visible to +> anyone with read access to the file. Use `ref` (vault URI) or `command` +> to source the value at runtime, or use variable interpolation to read it +> from the environment: `value: ${MY_TOKEN}`. ```yaml secrets: @@ -189,15 +191,6 @@ registries: ghcr.io: secret: command: gh auth token - docker.io: - username: - command: >- - echo "https://index.docker.io/v1/" | - docker-credential-desktop get | jq -r '.Username' - secret: - command: >- - echo "https://index.docker.io/v1/" | - docker-credential-desktop get | jq -r '.Secret' ``` ### `ports` From 20dde9e0b5ee1a41bc3ae18001ff5192cbec89ff Mon Sep 17 00:00:00 2001 From: David Karlsson <35727626+dvdksn@users.noreply.github.com> Date: Fri, 3 Jul 2026 09:56:34 +0200 Subject: [PATCH 05/11] docs(sandboxes): add Experimental sidebar badge to sandbox-environments page Co-Authored-By: Claude Sonnet 4.6 --- content/manuals/ai/sandboxes/sandbox-environments.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/content/manuals/ai/sandboxes/sandbox-environments.md b/content/manuals/ai/sandboxes/sandbox-environments.md index 62cd4491dfdf..a43fe41907d4 100644 --- a/content/manuals/ai/sandboxes/sandbox-environments.md +++ b/content/manuals/ai/sandboxes/sandbox-environments.md @@ -10,6 +10,11 @@ keywords: - environment file - sandbox configuration - declarative +params: + sidebar: + badge: + color: violet + text: Experimental --- > [!NOTE] From 899edf42370186a5047df9b3443860cd633e0945 Mon Sep 17 00:00:00 2001 From: David Karlsson <35727626+dvdksn@users.noreply.github.com> Date: Tue, 11 Aug 2026 08:35:39 +0000 Subject: [PATCH 06/11] docs: align sandbox environment reference with v0.39 The draft reference omitted supported commands and schema fields and misstated interpolation and cleanup behavior. Update it against docker/sandboxes release/v0.39 and resolve the workflows conflict with current main.\n\nCo-Authored-By: Codex --- .../ai/sandboxes/sandbox-environments.md | 245 +++++++++++------- 1 file changed, 158 insertions(+), 87 deletions(-) diff --git a/content/manuals/ai/sandboxes/sandbox-environments.md b/content/manuals/ai/sandboxes/sandbox-environments.md index a43fe41907d4..a1b14257dbc2 100644 --- a/content/manuals/ai/sandboxes/sandbox-environments.md +++ b/content/manuals/ai/sandboxes/sandbox-environments.md @@ -21,14 +21,13 @@ params: > `sbx env` is experimental. The command interface and file format may change > in future releases. -A sandbox environment file (`.sbxenv.yaml`) describes a sandbox in code: -the agent, kits, workspace, secrets, ports, and resource limits. Commit one -alongside your project and every team member runs an identical sandbox with a -single command, without sharing flag combinations or setup instructions. +A sandbox environment file describes the agent, kits, workspaces, environment +variables, credentials, MCP servers, ports, and resource limits for a sandbox. +Commit the file with your project so team members can run the same sandbox +configuration without sharing flag combinations or setup instructions. -The environment file doesn't need to live in the same directory as the -workspace. You can place it anywhere and point `workspace.path` at the target -directory: +The environment file doesn't need to be in the workspace. You can store it in +another directory and set `workspace.path` to the workspace: ```yaml # .sbxenv.yaml @@ -56,51 +55,75 @@ ports: ## Commands -| Command | Description | -| -------------------------- | --------------------------------------------------------------------------------- | -| `sbx env run [PATH...]` | Provisions the environment if it doesn't exist, then opens an interactive session | -| `sbx env create [PATH...]` | Provisions without attaching; use in scripts and CI | -| `sbx env rm [PATH...]` | Removes the sandbox and all resources provisioned by the environment | +| Command | Description | +| ----------------------------------------------- | ----------------------------------------------------------------------------------------- | +| `sbx env run [PATH...]` | Creates the environment if needed, then attaches to it | +| `sbx env create [PATH...]` | Creates the environment without attaching | +| `sbx env exec [PATH...] -- COMMAND [ARG...]` | Runs a command in an existing environment | +| `sbx env rm [PATH...]` | Removes the sandbox and credentials scoped to it | -`PATH` can be a directory (reads the `.sbxenv.yaml` inside it) or a direct -path to a file. With no argument, `sbx env` reads `.sbxenv.yaml` in the -current directory. +`PATH` can be a directory or a direct path to an environment file. When you +pass a directory, `sbx` reads `.sbxenv.yaml` and falls back to `.sbxenv.yml`. +With no path, `sbx` searches the working directory. -Passing multiple paths merges the files in order — see -[Multiple files](#multiple-files). +Pass the same set of paths to each lifecycle command so they resolve the same +sandbox. See [Multiple files](#multiple-files) for details. -`sbx env rm` removes all secrets and registry credentials that were -provisioned when the environment was created, not just the sandbox container. +`sbx env run` starts and attaches to an existing sandbox without provisioning +its secrets and bindings again. The command applies changes to `env` to the new +session and reconciles declared MCP servers. + +For `sbx env exec`, arguments before `--` are environment-file paths and +arguments after `--` form the command. Without `--`, all arguments form the +command and `sbx` reads the environment file from the working directory: + +```console +$ sbx env exec .sbxenv.yaml -- go test ./... +$ sbx env exec go test ./... +``` + +`sbx env rm` removes the sandbox and its scoped service and registry +credentials. Global credential bindings remain unless you pass +`--prune-bindings`. Host-global MCP registrations remain available to other +sandboxes. ## Multiple files -`sbx env run` and `sbx env create` accept multiple paths and deep-merge them -in order. Later files override scalar values; lists concatenate. This follows -the same semantics as Docker Compose's multiple `-f` files: +Pass multiple paths to merge environment files in order. Nested mappings merge +by key, lists concatenate, and values from later files replace earlier scalar +values. Relative workspace paths and the default sandbox name use the directory +of the first file. ```console $ sbx env run base.sbxenv.yaml local.sbxenv.yaml ``` -A common pattern is to commit a `base.sbxenv.yaml` with shared team -configuration and add `local.sbxenv.yaml` to `.gitignore` for personal -overrides: a different workspace path, additional secrets, or adjusted -resource limits. +Commit a `base.sbxenv.yaml` with shared configuration and add +`local.sbxenv.yaml` to `.gitignore` for personal overrides, such as another +workspace path, additional secrets, or different resource limits. ## Variable interpolation -Host environment variables are expanded before the file is parsed: +Host environment variables are expanded in each file before the files are +merged and parsed: + +| Syntax | Behavior | +| ------------------------ | ----------------------------------------------------------- | +| `$VAR` or `${VAR}` | Uses the value of `VAR`, or an empty string when unset | +| `${VAR:-default}` | Uses `default` when `VAR` is unset or empty | +| `${VAR-default}` | Uses `default` when `VAR` is unset | +| `${VAR:+replacement}` | Uses `replacement` when `VAR` is set and non-empty | +| `${VAR+replacement}` | Uses `replacement` when `VAR` is set | +| `${VAR:?message}` | Fails with `message` when `VAR` is unset or empty | +| `${VAR?message}` | Fails with `message` when `VAR` is unset | +| `$$` | Inserts a literal `$` | -| Syntax | Behavior | -| ------------------ | ----------------------------------------------- | -| `$VAR` or `${VAR}` | Expands to the value of `VAR`; fails if unset | -| `${VAR:-default}` | Uses `default` if `VAR` is unset or empty | -| `${VAR:?message}` | Fails with `message` if `VAR` is unset or empty | -| `$$` | Literal `$` | +Default, replacement, and error values can contain nested variable +expressions. ```yaml workspace: - path: $HOME/src/myproject + path: ${WORKSPACE:-$HOME/src/myproject} secrets: my-token: @@ -109,70 +132,78 @@ secrets: ## File reference +The loader rejects unknown fields and unsupported schema versions. + ### Top-level fields | Field | Type | Required | Default | Description | | ---------------------- | ---------------- | -------- | ------------------------------ | ------------------------------------------------------------------------------- | -| `schemaVersion` | string | Yes | — | Schema version. Currently `"1"` | +| `schemaVersion` | string | Yes | None | Schema version. The supported value is `"1"` | | `name` | string | No | `-` | Sandbox name | -| `agent` | string | Yes | — | Agent type, e.g. `claude` | -| `workspace` | string or object | No | `.` | Workspace path or configuration; see [`workspace`](#workspace) | -| `additionalWorkspaces` | list | No | — | Extra directories to mount; see [`additionalWorkspaces`](#additionalworkspaces) | -| `kits` | list of strings | No | — | Kit references to install at sandbox creation | -| `env` | map | No | — | Environment variables to inject into the sandbox | -| `sandboxOptions` | object | No | — | Resource and image-pull settings; see [`sandboxOptions`](#sandboxoptions) | -| `secrets` | map | No | — | Service credentials; see [`secrets`](#secrets) | -| `registries` | map | No | — | Registry pull credentials; see [`registries`](#registries) | -| `ports` | list | No | — | Port mappings; see [`ports`](#ports) | +| `agent` | string | Yes | None | Built-in agent or the name of an agent kit | +| `kits` | list of strings | No | None | Directory, ZIP, or OCI kit references to install at creation | +| `workspace` | string or object | No | First file's directory | Primary workspace. See [`workspace`](#workspace) | +| `additionalWorkspaces` | list | No | None | Extra directories to mount. See [`additionalWorkspaces`](#additionalworkspaces) | +| `env` | map of strings | No | None | Environment variables for the sandbox | +| `sandboxOptions` | object | No | None | Creation options. See [`sandboxOptions`](#sandboxoptions) | +| `secrets` | map | No | None | Service credentials. See [`secrets`](#secrets) | +| `bindings` | map | No | None | Credential injection approvals. See [`bindings`](#bindings) | +| `registries` | map | No | None | Registry pull credentials. See [`registries`](#registries) | +| `mcp` | object | No | None | MCP servers. See [`mcp`](#mcp) | +| `ports` | list | No | None | Port mappings. See [`ports`](#ports) | ### `workspace` -When specified as a string, `workspace` is treated as the path. Use the -object form to enable clone mode or when the file doesn't live next to the -workspace: +When specified as a string, `workspace` is the path. Use the object form for +clone mode: + +| Field | Type | Default | Description | +| ------- | ------- | ---------------------- | ----------------------------------------------------------------------- | +| `path` | string | First file's directory | Workspace directory. Relative paths resolve from the first file | +| `clone` | boolean | `false` | Use a private clone, equivalent to `sbx create --clone` | -| Field | Type | Default | Description | -| ------- | ------- | ------- | ----------------------------------------------------------------------- | -| `path` | string | `.` | Path to the workspace directory | -| `clone` | boolean | `false` | Mount the workspace as a private clone, equivalent to `sbx run --clone` | +You can override `workspace.clone` for one `create` or `run` invocation with +`--clone` or `--clone=false`. ### `additionalWorkspaces` -A list of extra directories to mount alongside the primary workspace: +Each additional workspace is mounted after the primary workspace. Relative +paths resolve from the directory of the first environment file. -| Field | Type | Required | Description | -| ---------- | ------- | -------- | ----------------------------- | -| `path` | string | Yes | Path to the directory | -| `readOnly` | boolean | No | Mount the directory read-only | +| Field | Type | Required | Default | Description | +| ---------- | ------- | -------- | ------- | ----------------------------- | +| `path` | string | Yes | None | Directory to mount | +| `readOnly` | boolean | No | `false` | Mount the directory read-only | ### `sandboxOptions` -| Field | Type | Default | Description | -| ------------ | ------ | -------- | --------------------------------------------------------------- | -| `memory` | string | — | Memory limit, e.g. `8g`, `512m` | -| `cpus` | number | — | CPU limit | -| `pullPolicy` | string | `always` | When to pull the sandbox image: `always`, `missing`, or `never` | -| `template` | string | — | Custom sandbox template image | -| `profile` | string | — | Governance profile name | +| Field | Type | Default | Description | +| ------------ | ------- | -------- | --------------------------------------------------------------- | +| `template` | string | None | Custom sandbox template image | +| `memory` | string | None | Memory limit, such as `8g` or `512m` | +| `cpus` | integer | `0` | CPU limit. `0` selects the automatic value | +| `pullPolicy` | string | `always` | Image pull policy: `always`, `missing`, or `never` | +| `profile` | string | None | Governance profile name | ### `secrets` -A map of secret names to secret sources. Each secret is provisioned when the -environment is created, scoped to the sandbox. `sbx env rm` removes all -secrets in this map. +`secrets` maps service names to secret sources. Each entry must set exactly one +of `value`, `ref`, or `command`. The secret is stored at the sandbox scope when +the environment is created. -| Field | Description | -| --------- | ------------------------------------------------------------------------------------------------ | -| `ref` | A vault URI, e.g. `op://Vault/Item/field` (1Password). Resolved from the vault at creation time. | -| `command` | A shell command whose stdout becomes the secret value. | -| `value` | A plaintext secret value. | -| `refresh` | Re-fetch interval for `ref`-based secrets, e.g. `55m`. | +| Field | Type | Default | Description | +| ---------- | ------- | ------- | ---------------------------------------------------------------------------- | +| `value` | string | None | Literal secret value | +| `ref` | string | None | Vault URI, such as `op://Vault/Item/field` | +| `command` | string | None | Host shell command whose standard output becomes the secret | +| `refresh` | string | None | Resolution policy for `ref` or `command`, such as `on-demand` or `55m` | +| `backend` | string | Automatic | Resolver for `ref`: `sdk` or `cli` | +| `noVerify` | boolean | `false` | Skip resolving a `ref` or `command` once when provisioning the secret | > [!WARNING] -> Avoid setting real credentials as a plaintext `value`. The plaintext is visible to -> anyone with read access to the file. Use `ref` (vault URI) or `command` -> to source the value at runtime, or use variable interpolation to read it -> from the environment: `value: ${MY_TOKEN}`. +> A literal `value` is visible to anyone with read access to the file. Use a +> vault URI with `ref`, obtain the value at runtime with `command`, or use +> variable interpolation such as `value: ${MY_TOKEN}`. ```yaml secrets: @@ -183,13 +214,32 @@ secrets: command: gh auth token ``` +### `bindings` + +`bindings` approves credential injection domains for each service. The +environment merges these approvals into the user's global +`credentials.yaml`. Each service can contain an `apiKey` block, an `oauth` +block, or both. Each block contains a `domains` list: + +```yaml +bindings: + github: + apiKey: + domains: + - api.github.com +``` + +`sbx env rm` preserves global bindings by default. Pass `--prune-bindings` to +remove every service binding declared by the environment file. + ### `registries` -A map of registry hostnames to pull credentials. Each entry requires -`secret` and accepts an optional `username`. Both fields use the same secret -source forms as [`secrets`](#secrets) (`ref`, `command`, or `value`). -Omitting `username` stores the credential as token-only, which registries -like GHCR and GitLab accept. +`registries` maps registry hostnames to pull credentials. Each entry requires +`secret` and accepts an optional `username`. Both fields accept a secret source +with exactly one of `value`, `ref`, or `command`. + +When `username` is omitted, `sbx` stores a token-only credential. Registries +such as GHCR and GitLab accept token-only credentials. ```yaml registries: @@ -198,12 +248,33 @@ registries: command: gh auth token ``` +### `mcp` + +The `mcp.servers` list registers MCP servers on the host and adds them to the +sandbox. This field requires the hosted MCP control plane through +`SBX_MCP_URL`. MCP registrations are host-global and remain after +`sbx env rm`. + +| Field | Type | Required | Default | Description | +| --------- | --------------- | -------- | ------- | --------------------------------------------------------------- | +| `name` | string | Yes | None | Server name | +| `url` | string | No | None | Remote server URL, registry reference, or OCI reference | +| `command` | string | No | None | Command for a local stdio server | +| `args` | list of strings | No | None | Arguments passed to `command` | + +Each server must set exactly one of `url` or `command`. + ### `ports` -A list of port mappings between the sandbox and the host: +`ports` publishes sandbox ports when the environment is created. Ports exposed +by a kit but omitted from this list receive an ephemeral host port. + +| Field | Type | Required | Default | Description | +| ---------- | ------- | -------- | ---------------- | --------------------------------------------------------------------- | +| `sandbox` | integer | Yes | None | Sandbox port from 1 through 65535 | +| `host` | integer | No | Ephemeral | Host port from 1 through 65535 | +| `protocol` | string | No | `tcp` | `tcp`, `tcp4`, `tcp6`, `udp`, `udp4`, or `udp6` | +| `hostIP` | string | No | Loopback | Host interface. The default uses available IPv4 and IPv6 loopback | -| Field | Type | Required | Default | Description | -| ---------- | ------- | -------- | ------- | ------------------------------------------------------------------ | -| `sandbox` | integer | Yes | — | Port number inside the sandbox | -| `host` | integer | No | — | Port number on the host. Omit to expose without a fixed host port. | -| `protocol` | string | No | `tcp` | Protocol: `tcp` or `udp` | +If a port can't be published, sandbox creation fails and removes the new +sandbox. From f1f14b2693a6b39da3efeb90617f4f4b581f1494 Mon Sep 17 00:00:00 2001 From: David Karlsson <35727626+dvdksn@users.noreply.github.com> Date: Tue, 11 Aug 2026 09:34:22 +0000 Subject: [PATCH 07/11] sandboxes: prepare environment docs for v0.39 Clarify the lifecycle, cleanup, MCP, and local-only behavior of declarative sandbox environments. Vendor the generated v0.39 sbx env CLI reference and link the guide to it. Signed-off-by: David Karlsson <35727626+dvdksn@users.noreply.github.com> --- .../ai/sandboxes/sandbox-environments.md | 42 ++++++++---- data/sbx_cli/sbx_env.yaml | 28 ++++++++ data/sbx_cli/sbx_env_create.yaml | 30 ++++++++ data/sbx_cli/sbx_env_exec.yaml | 68 +++++++++++++++++++ data/sbx_cli/sbx_env_rm.yaml | 35 ++++++++++ data/sbx_cli/sbx_env_run.yaml | 35 ++++++++++ 6 files changed, 224 insertions(+), 14 deletions(-) create mode 100644 data/sbx_cli/sbx_env.yaml create mode 100644 data/sbx_cli/sbx_env_create.yaml create mode 100644 data/sbx_cli/sbx_env_exec.yaml create mode 100644 data/sbx_cli/sbx_env_rm.yaml create mode 100644 data/sbx_cli/sbx_env_run.yaml diff --git a/content/manuals/ai/sandboxes/sandbox-environments.md b/content/manuals/ai/sandboxes/sandbox-environments.md index a1b14257dbc2..5fb0dbb5ae78 100644 --- a/content/manuals/ai/sandboxes/sandbox-environments.md +++ b/content/manuals/ai/sandboxes/sandbox-environments.md @@ -18,8 +18,9 @@ params: --- > [!NOTE] -> `sbx env` is experimental. The command interface and file format may change -> in future releases. +> `sbx env` requires `sbx` 0.39.0 or later and supports local sandboxes only. +> The feature is experimental, so the command interface and file format may +> change in future releases. A sandbox environment file describes the agent, kits, workspaces, environment variables, credentials, MCP servers, ports, and resource limits for a sandbox. @@ -55,12 +56,12 @@ ports: ## Commands -| Command | Description | -| ----------------------------------------------- | ----------------------------------------------------------------------------------------- | -| `sbx env run [PATH...]` | Creates the environment if needed, then attaches to it | -| `sbx env create [PATH...]` | Creates the environment without attaching | -| `sbx env exec [PATH...] -- COMMAND [ARG...]` | Runs a command in an existing environment | -| `sbx env rm [PATH...]` | Removes the sandbox and credentials scoped to it | +| Command | Description | +| --------------------------------------------------------------------------------------- | ------------------------------------------------ | +| [`sbx env run`](/reference/cli/sbx/env/run/) `[PATH...]` | Creates the environment if needed, then attaches | +| [`sbx env create`](/reference/cli/sbx/env/create/) `[PATH...]` | Creates the environment without attaching | +| [`sbx env exec`](/reference/cli/sbx/env/exec/) `[PATH...] -- COMMAND [ARG...]` | Runs a command in an existing environment | +| [`sbx env rm`](/reference/cli/sbx/env/rm/) `[PATH...]` | Removes the sandbox and its scoped credentials | `PATH` can be a directory or a direct path to an environment file. When you pass a directory, `sbx` reads `.sbxenv.yaml` and falls back to `.sbxenv.yml`. @@ -70,8 +71,10 @@ Pass the same set of paths to each lifecycle command so they resolve the same sandbox. See [Multiple files](#multiple-files) for details. `sbx env run` starts and attaches to an existing sandbox without provisioning -its secrets and bindings again. The command applies changes to `env` to the new -session and reconciles declared MCP servers. +its secrets and bindings again. For an existing sandbox, the command applies +changes to `env` to the new session and reconciles declared MCP servers. Changes +to workspaces, kits, ports, secrets, bindings, and `sandboxOptions` require you +to remove the environment with `sbx env rm` and create it again. For `sbx env exec`, arguments before `--` are environment-file paths and arguments after `--` form the command. Without `--`, all arguments form the @@ -87,6 +90,13 @@ credentials. Global credential bindings remain unless you pass `--prune-bindings`. Host-global MCP registrations remain available to other sandboxes. +Secret provisioning, binding updates, and MCP server registration occur before +the sandbox is created. If sandbox creation fails, scoped secrets remain, and +bindings and MCP registrations may also remain. Run `sbx env rm` with the same +paths to remove the scoped secrets. Pass `--prune-bindings` if you also want to +remove the declared global bindings. MCP registrations are host-global and +remain after cleanup. + ## Multiple files Pass multiple paths to merge environment files in order. Nested mappings merge @@ -232,6 +242,11 @@ bindings: `sbx env rm` preserves global bindings by default. Pass `--prune-bindings` to remove every service binding declared by the environment file. +> [!WARNING] +> `--prune-bindings` deletes the complete global binding entry for every +> service declared in the environment file. This can affect other sandboxes +> that share those service bindings. + ### `registries` `registries` maps registry hostnames to pull credentials. Each entry requires @@ -250,10 +265,9 @@ registries: ### `mcp` -The `mcp.servers` list registers MCP servers on the host and adds them to the -sandbox. This field requires the hosted MCP control plane through -`SBX_MCP_URL`. MCP registrations are host-global and remain after -`sbx env rm`. +The `mcp.servers` list registers servers with the built-in +[MCP gateway](mcp-gateway.md) and adds them to the sandbox. MCP registrations +are host-global and remain after `sbx env rm`. | Field | Type | Required | Default | Description | | --------- | --------------- | -------- | ------- | --------------------------------------------------------------- | diff --git a/data/sbx_cli/sbx_env.yaml b/data/sbx_cli/sbx_env.yaml new file mode 100644 index 000000000000..9c64d66c74ee --- /dev/null +++ b/data/sbx_cli/sbx_env.yaml @@ -0,0 +1,28 @@ +name: sbx env +synopsis: | + Manage sandboxes declaratively from a .sbxenv.yaml file +experimental: true +description: |- + Manage a sandbox environment declared in a .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. +usage: sbx env COMMAND +options: + - name: help + shorthand: h + default_value: "false" + usage: help for env +inherited_options: + - 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 rm - Remove a sandbox environment and its scoped resources + - sbx env run - Create (if needed) and attach to a sandbox environment diff --git a/data/sbx_cli/sbx_env_create.yaml b/data/sbx_cli/sbx_env_create.yaml new file mode 100644 index 000000000000..1048fa27ea5f --- /dev/null +++ b/data/sbx_cli/sbx_env_create.yaml @@ -0,0 +1,30 @@ +name: sbx env create +synopsis: Create a sandbox environment from .sbxenv.yaml +experimental: true +description: |- + Read the environment file from PATH (default: current directory), + provision its declared secrets at the sandbox scope, merge its credential + bindings, and create the sandbox. Use "sbx env run" to attach. + + Each PATH may be a directory (the file is /.sbxenv.yaml) or the + path to the environment file itself. Passing more than one PATH deep-merges them + in order (docker-compose `-f` semantics): later files override earlier ones. + Values may reference environment variables with ${VAR} / $VAR (and + ${VAR:-default}); see the docs for the full syntax. +usage: sbx env create [PATH...] [flags] +options: + - name: clone + default_value: "false" + usage: | + Override workspace.clone in .sbxenv.yaml (see 'sbx create --clone') + - name: help + shorthand: h + default_value: "false" + usage: help for create +inherited_options: + - name: debug + shorthand: D + default_value: "false" + usage: Enable debug logging +see_also: + - sbx env - (Experimental) Manage sandboxes declaratively from a .sbxenv.yaml file diff --git a/data/sbx_cli/sbx_env_exec.yaml b/data/sbx_cli/sbx_env_exec.yaml new file mode 100644 index 000000000000..225789753ab1 --- /dev/null +++ b/data/sbx_cli/sbx_env_exec.yaml @@ -0,0 +1,68 @@ +name: sbx env exec +synopsis: Execute a command inside a sandbox environment +experimental: true +description: |- + Run COMMAND in the sandbox declared in .sbxenv.yaml. The sandbox + must already exist (see "sbx env create" and "sbx env run"); a stopped sandbox is + started first. + + Arguments before `--` are environment-file paths, following the same rules as + the other "sbx env" subcommands: each PATH may be a directory (the file is + /.sbxenv.yaml) or the path to the environment file itself, and passing + more than one deep-merges them in order. Without a `--` every positional + argument forms the command and the environment file is read from the current + directory. + + Flags match the behavior of "sbx exec". +usage: sbx env exec [flags] [PATH...] -- COMMAND [ARG...] +options: + - name: detach + shorthand: d + default_value: "false" + usage: 'Detached mode: run command in the background' + - name: detach-keys + usage: Override the key sequence for detaching a container + - name: env + shorthand: e + default_value: '[]' + usage: Set environment variables + - name: env-file + default_value: '[]' + usage: Read in a file of environment variables + - name: help + shorthand: h + default_value: "false" + usage: help for exec + - name: interactive + shorthand: i + default_value: "false" + usage: Keep STDIN open even if not attached + - name: privileged + default_value: "false" + usage: Give extended privileges to the command + - name: tty + shorthand: t + default_value: "false" + usage: Allocate a pseudo-TTY + - name: user + shorthand: u + usage: 'Username or UID (format: [:])' + - name: workdir + shorthand: w + usage: Working directory inside the container +inherited_options: + - name: debug + shorthand: D + default_value: "false" + usage: Enable debug logging +example: |4- + # Run a command in the environment declared in the current directory + sbx env exec go test ./... + + # Open a shell + sbx env exec -it -- bash + + # Run against explicitly merged environment files + sbx env exec .sbxenv.yaml override.yaml -- npm test +see_also: + - sbx env - (Experimental) Manage sandboxes declaratively from a .sbxenv.yaml file diff --git a/data/sbx_cli/sbx_env_rm.yaml b/data/sbx_cli/sbx_env_rm.yaml new file mode 100644 index 000000000000..5f43f20ade82 --- /dev/null +++ b/data/sbx_cli/sbx_env_rm.yaml @@ -0,0 +1,35 @@ +name: sbx env rm +synopsis: Remove a sandbox environment and its scoped resources +experimental: true +description: |- + Remove the sandbox declared in .sbxenv.yaml along with the + secret values provisioned at its sandbox scope (service, custom, and registry + credentials). Global credential bindings are left in place by default since + they are user-wide and may be shared with other sandboxes; pass + --prune-bindings to also remove the bindings this environment declares. + + Each PATH may be a directory (the file is /.sbxenv.yaml) or the + path to the environment file itself. Passing more than one PATH deep-merges them + in order (docker-compose `-f` semantics), so the same set used to create the + environment resolves to the same sandbox on removal. +usage: sbx env rm [PATH...] [flags] +options: + - name: force + shorthand: f + default_value: "false" + usage: Skip confirmation prompts + - name: help + shorthand: h + default_value: "false" + usage: help for rm + - name: prune-bindings + default_value: "false" + usage: | + Also remove this environment's bindings from the global credentials.yaml +inherited_options: + - name: debug + shorthand: D + default_value: "false" + usage: Enable debug logging +see_also: + - sbx env - (Experimental) Manage sandboxes declaratively from a .sbxenv.yaml file diff --git a/data/sbx_cli/sbx_env_run.yaml b/data/sbx_cli/sbx_env_run.yaml new file mode 100644 index 000000000000..f23ca8f61518 --- /dev/null +++ b/data/sbx_cli/sbx_env_run.yaml @@ -0,0 +1,35 @@ +name: sbx env run +synopsis: Create (if needed) and attach to a sandbox environment +experimental: true +description: |- + Read the environment file from PATH (default: current directory) + and drop into the sandbox shell. If the sandbox already exists it is started + and re-attached without re-provisioning; otherwise it is created first + (provisioning secrets and bindings) and then attached. + + Each PATH may be a directory (the file is /.sbxenv.yaml) or the + path to the environment file itself. Passing more than one PATH deep-merges them + in order (docker-compose `-f` semantics): later files override earlier ones. + Values may reference environment variables with ${VAR} / $VAR (and + ${VAR:-default}); see the docs for the full syntax. +usage: sbx env run [PATH...] [flags] +options: + - name: clone + default_value: "false" + usage: | + Override workspace.clone in .sbxenv.yaml (see 'sbx create --clone') + - name: detached + shorthand: d + default_value: "false" + usage: Create/start the sandbox without attaching + - name: help + shorthand: h + default_value: "false" + usage: help for run +inherited_options: + - name: debug + shorthand: D + default_value: "false" + usage: Enable debug logging +see_also: + - sbx env - (Experimental) Manage sandboxes declaratively from a .sbxenv.yaml file From 9feb274eecdb12ed3450a5040e04334173ff84ac Mon Sep 17 00:00:00 2001 From: David Karlsson <35727626+dvdksn@users.noreply.github.com> Date: Tue, 11 Aug 2026 09:46:08 +0000 Subject: [PATCH 08/11] sandboxes: link environment files from get started The experimental environment-file workflow was only discoverable from the workflow guide. Add a concise link in the get-started next steps with its v0.39 availability requirement. Signed-off-by: David Karlsson <35727626+dvdksn@users.noreply.github.com> --- content/manuals/ai/sandboxes/get-started.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/content/manuals/ai/sandboxes/get-started.md b/content/manuals/ai/sandboxes/get-started.md index 7a709b1f8c09..7f9a5451e4c7 100644 --- a/content/manuals/ai/sandboxes/get-started.md +++ b/content/manuals/ai/sandboxes/get-started.md @@ -268,6 +268,9 @@ Then explore: publishing. - [Workflow patterns](workflows.md) — Git strategies, local services, CI, and authenticated tools. +- [Sandbox environment files](sandbox-environments.md) — declare and share + repeatable local sandbox configurations with `.sbxenv.yaml`. Requires `sbx` + 0.39.0 or later. - [Customize with kits](customize/) — package an agent, its tools, and its network rules into a reusable definition you launch with a single flag. - [Agents](agents/) — the full list of supported agents and how to configure From 63b47b337fc84346b8dadad28758aea20763d10a Mon Sep 17 00:00:00 2001 From: David Karlsson <35727626+dvdksn@users.noreply.github.com> Date: Wed, 12 Aug 2026 11:19:46 +0000 Subject: [PATCH 09/11] sandboxes: improve environment file introduction The page opened with an ancillary workspace-location case before showing the feature's primary workflow. Lead with a project-local web application example, explain the problem it solves, and remove the redundant local-sandbox qualifier. Signed-off-by: David Karlsson <35727626+dvdksn@users.noreply.github.com> --- .../ai/sandboxes/sandbox-environments.md | 49 +++++++++++-------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/content/manuals/ai/sandboxes/sandbox-environments.md b/content/manuals/ai/sandboxes/sandbox-environments.md index 5fb0dbb5ae78..7b7ba1ec60b0 100644 --- a/content/manuals/ai/sandboxes/sandbox-environments.md +++ b/content/manuals/ai/sandboxes/sandbox-environments.md @@ -17,43 +17,50 @@ params: text: Experimental --- -> [!NOTE] -> `sbx env` requires `sbx` 0.39.0 or later and supports local sandboxes only. -> The feature is experimental, so the command interface and file format may -> change in future releases. +A sandbox environment file captures the setup for a project in a +`.sbxenv.yaml` file. Instead of sharing a collection of CLI flags and setup +steps, commit the file so everyone can create a consistent sandbox setup with +one command. -A sandbox environment file describes the agent, kits, workspaces, environment -variables, credentials, MCP servers, ports, and resource limits for a sandbox. -Commit the file with your project so team members can run the same sandbox -configuration without sharing flag combinations or setup instructions. +> [!NOTE] +> `sbx env` requires `sbx` 0.39.0 or later. The feature is experimental, so the +> command interface and file format may change in future releases. -The environment file doesn't need to be in the workspace. You can store it in -another directory and set `workspace.path` to the workspace: +For example, the following file defines a sandbox for a web application. It +names the sandbox, selects the agent, sets an environment variable, obtains a +GitHub credential from the host, and publishes the development server on port +3000: ```yaml # .sbxenv.yaml schemaVersion: "1" -name: docs-env +name: web-app agent: claude -workspace: - path: $HOME/src/github.com/docker/docs - clone: true - -kits: - - "git+https://github.com/docker/sbx-kits-contrib.git#dir=vale" - - "git+https://github.com/docker/sbx-kits-contrib.git#dir=git-ssh-sign" - - "git+https://github.com/docker/sbx-kits-contrib.git#dir=github-ssh" +env: + NODE_ENV: development secrets: github: command: gh auth token ports: - - sandbox: 1313 - host: 1313 + - sandbox: 3000 + host: 3000 ``` +Save the file in the project directory, then run: + +```console +$ sbx env run +``` + +`sbx` uses the project directory as the workspace, provisions the declared +credential, creates the sandbox, and attaches to the agent. Other team members +can run the same command after cloning the project. Environment files can also +install kits, mount additional workspaces, register MCP servers, and set +resource limits. + ## Commands | Command | Description | From 3456c6bd7dbaa8ea04ebd6391a599d3ad5d2fce3 Mon Sep 17 00:00:00 2001 From: David Karlsson <35727626+dvdksn@users.noreply.github.com> Date: Wed, 12 Aug 2026 11:35:48 +0000 Subject: [PATCH 10/11] sandboxes: add environment workflow gallery The environment file page moved from one example directly into command and schema reference material. Add four task-oriented recipes for shared project setup, personal overrides, multi-repository work, and automation, then separate update and cleanup behavior into dedicated sections. Signed-off-by: David Karlsson <35727626+dvdksn@users.noreply.github.com> --- .../ai/sandboxes/sandbox-environments.md | 159 ++++++++++++++---- 1 file changed, 128 insertions(+), 31 deletions(-) diff --git a/content/manuals/ai/sandboxes/sandbox-environments.md b/content/manuals/ai/sandboxes/sandbox-environments.md index 7b7ba1ec60b0..e80b6705b4ed 100644 --- a/content/manuals/ai/sandboxes/sandbox-environments.md +++ b/content/manuals/ai/sandboxes/sandbox-environments.md @@ -26,10 +26,17 @@ one command. > `sbx env` requires `sbx` 0.39.0 or later. The feature is experimental, so the > command interface and file format may change in future releases. -For example, the following file defines a sandbox for a web application. It -names the sandbox, selects the agent, sets an environment variable, obtains a -GitHub credential from the host, and publishes the development server on port -3000: +## Common workflows + +The following examples combine environment file fields into configurations you +can adapt for a project. + +### Share a complete project environment + +Commit a `.sbxenv.yaml` file that includes the agent, project tools, +credentials, environment variables, and ports the project needs. The following +example adds the Playwright mixin kit to a web application so the agent can run +browser tests: ```yaml # .sbxenv.yaml @@ -37,6 +44,9 @@ schemaVersion: "1" name: web-app agent: claude +kits: + - "git+https://github.com/docker/sbx-kits-contrib.git#dir=playwright" + env: NODE_ENV: development @@ -49,17 +59,115 @@ ports: host: 3000 ``` -Save the file in the project directory, then run: +The Playwright kit installs the browser test tools, declares the network access +needed to install them, and gives the agent instructions for using them. Before +using a Git kit from this repository, add its source to your +[kit source allowlist](customize/kits.md#restrict-kit-sources): + +```console +$ sbx settings set kit.allowedSources '["docker.io/","github.com/docker/"]' +``` + +The setting replaces the complete allowlist, so include any existing sources +you want to keep. Pin remote kits with the `ref` URL parameter when you need +reproducible setup. + +Run the environment from the project directory: ```console $ sbx env run ``` `sbx` uses the project directory as the workspace, provisions the declared -credential, creates the sandbox, and attaches to the agent. Other team members -can run the same command after cloning the project. Environment files can also -install kits, mount additional workspaces, register MCP servers, and set -resource limits. +credential, installs the kit, creates the sandbox, publishes the port, and +attaches to the agent. Other team members can run the same command after +cloning the project. + +### Combine team defaults and personal settings + +Keep the shared configuration in a committed file and put machine-specific +settings in a file excluded from version control. For example, commit +`base.sbxenv.yaml`: + +```yaml +schemaVersion: "1" +name: web-app +agent: claude + +env: + NODE_ENV: development + +sandboxOptions: + cpus: 4 + memory: 8g +``` + +Add `local.sbxenv.yaml` to `.gitignore`, then use it for personal settings: + +```yaml +env: + LOG_LEVEL: debug + +sandboxOptions: + memory: 12g +``` + +Pass both files in merge order: + +```console +$ sbx env run base.sbxenv.yaml local.sbxenv.yaml +``` + +Nested 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. The first file controls the +base directory for relative workspace paths and the default sandbox name. + +### Work across multiple repositories + +Mount related repositories alongside the primary project when the agent needs +to coordinate changes or consult shared code and documentation: + +```yaml +# .sbxenv.yaml in the web-app repository +schemaVersion: "1" +name: web-platform +agent: codex + +workspace: . + +additionalWorkspaces: + - path: ../shared-components + - path: ../architecture-docs + readOnly: true +``` + +The agent starts in `web-app`, can modify `shared-components`, and can read +`architecture-docs` without changing it. Relative paths resolve from the +directory of the first environment file. Additional workspaces are mounted +directly even when the primary workspace uses clone mode. + +### Reuse an environment in automation + +Use the same committed environment for interactive development and automated +tasks. Developers attach to the agent with `run`: + +```console +$ sbx env run +``` + +Automation can create the sandbox without attaching, run commands in it, and +remove it afterward: + +```console +$ sbx env create +$ sbx env exec -- npm test +$ sbx env rm --force +``` + +Commands and vault references under `secrets` resolve on the host, so the +automation runner must provide the referenced tools and authentication. The +secret values remain outside the environment file. ## Commands @@ -75,13 +183,7 @@ pass a directory, `sbx` reads `.sbxenv.yaml` and falls back to `.sbxenv.yml`. With no path, `sbx` searches the working directory. Pass the same set of paths to each lifecycle command so they resolve the same -sandbox. See [Multiple files](#multiple-files) for details. - -`sbx env run` starts and attaches to an existing sandbox without provisioning -its secrets and bindings again. For an existing sandbox, the command applies -changes to `env` to the new session and reconciles declared MCP servers. Changes -to workspaces, kits, ports, secrets, bindings, and `sandboxOptions` require you -to remove the environment with `sbx env rm` and create it again. +sandbox. For `sbx env exec`, arguments before `--` are environment-file paths and arguments after `--` form the command. Without `--`, all arguments form the @@ -92,6 +194,16 @@ $ sbx env exec .sbxenv.yaml -- go test ./... $ sbx env exec go test ./... ``` +## Update an environment + +`sbx env run` starts and attaches to an existing sandbox without provisioning +its secrets and bindings again. For an existing sandbox, the command applies +changes to `env` to the new session and reconciles declared MCP servers. Changes +to workspaces, kits, ports, secrets, bindings, and `sandboxOptions` require you +to remove the environment with `sbx env rm` and create it again. + +## Remove an environment + `sbx env rm` removes the sandbox and its scoped service and registry credentials. Global credential bindings remain unless you pass `--prune-bindings`. Host-global MCP registrations remain available to other @@ -104,21 +216,6 @@ paths to remove the scoped secrets. Pass `--prune-bindings` if you also want to remove the declared global bindings. MCP registrations are host-global and remain after cleanup. -## Multiple files - -Pass multiple paths to merge environment files in order. Nested mappings merge -by key, lists concatenate, and values from later files replace earlier scalar -values. Relative workspace paths and the default sandbox name use the directory -of the first file. - -```console -$ sbx env run base.sbxenv.yaml local.sbxenv.yaml -``` - -Commit a `base.sbxenv.yaml` with shared configuration and add -`local.sbxenv.yaml` to `.gitignore` for personal overrides, such as another -workspace path, additional secrets, or different resource limits. - ## Variable interpolation Host environment variables are expanded in each file before the files are From 8f2a9a72e8d32cd0f979a1a4ed9655a7212c909b Mon Sep 17 00:00:00 2001 From: David Karlsson <35727626+dvdksn@users.noreply.github.com> Date: Wed, 12 Aug 2026 12:17:54 +0000 Subject: [PATCH 11/11] sandboxes: omit environment interpolation docs Variable interpolation is scheduled to be superseded after v0.39 and should not be promoted as a lasting workflow. Remove its authored guide section and the interpolation suggestion from the secret warning while preserving generated v0.39 CLI reference data. Signed-off-by: David Karlsson <35727626+dvdksn@users.noreply.github.com> --- .../ai/sandboxes/sandbox-environments.md | 31 +------------------ 1 file changed, 1 insertion(+), 30 deletions(-) diff --git a/content/manuals/ai/sandboxes/sandbox-environments.md b/content/manuals/ai/sandboxes/sandbox-environments.md index e80b6705b4ed..2b6422375995 100644 --- a/content/manuals/ai/sandboxes/sandbox-environments.md +++ b/content/manuals/ai/sandboxes/sandbox-environments.md @@ -216,34 +216,6 @@ paths to remove the scoped secrets. Pass `--prune-bindings` if you also want to remove the declared global bindings. MCP registrations are host-global and remain after cleanup. -## Variable interpolation - -Host environment variables are expanded in each file before the files are -merged and parsed: - -| Syntax | Behavior | -| ------------------------ | ----------------------------------------------------------- | -| `$VAR` or `${VAR}` | Uses the value of `VAR`, or an empty string when unset | -| `${VAR:-default}` | Uses `default` when `VAR` is unset or empty | -| `${VAR-default}` | Uses `default` when `VAR` is unset | -| `${VAR:+replacement}` | Uses `replacement` when `VAR` is set and non-empty | -| `${VAR+replacement}` | Uses `replacement` when `VAR` is set | -| `${VAR:?message}` | Fails with `message` when `VAR` is unset or empty | -| `${VAR?message}` | Fails with `message` when `VAR` is unset | -| `$$` | Inserts a literal `$` | - -Default, replacement, and error values can contain nested variable -expressions. - -```yaml -workspace: - path: ${WORKSPACE:-$HOME/src/myproject} - -secrets: - my-token: - value: ${MY_TOKEN:?MY_TOKEN must be set} -``` - ## File reference The loader rejects unknown fields and unsupported schema versions. @@ -316,8 +288,7 @@ the environment is created. > [!WARNING] > A literal `value` is visible to anyone with read access to the file. Use a -> vault URI with `ref`, obtain the value at runtime with `command`, or use -> variable interpolation such as `value: ${MY_TOKEN}`. +> vault URI with `ref` or obtain the value at runtime with `command`. ```yaml secrets: