From 80bd6569e5f3eb449ff7e99b9da0d3fa8aef6030 Mon Sep 17 00:00:00 2001 From: David Karlsson <35727626+dvdksn@users.noreply.github.com> Date: Thu, 24 Sep 2026 18:00:08 +0200 Subject: [PATCH] docs: document v3 kits (#26065) Add v3 kit documentation for Docker Sandboxes: concepts, usage, authoring, and kit sets. Link to the upstream specification for reference details and retain v2 guidance. Validation: Markdown/style checks, Hugo build, internal links, and example build checks passed. Closes docker/sbx-releases#569 @netlify /ai/sandboxes/customize/ --- content/guides/mistral-vibe-sandbox.md | 20 +- content/manuals/ai/sandboxes/_index.md | 4 +- .../ai/sandboxes/agents/claude-code.md | 2 +- .../ai/sandboxes/agents/docker-agent.md | 2 +- content/manuals/ai/sandboxes/agents/shell.md | 2 +- .../ai/sandboxes/configuration/credentials.md | 129 +++- .../configuration/environment-files.md | 11 +- .../configuration/registry-mirror.md | 2 +- .../ai/sandboxes/configuration/settings.md | 4 +- .../manuals/ai/sandboxes/customize/_index.md | 147 ++-- .../ai/sandboxes/customize/author/_index.md | 188 ++++++ .../sandboxes/customize/author/base-images.md | 190 ++++++ .../customize/author/build-an-agent.md | 419 ++++++++++++ .../sandboxes/customize/author/distribute.md | 117 ++++ .../ai/sandboxes/customize/author/kit-sets.md | 244 +++++++ .../ai/sandboxes/customize/author/patterns.md | 147 ++++ .../sandboxes/customize/author/tool-mixins.md | 210 ++++++ .../ai/sandboxes/customize/build-an-agent.md | 326 --------- .../ai/sandboxes/customize/kit-examples.md | 467 ------------- .../{kit-reference.md => kits-v2.md} | 618 +++++++++++------ .../manuals/ai/sandboxes/customize/kits.md | 631 ------------------ .../ai/sandboxes/customize/templates.md | 270 -------- .../ai/sandboxes/customize/use-kits.md | 302 +++++++++ content/manuals/ai/sandboxes/faq.md | 22 +- .../ai/sandboxes/governance/concepts.md | 7 +- .../monitor-and-enforce/monitoring.md | 2 +- .../ai/sandboxes/integrations/t3-code.md | 4 +- .../manuals/ai/sandboxes/security/_index.md | 2 +- .../manuals/ai/sandboxes/troubleshooting.md | 9 +- content/manuals/ai/sandboxes/usage.md | 155 ++++- .../ai/sandboxes/workflows/authentication.md | 2 +- content/manuals/ai/sandboxes/workflows/git.md | 4 +- .../docker-hub/image-library/catalogs.md | 9 +- .../docker-hub/image-library/search.md | 9 +- data/whats-new.json | 2 +- 35 files changed, 2645 insertions(+), 2034 deletions(-) create mode 100644 content/manuals/ai/sandboxes/customize/author/_index.md create mode 100644 content/manuals/ai/sandboxes/customize/author/base-images.md create mode 100644 content/manuals/ai/sandboxes/customize/author/build-an-agent.md create mode 100644 content/manuals/ai/sandboxes/customize/author/distribute.md create mode 100644 content/manuals/ai/sandboxes/customize/author/kit-sets.md create mode 100644 content/manuals/ai/sandboxes/customize/author/patterns.md create mode 100644 content/manuals/ai/sandboxes/customize/author/tool-mixins.md delete mode 100644 content/manuals/ai/sandboxes/customize/build-an-agent.md delete mode 100644 content/manuals/ai/sandboxes/customize/kit-examples.md rename content/manuals/ai/sandboxes/customize/{kit-reference.md => kits-v2.md} (62%) delete mode 100644 content/manuals/ai/sandboxes/customize/kits.md delete mode 100644 content/manuals/ai/sandboxes/customize/templates.md create mode 100644 content/manuals/ai/sandboxes/customize/use-kits.md diff --git a/content/guides/mistral-vibe-sandbox.md b/content/guides/mistral-vibe-sandbox.md index 833abaa249..ebfe2c9c01 100644 --- a/content/guides/mistral-vibe-sandbox.md +++ b/content/guides/mistral-vibe-sandbox.md @@ -28,6 +28,9 @@ In this guide, you'll learn how to: - Write an agent kit that wires Vibe to the Mistral API through the proxy - Validate, launch, and iterate on the sandbox +This guide uses the v2 format. For its reference and migration +guidance, see [Kits v2](../manuals/ai/sandboxes/customize/kits-v2.md). + ## How isolation works Every outbound request from a sandbox passes through a proxy that runs on @@ -168,7 +171,7 @@ Each field does the following: | Field | Purpose | | --------------------------- | -------------------------------------------------------------------------------------------------------------- | | `kind: sandbox` | Declares a sandbox agent: a complete image plus its launch configuration. | -| `name` | The kit's identifier, reused in the `sbx run` command. | +| `name` | The kit's identifier. Pass the kit directory to `sbx run`. | | `sandbox.image` | The pinned image you published in Step 3. Its `CMD` launches Vibe, so the kit doesn't set an entrypoint. | | `agentInstructions.filename`| The instructions file Vibe reads in the project. | | `agentInstructions.content` | Markdown appended to `AGENTS.md` at creation to prime the agent about its environment. | @@ -177,9 +180,6 @@ Each field does the following: | `credentials[].apiKey.name` | The environment variable the proxy manages. Vibe sees a sentinel value; the proxy swaps in the real key. | | `credentials[].apiKey.inject`| Where and how the proxy attaches the key. `scheme: bearer` sets `Authorization: Bearer ` for the domain. | -For the full kit format, see -[Kits](../manuals/ai/sandboxes/customize/kits.md). - > [!WARNING] > `--agent auto-approve` runs Vibe in a mode that approves every tool > execution without prompting. The sandbox isolates the agent from your host, @@ -197,13 +197,13 @@ $ sbx kit validate ./mistral-vibe Then, from your project directory, launch the agent with the kit: ```console -$ sbx run --kit ./mistral-vibe --name mistral-vibe mistral-vibe . +$ sbx run ./mistral-vibe --name mistral-vibe . ``` -- `--kit ./mistral-vibe` points to the folder that contains `spec.yaml`. +- `./mistral-vibe` is the sandbox kit reference, pointing to the folder that + contains `spec.yaml`. - `--name mistral-vibe` names the sandbox. Without it, `sbx` derives a name from the agent and the working directory, and the commands below won't match. -- `mistral-vibe` is the agent name from `spec.yaml`. - `.` is the project directory to mount in the sandbox. Vibe starts in an isolated microVM, talks to the Mistral API through the @@ -223,7 +223,7 @@ it. Use it to spot a host missing from `permissions.network.allow`. After you change `spec.yaml`, recreate the sandbox for a clean start: ```console -$ sbx rm mistral-vibe && sbx run --kit ./mistral-vibe --name mistral-vibe mistral-vibe . +$ sbx rm mistral-vibe && sbx run ./mistral-vibe --name mistral-vibe . ``` ## Clean up @@ -245,7 +245,7 @@ Files in your workspace are unaffected. ## Learn more - [Get started with Docker Sandboxes](../manuals/ai/sandboxes/get-started.md) -- [Build your own agent kit](../manuals/ai/sandboxes/customize/build-an-agent.md) -- [Customize sandboxes with kits](../manuals/ai/sandboxes/customize/kits.md) +- [Build a v3 agent workload](/manuals/ai/sandboxes/customize/author/build-an-agent.md) +- [Customize sandboxes with kits](/manuals/ai/sandboxes/customize/_index.md) - [Credentials and built-in services](../manuals/ai/sandboxes/configuration/credentials.md#built-in-services) - [Mistral Vibe](https://github.com/mistralai/mistral-vibe) diff --git a/content/manuals/ai/sandboxes/_index.md b/content/manuals/ai/sandboxes/_index.md index 1db8a83b1c..0c95d3e92d 100644 --- a/content/manuals/ai/sandboxes/_index.md +++ b/content/manuals/ai/sandboxes/_index.md @@ -48,8 +48,8 @@ jump to the [usage guide](usage.md) for basic commands. Cursor to a sandbox over SSH - [MCP gateway](mcp-gateway.md) — register MCP servers and connect them to sandboxed agents -- [Customize](customize/) — reusable templates and declarative kits for - extending or tailoring sandboxes +- [Kits](customize/) — package tools and configuration into reusable + sandbox environments - [Architecture](architecture.md) — microVM isolation, workspace mounting, networking - [Security](security/) — isolation model, credential handling, and diff --git a/content/manuals/ai/sandboxes/agents/claude-code.md b/content/manuals/ai/sandboxes/agents/claude-code.md index f2fbe17af8..8d93c99d01 100644 --- a/content/manuals/ai/sandboxes/agents/claude-code.md +++ b/content/manuals/ai/sandboxes/agents/claude-code.md @@ -124,7 +124,7 @@ See [Git workflows](../workflows/git.md) for clone-mode details. ## Base image The sandbox uses `docker/sandbox-templates:claude-code`. See -[Templates](../customize/templates.md) to build your own image on top of +[Base images](/manuals/ai/sandboxes/customize/author/base-images.md) to build your own image on top of this base. ## Use a local model diff --git a/content/manuals/ai/sandboxes/agents/docker-agent.md b/content/manuals/ai/sandboxes/agents/docker-agent.md index 656d1488e3..3916d08b0c 100644 --- a/content/manuals/ai/sandboxes/agents/docker-agent.md +++ b/content/manuals/ai/sandboxes/agents/docker-agent.md @@ -69,5 +69,5 @@ $ sbx run --name -- run --yolo agent.yml ## Base image The sandbox uses `docker/sandbox-templates:docker-agent`. See -[Templates](../customize/templates.md) to build your own image on top of +[Base images](/manuals/ai/sandboxes/customize/author/base-images.md) to build your own image on top of this base. diff --git a/content/manuals/ai/sandboxes/agents/shell.md b/content/manuals/ai/sandboxes/agents/shell.md index 5e26f6c8f9..78533bcfc9 100644 --- a/content/manuals/ai/sandboxes/agents/shell.md +++ b/content/manuals/ai/sandboxes/agents/shell.md @@ -52,7 +52,7 @@ $ sbx secret set openai Once inside the shell, you can install agents using their standard methods, for example `npm install -g @continuedev/cli`. For complex setups, build a -[custom template](../customize/templates.md) instead of installing +[workload kit](/manuals/ai/sandboxes/customize/_index.md) instead of installing interactively each time. ## Base image diff --git a/content/manuals/ai/sandboxes/configuration/credentials.md b/content/manuals/ai/sandboxes/configuration/credentials.md index d122c09bfc..0534d7e1e0 100644 --- a/content/manuals/ai/sandboxes/configuration/credentials.md +++ b/content/manuals/ai/sandboxes/configuration/credentials.md @@ -27,7 +27,7 @@ sees only a sentinel like `proxy-managed`. A kit can set OAuth `passthrough: true` to opt out of sentinel masking. This sends the real token response into the sandbox and reduces credential isolation. -See the [`oauth` kit fields](../customize/kit-reference.md#oauth). +See the [`oauth` kit fields](https://github.com/docker/sandbox-kit-spec/blob/main/docs/spec/capabilities/com.docker.sandbox/credential@1.md). There are several ways to provide that value. When more than one source has a value for the same service, the stored secret takes precedence. @@ -37,9 +37,12 @@ value for the same service, the stored secret takes precedence. | [Stored secrets](#stored-secrets) (`sbx secret set`) | A value or dynamic source in your OS keychain, keyed by service | The default for any built-in or kit-declared service | | [Custom secrets](#custom-secrets) (`sbx secret set-custom`) | A value keyed to a domain and environment variable | The service model doesn't fit — the agent validates the variable's format, or the secret rides in a request body | | OAuth | A host-side sign-in flow; the token never enters the sandbox | The agent supports it, such as Claude Code, Codex, Cursor, or Droid | -| [Credential bindings](#credential-bindings) (`credentials.yaml`) | Per-service mechanism and domain approval | Required for third-party `schemaVersion: "2"` kits | | [Registry credentials](#registry-credentials) (`sbx secret set --registry`) | Authentication for pulling images and kits | Pulling templates or kits from a private registry | +Providing a value and approving its use are separate steps. +[Credential bindings](#credential-bindings) record which mechanisms and domains +you authorize a kit to use. They don't store the credential value. + For multi-provider agents (OpenCode, Docker Agent), the proxy selects credentials based on the API endpoint being called. See individual [agent pages](../agents/) for provider-specific details. @@ -227,8 +230,64 @@ it into requests to the listed API domains. ### Services declared by kits -Custom kits can declare their own service identifiers in `spec.yaml`. In -`schemaVersion: "2"`, credentials are declared under the `credentials:` list: +Use the service identifier from the kit's documentation when storing its +credential. For a kit that declares `my-service`, run: + +```console +$ sbx secret set my-service +``` + +There's no separate registration step. The stored value and the kit's request +use the same identifier. Approve the kit's credential request when prompted. +See [Credential bindings](#credential-bindings). + +When authoring a kit, declare how it uses that service. V3 uses a credential +capability, and v2 uses a top-level `credentials` list. Both examples declare the +service and permit access to its API host: + +{{< tabs >}} +{{< tab name="v3" >}} + +```yaml +capabilities: + - type: com.docker.sandbox/network-policy@1 + config: + runtime: + allow: [api.my-service.com] + - type: com.docker.sandbox/credential@1 + config: + service: my-service + phase: runtime + apiKey: + name: MY_SERVICE_TOKEN + proxyManaged: true + inject: + - domain: api.my-service.com + header: Authorization + format: "Bearer %s" +``` + +For API keys, specify both the HTTP header and its value format, as in this +example. `sbx` doesn't use `apiKey.inject[].scheme` in v3 kits. + +For OAuth, use JSON credential files and a provider that returns the refresh +token in `refresh_token`. `sbx` doesn't support TOML credential files or a +different refresh-token field. + +Credentials declared for the install phase are available during install hooks. +Add the domains that receive these credentials to the network policy's +`install.allow` list. An entry in `runtime.allow` alone doesn't grant access +during installation. If a hook reads a credential environment variable, +include that name in its `env` list. + +In `sbx`, the proxy stops injecting credentials into install-only domains +before the agent launches. A domain remains available for credential injection +if any runtime credential targets it, even under a different service name. +If you declare the same service for both phases, `sbx` uses the runtime +declaration's credential settings in both phases. + +{{< /tab >}} +{{< tab name="v2" >}} ```yaml credentials: @@ -239,21 +298,20 @@ credentials: inject: - domain: api.my-service.com scheme: bearer + +permissions: + network: + allow: [api.my-service.com] ``` +{{< /tab >}} +{{< /tabs >}} + Each service declares `apiKey`, `oauth`, or both. When both resolve at runtime, -the API key takes precedence and OAuth acts as the fallback. To provide the -credential value, run `sbx secret set` with the same identifier the kit -declares: - -```console -$ sbx secret set my-service -``` - -There's no separate registration step; the keychain entry is keyed on the -identifier the kit already uses. See -[Authenticate to external services](../customize/kits.md#authenticate-to-external-services) -for the full kit-side wiring. +the API key takes precedence and OAuth acts as the fallback. For complete +kit-side configuration, see +[V3 credential definition](https://github.com/docker/sandbox-kit-spec/blob/main/docs/spec/capabilities/com.docker.sandbox/credential@1.md) +or [V2 credentials](../customize/kits-v2.md#credentials). ### List and remove secrets @@ -460,11 +518,11 @@ you've approved for each service. It lives at `~/.config/sbx/credentials.yaml`, or `%APPDATA%\sbx\credentials.yaml` on Windows. -Third-party kits that declare `schemaVersion: "2"` require an approved binding -for each credential they use. `sbx` creates one interactively the first time you +Third-party kits require an approved binding for each credential they use, +regardless of schema version. `sbx` creates one interactively the first time you run such a kit (see [First-run approval](#first-run-approval)); you can also -write entries by hand. Credentials declared only by embedded, built-in kits are -authorized by provenance and don't need a binding. +write entries by hand. Credentials requested only by the built-in kits shipped +with `sbx` don't need a binding. Each entry under `bindings` is keyed by a [service identifier](#built-in-services) and approves one or both credential @@ -504,30 +562,31 @@ both cases, you approve the domains declared by the kit. `sbx` writes the entry to `credentials.yaml`. In non-interactive contexts (CI or `--detached`), there's no one to answer the -prompt. Without a binding, the sandbox starts with the credential withheld. If -the kit marks the credential as `required: true`, `sbx` also prints a warning. +prompt. In `sbx`, the sandbox starts with the credential withheld when no +binding exists. For a required credential, `sbx` prints a warning rather than +failing sandbox creation. This is a limitation of `sbx` enforcement: kit authors +shouldn't rely on a required credential being available merely because the +sandbox started. + Pre-create the binding by running the kit interactively once or by writing `credentials.yaml` directly before running unattended. -The bindings file gates whether a third-party v2 kit can use a service +The bindings file gates whether a third-party kit can use a service credential. The kit's credential injection rules and network permissions still constrain which requests can carry the credential. ### Kits that require a binding -Only third-party kits that declare `schemaVersion: "2"` require a binding. -Built-in agents also use `schemaVersion: "2"`, but credentials declared only by -embedded kits are authorized by provenance and inject automatically. A -third-party kit that extends a built-in agent inherits its credentials, but not -its built-in provenance. The inherited credentials therefore require approval. -If a third-party kit declares the same service itself, that service also -requires approval. Kits on `schemaVersion: "1"` inject their declared -credentials without a binding. +Third-party kits require your approval to use credentials, regardless of +schema version. The built-in kits shipped with `sbx` can use credentials they +request without a binding. If a third-party v2 kit extends a built-in agent, +you must approve its use of the inherited credentials. You must also approve +a third-party kit that requests the same service itself. ## Registry credentials Registry credentials authenticate to private OCI registries when pulling -[templates](../customize/templates.md) or [kits](../customize/kits.md), and can +[templates](../usage.md#load-a-template) or [kits](/manuals/ai/sandboxes/customize/_index.md), and can also let the agent pull and push images from inside the sandbox through the host-side proxy. Use `sbx secret set --registry ` to store them. For Docker Hub, `sbx` reuses your `sbx login` session — no registry secret needed. @@ -587,10 +646,12 @@ To scope the credential to a single sandbox, store it under that sandbox's name: $ gh auth token | sbx secret set --sandbox my-app --registry ghcr.io --password-stdin ``` -For Docker Hub, `sbx kit pull` and `sbx kit push` use the session from +For v2 kits on Docker Hub, `sbx kit pull` and `sbx kit push` use the session from `sbx login`. For other registries, both commands use these credentials. Both commands fall back to the Docker credential store, so credentials from -`docker login` also work. +`docker login` also work. V3 kits are +[published with Docker Buildx](/manuals/ai/sandboxes/customize/author/distribute.md#publish-an-image), +which uses the credentials from `docker login`. ### Trust a private registry authentication endpoint diff --git a/content/manuals/ai/sandboxes/configuration/environment-files.md b/content/manuals/ai/sandboxes/configuration/environment-files.md index 4d64de5cb2..dcd86c75e3 100644 --- a/content/manuals/ai/sandboxes/configuration/environment-files.md +++ b/content/manuals/ai/sandboxes/configuration/environment-files.md @@ -462,8 +462,15 @@ true`. `kits` accepts local directories, ZIP archives, OCI registry references, and Git URLs prefixed with `git+https://` or `git+ssh://`. Kits can install tools, -configure the sandbox, and give the agent project-specific instructions. See -[Kits](../customize/kits.md) for details. +configure the sandbox, and give the agent project-specific instructions. +The examples on this page pair built-in agents with v2 mixins. See +[Kits v2](/manuals/ai/sandboxes/customize/kits-v2.md) for that format, or +[Version compatibility](/manuals/ai/sandboxes/customize/_index.md#version-compatibility) +when selecting v3 kits. + +An environment file selects kits and configures a sandbox's host resources. +A kit descriptor defines the package itself. The environment file's +`schemaVersion` is independent of the schema version in a kit descriptor. Explicit relative paths resolve from the directory of the environment file that declares them. These include `.`, `..`, paths that start with `./` or diff --git a/content/manuals/ai/sandboxes/configuration/registry-mirror.md b/content/manuals/ai/sandboxes/configuration/registry-mirror.md index d9bd973fcd..0304505def 100644 --- a/content/manuals/ai/sandboxes/configuration/registry-mirror.md +++ b/content/manuals/ai/sandboxes/configuration/registry-mirror.md @@ -54,7 +54,7 @@ mirror URL paths differently from image repository prefixes. Docker Engine connects to the mirror over HTTPS, so the sandbox must trust the certificate that the mirror presents. For a mirror that uses an internal certificate authority, add the CA to the sandbox's system trust store. See -[Install an internal CA certificate](../customize/kit-examples.md#install-an-internal-ca-certificate). +[Install an internal CA certificate](../customize/kits-v2.md#install-an-internal-ca-certificate). Template and kit pulls use the changed setting immediately. Existing sandboxes retain the Docker Engine mirror configuration with which they were created. diff --git a/content/manuals/ai/sandboxes/configuration/settings.md b/content/manuals/ai/sandboxes/configuration/settings.md index 060b5c4fe4..1817389c0c 100644 --- a/content/manuals/ai/sandboxes/configuration/settings.md +++ b/content/manuals/ai/sandboxes/configuration/settings.md @@ -305,7 +305,7 @@ organization's repositories, but not `github.com/myorg-other/`. The value by [kit.allowLocalKits](#kitallowlocalkits), and pinned agent kits have the [kit.allowExtractedAgents](#kitallowextractedagents) exception. -See [restrict kit sources](../customize/kits.md#restrict-kit-sources) for source +See [restrict kit sources](../customize/use-kits.md#restrict-kit-sources) for source formats and examples. #### kit.allowLocalKits {.wrap-anywhere} @@ -366,7 +366,7 @@ Pinned agent kits remain exempt while A signature covers the kit's `spec.yaml` and `files/` content. It doesn't pin image tags or verify downloads performed by the kit's commands. See -[sign and verify kits](../customize/kits.md#sign-and-verify-kits). +[sign and verify kits](../customize/kits-v2.md#sign-and-verify-kits). #### kit.trustedSigners {.wrap-anywhere} diff --git a/content/manuals/ai/sandboxes/customize/_index.md b/content/manuals/ai/sandboxes/customize/_index.md index 94e3434250..b73a5ee66f 100644 --- a/content/manuals/ai/sandboxes/customize/_index.md +++ b/content/manuals/ai/sandboxes/customize/_index.md @@ -1,70 +1,115 @@ --- -title: Customizing sandboxes -linkTitle: Customize -description: Build reusable sandbox images and extend or define agents using templates and kits. -keywords: sandboxes, sbx, customize, templates, kits, mixins, custom agents +title: Kits +description: Use sandbox kits and share environments as kit sets composed from workloads and mixins. +keywords: sandboxes, sbx, kits, v3, workloads, mixins weight: 90 +linkTitle: Kits aliases: - /ai/sandboxes/agents/custom-environments/ -params: - sidebar: - badge: - color: blue - text: Early Access --- {{< summary-bar feature_name="Docker Sandboxes sbx" >}} -Docker Sandboxes offers two ways to customize a sandbox beyond the built-in -defaults: +Kits let you shape a sandbox around the way you work. Use a custom base image, +add the tools your project needs, and give your agent instructions for using +them. You also control which services the sandbox can access, how it +authenticates, and what runs when the sandbox starts. -- [Templates](templates.md) — reusable sandbox images with tools, packages, - and configuration baked in. Extend a base image with a Dockerfile, or - save a running sandbox as a template. -- [Kits](kits.md) — declarative YAML artifacts that extend an agent with - tools, credentials, network rules, and files at runtime, or define a new - agent from scratch. +A kit can define the whole environment or add something to an existing one, +such as a toolchain or your team's shared configuration. Package those choices +once, then reuse them across projects and share them with your team. -Kits are experimental. The kit file format, CLI commands, and experience for -creating, loading, and managing kits are subject to change as the feature -evolves. Share feedback and bug reports in the -[docker/sbx-releases](https://github.com/docker/sbx-releases) repository. +This page covers v3 kits, which require `sbx` v0.45 or later. See +[Version compatibility](#version-compatibility) for compatibility with earlier +kit formats. -## Templates and kits, side by side +## What is a kit? -A template is a Docker image that the sandbox runs. It's built ahead -of time with a Dockerfile (or saved from a running sandbox), pushed to a -registry, and pulled when a sandbox is created. Use templates for things -that belong in an image: system packages, language toolchains, large -dependencies — anything you'd rather not reinstall on every sandbox start. +A kit packages software and configuration for a sandbox. A YAML file, called +its descriptor, tells Docker Sandboxes what the kit needs: network access, +credentials, setup commands, or instructions for the agent. You publish the +kit as a container image containing its files and descriptor. -A kit is a YAML artifact applied at sandbox creation. The kit can run -install commands, drop files into the sandbox, declare network and -credential rules, and (for sandbox kits) define which template image the -agent runs in. Use kits for things that vary per agent or per team: -shared linter config, project-specific install steps, credential -injection for a service the agent talks to. +You identify a published kit by its container image reference, such as +`me/my-kit:latest`. When you use the kit, `sbx` prepares its files and applies +its settings. You can use one kit for a complete environment or combine kits +that contribute different parts. -Templates and kits work together. A sandbox kit's `sandbox.image` field -points at a template: the template provides the base environment, the -kit layers config, secrets, and runtime behavior on top. A team can ship -one heavy template and several thin kits without rebuilding the image -each time something changes. +## What kits can do -## When to use which +Use kits to: -| Goal | Option | -| --------------------------------------------------------- | ------------------------------------------------------------- | -| Pre-install tools and packages into a reusable base image | [Template](templates.md) | -| Capture a configured running sandbox for reuse | [Saved template](templates.md#saving-a-sandbox-as-a-template) | -| Add a tool, credential, or config to agent runs via YAML | [Kit (mixin)](kits.md) | -| Define a new agent from scratch | [Kit (sandbox)](kits.md#define-an-agent) | +- Package a custom agent, or configure an existing agent for your team's + projects. +- Include the tools the agent needs, such as linters, language runtimes, + test runners, and compilers. +- Share linter rules, editor settings, helper scripts, and reference material. + Give the agent instructions and skills for using them. +- Connect the agent to services through network rules and credentials, + including internal APIs and private package registries. +- Initialize each sandbox and run supporting services when it starts, such + as a development server for previewing the agent's work. -Templates and kits can be used together. A template bakes heavy tools into -the image for fast sandbox startup; a kit layered on top adds per-run -credentials, config, or extra capabilities. +## Workloads and mixins -## Tutorials +Kits have two roles in a sandbox: a workload supplies the base environment +and launch command, and mixins add tools or behavior to it. -- [Build your own agent kit](build-an-agent.md) — step-by-step walkthrough - for packaging [Amp](https://ampcode.com/) as a sandbox kit. +| Kind | What it supplies | How you use it | +| --- | --- | --- | +| `workload` | The environment and command to run, such as an agent or a shell | Pass it to `sbx run` or `sbx create` | +| `mixin` | Additional tools, configuration, or runtime behavior | Add it with `--kit` | + +For example, this command runs a workload with a mixin: + +```console +$ sbx run me/my-agent-kit:latest --kit me/my-mixin:latest +``` + +The workload supplies the environment and launch command. The mixin adds its +tools and configuration to that environment. + +## Kit sets + +A kit set combines kits into a single kit that you can publish and reuse. +Use it to package a workload with the mixins you need, so you and your team +can run the environment from one reference. + +The set specifies which kits and versions to combine. It can also add setup +commands, agent instructions, network access, and other settings for the +combined environment. + +If the set includes a workload, you run the published kit with `sbx run`. +If it contains only mixins, you add it to a workload with `--kit`. + +See [Use kits](/manuals/ai/sandboxes/customize/use-kits.md) for how to run kits +and add mixins. To customize and publish your own combination, see +[Compose a kit set](/manuals/ai/sandboxes/customize/author/kit-sets.md). + +## Version compatibility + +V3 kits cannot be combined with v1 or v2 kits in the same sandbox. To use +v3, select a v3 workload and use v3 for every mixin you add. + +The built-in agent names, such as `claude` and `codex`, select v2 kits. +You can't add a v3 mixin to these built-ins. For example, +`sbx run claude --kit ./some-v3-mixin` fails because it mixes kit versions. +Instead, select a v3 workload by its published image, local path, or Git +reference, as shown in [Run a kit](/manuals/ai/sandboxes/customize/use-kits.md#run-a-kit). + +V2 remains supported, including the built-in agents and +existing v2 customizations. See [Kits v2](/manuals/ai/sandboxes/customize/kits-v2.md) for maintenance +and migration guidance. + +## Choose your next step + +- [Use kits](/manuals/ai/sandboxes/customize/use-kits.md) to run a published environment or combine + a workload with mixins. +- [Author kits](/manuals/ai/sandboxes/customize/author/_index.md) to build an agent environment, + package a tool, or combine kits into a set to share with your team. +- Explore the [sandbox-kit-spec repository](https://github.com/docker/sandbox-kit-spec) + for the authoritative v3 specification, build frontend, and examples. + +For the earlier format used by built-in agents, see [Kits v2](/manuals/ai/sandboxes/customize/kits-v2.md). +To save an environment you've configured inside a sandbox, +see [Save a sandbox as a template](/manuals/ai/sandboxes/usage.md#saving-a-sandbox-as-a-template). diff --git a/content/manuals/ai/sandboxes/customize/author/_index.md b/content/manuals/ai/sandboxes/customize/author/_index.md new file mode 100644 index 0000000000..c0c4d0d203 --- /dev/null +++ b/content/manuals/ai/sandboxes/customize/author/_index.md @@ -0,0 +1,188 @@ +--- +title: Author kits +description: Build and share sandbox environments with kits. Choose a tutorial, organize your source files, and decide what happens during build and setup. +keywords: sandboxes, sbx, kits, v3, workloads, mixins +weight: 20 +--- + +{{< summary-bar feature_name="Docker Sandboxes sbx" >}} + +Build a kit to give your team a repeatable sandbox environment. You can +package an agent, add a tool to use with different agents, or combine existing +kits into one kit your team can run. The guides in this section walk through +each approach. + +> [!NOTE] +> Select a v3 workload and v3 mixins together. +> Built-in shortcuts such as `claude` and `codex` use v2 and can't be combined +> with v3 mixins. See [Version compatibility](/manuals/ai/sandboxes/customize/_index.md#version-compatibility) +> or the [v2 reference](/manuals/ai/sandboxes/customize/kits-v2.md). + +## Choose what to author + +- [Compose a kit set](/manuals/ai/sandboxes/customize/author/kit-sets.md) to combine + kits you've published or chosen from a registry. A set can also add network + access, setup commands, and agent instructions, and let users choose settings + such as which model to use. +- [Build a tool mixin](/manuals/ai/sandboxes/customize/author/tool-mixins.md) to + package a reusable tool with its network access and credentials. +- [Build an agent workload](/manuals/ai/sandboxes/customize/author/build-an-agent.md) + to control the base environment, agent installation, and launch command. + You can also [use an existing agent image](/manuals/ai/sandboxes/customize/author/base-images.md#use-an-image-in-a-v3-workload). + +For complete kits you can study and adapt, see +[Kit examples](https://github.com/docker/sandbox-kit-spec/tree/main/examples) +in the Docker Sandbox Kit Specification repository. + +## Directory and build layout + +Keep each kit's source in its own directory. A kit usually starts with two +files: + +- A YAML descriptor identifies the kit as a workload, mixin, or set and + declares its settings and requirements. +- A Dockerfile installs software and copies files into the image. + +Use the kit's name for the directory and descriptor. If the kit has a +Dockerfile, use the same filename stem as the descriptor: `my-kit.yaml` +pairs with `my-kit.dockerfile`. + +For example: + +```text +my-kit/ +├── my-kit.yaml +├── my-kit.dockerfile +├── context.md +└── files/ + └── settings.json +``` + +Organize supporting files in whatever way suits your kit. This example keeps +agent instructions in `context.md` and configuration files under `files/`. + +### How the files work together + +The Dockerfile defines what goes into the image, such as installed tools +and configuration files. For a workload, it also sets the command to launch. +The YAML descriptor defines the kit's settings and requirements, such as +network access, credentials, and agent instructions. + +The descriptor starts with a syntax declaration: + +```yaml +# syntax=docker/sandbox-kit:3 +``` + +This selects the kit build frontend, which reads the descriptor and its +matching Dockerfile. The build produces a container image containing the +software, supporting files, and validated descriptor. + +A kit set uses the descriptor's `kits:` list to combine published kits. + +### Build and use the kit + +When building with Docker Buildx, pass the YAML descriptor to `-f` and +the source directory as the build context: + +```console +$ docker buildx build -f my-kit/my-kit.yaml -t my-kit:dev my-kit/ +``` + +You can also give `sbx` a reference to a local kit directory. It builds the kit +when creating the sandbox. After publishing the image to a registry, you can +use its image reference instead. + +For build options and publishing instructions, see +[Build and distribute kits](/manuals/ai/sandboxes/customize/author/distribute.md). + +### Other source layouts + +The separate descriptor and Dockerfile are one way to organize a kit. +You can also write a Dockerfile inline under `build: |`, select one with +`dockerfile:`, or embed the descriptor in a Dockerfile comment. + +See [Authoring forms](https://github.com/docker/sandbox-kit-spec/blob/main/docs/spec/SPEC-v3.md#3-authoring-forms) +for the syntax. + +## Capabilities + +Installing a tool is often only part of the job. The tool might also need to +reach an API, authenticate with a credential, or run a setup command before +the agent starts. Describe those needs in the descriptor's `capabilities` +list. Each entry asks Docker Sandboxes to provide one of these features. + +A kit's Dockerfile defines how its image is built. Its capabilities describe +what Docker Sandboxes needs to do when preparing and running the sandbox. +For example, a tool mixin can install an API client through its Dockerfile +and use a network capability to request access to that API. Building or +running the image with Docker alone doesn't apply these capability settings. + +You can add capabilities to a workload, mixin, or set. Keep each request with +the kit that needs it, so a tool's access rules follow it when you use it with +another agent. + +Each capability entry identifies the feature in `type`. Capabilities that +need settings take them in `config`. For example, `com.docker.sandbox/network-policy@1` +requests network access, and its `config` lists the domains to allow. + +The `@1` identifies the capability's version. It is independent of the kit +format version and the `sbx` release. The +[upstream capability definitions](https://github.com/docker/sandbox-kit-spec/blob/main/docs/spec/SPEC-v3.md#72-well-known-types) +describe the available capabilities and their settings. + +> [!NOTE] +> `sbx` doesn't apply `usb-device@1`, `privileged@1`, or `agent-sessions@1` +> requests. Its capability enforcement can let sandbox creation succeed even +> when a required capability is unsupported. Don't rely on this behavior: +> choose capabilities supported by the runtime where your kit will run. +> The `kit-registry@1` capability is restricted to approved OCI builder kits; +> local and Git kit sources don't receive it. + +The guides here show how to use capabilities with Docker Sandboxes. For all +descriptor fields and the rules for combining kits, see the +[upstream v3 specification](https://github.com/docker/sandbox-kit-spec/blob/main/docs/spec/SPEC-v3.md). + +## Choose when setup runs + +Install tools and copy static files during the image build so you can reuse +them in every sandbox. Some setup needs to wait until the sandbox exists. For +example, a mixin can bring a CA certificate, but it needs the workload's tools +to register that certificate. Use a lifecycle capability to run commands or +generate files at the right point: + +| Where to put the work | When it runs in `sbx` | Example | +| --- | --- | --- | +| Dockerfile `RUN` and `COPY` | Image build | Install a tool and copy its default configuration | +| Lifecycle `install` hooks | Once during sandbox creation, before the agent launches | Register a CA or populate a mounted directory | +| Lifecycle `files` | During creation, after install hooks and before the agent launches | Generate settings from kit arguments | +| Lifecycle `startup` hooks | Every sandbox start, alongside the agent | Start a background service or refresh state after a restart | + +Lifecycle hooks are commands that run during sandbox creation or startup. +Make startup hooks safe to run more than once. In `sbx`, they run alongside +the agent, so the agent might start before they finish. If a command must +finish before every agent launch, put it in the workload's entrypoint instead. + +### Pass environment variables to hooks + +In `sbx`, install hooks receive a limited set of environment variables: +basic process variables, proxy settings, and certificate paths. If your command needs another +variable, name it in the hook's `env` list. For example, `env: [WORKSPACE_DIR]` +gives the command the mounted workspace's path. In `sbx`, startup hooks receive +the sandbox's environment without this filtering. + +See [Kit authoring patterns](/manuals/ai/sandboxes/customize/author/patterns.md#run-setup-after-combining-kits) +for setup examples and the upstream +[lifecycle definition](https://github.com/docker/sandbox-kit-spec/blob/main/docs/spec/capabilities/com.docker.sandbox/lifecycle@1.md) +for the fields. + +## Set workload compute requirements + +Set the workload's default CPU and memory allocation with the +[`resources@1` capability](https://github.com/docker/sandbox-kit-spec/blob/main/docs/spec/capabilities/com.docker.sandbox/resources@1.md) +in its descriptor. Use a whole number of CPU cores. Anyone running the kit +can override these defaults with `--cpus` and `--memory` when creating a sandbox. + +Put these settings on the workload. `sbx` ignores resource settings on +mixins added separately, and it doesn't use the capability's `gpu` field +to select GPUs. diff --git a/content/manuals/ai/sandboxes/customize/author/base-images.md b/content/manuals/ai/sandboxes/customize/author/base-images.md new file mode 100644 index 0000000000..a66065d754 --- /dev/null +++ b/content/manuals/ai/sandboxes/customize/author/base-images.md @@ -0,0 +1,190 @@ +--- +title: Base images for sandbox workloads +linkTitle: Base images +weight: 10 +description: Choose a Docker-provided agent image or your own Linux base image for a sandbox workload kit. +keywords: sandboxes, sbx, kits, base images, templates, dockerfile, custom agents +aliases: + - /ai/sandboxes/customize/templates/ +--- + +{{< summary-bar feature_name="Docker Sandboxes sbx" >}} + +A base image gives your workload its operating system and starting set of +tools. Docker provides images with agents already installed. You can also start +from another Linux image and prepare it yourself. Choose the base image in your +workload's Dockerfile. Use the kit descriptor to configure network access, +credentials, and other sandbox behavior. A kit set uses the base image from its +workload. + +To save and reuse an environment you've configured interactively, see +[Save a sandbox as a template](/manuals/ai/sandboxes/usage.md#saving-a-sandbox-as-a-template). + +## Docker-provided images + +Docker's sandbox templates are published as +`docker/sandbox-templates:`. They are based on Ubuntu and run as a +non-root `agent` user with sudo access. Most variants include Git, Docker +CLI, and common development tools like Node.js, Python, Go, and Java. + +| Variant | Agent | +| --------------------- | -------------------------------------------------------------------- | +| `claude-code` | [Claude Code](https://claude.ai/download) | +| `claude-code-minimal` | Claude Code with a minimal toolset (no Node.js, Python, Go, or Java) | +| `codex` | [OpenAI Codex](https://github.com/openai/codex) | +| `copilot` | [GitHub Copilot](https://github.com/github/copilot-cli) | +| `cursor-agent` | [Cursor](https://cursor.com/cli) | +| `devin` | [Devin CLI](https://docs.devin.ai/work-with-devin/devin-cli) | +| `docker-agent` | [Docker Agent](https://github.com/docker/docker-agent) | +| `droid` | [Droid](https://www.factory.ai) | +| `gemini` | [Gemini CLI](https://github.com/google-gemini/gemini-cli) | +| `kiro` | [Kiro](https://kiro.dev) | +| `opencode` | [OpenCode](https://opencode.ai) | +| `shell` | No agent pre-installed. Use for manual agent setup. | + +## Use an image in a v3 workload + +Start your workload's Dockerfile with `FROM`, then add the tools and +configuration you need. Install system packages as `root`, and switch back +to `agent` before installing tools in the agent's home directory. Running +those installers as `root` puts files under `/root/`, where the agent can't +use them. + +### What the base image provides + +`FROM` inherits the image's files and settings. If the image is also a +published kit, its capabilities don't carry over. Declare network access, +credentials, storage, and hooks in your own descriptor. To keep an existing +kit's capabilities and add tools, [compose a kit set](/manuals/ai/sandboxes/customize/author/kit-sets.md). + +Your descriptor determines the kit format version. A v3 descriptor creates +a v3 kit, including when you use a Docker template image as its base. See +[Version compatibility](/manuals/ai/sandboxes/customize/_index.md#version-compatibility). + +### Package an existing agent image + +This example packages Docker's OpenCode image as a v3 workload. The image +already has an agent installed, so you only need to choose its launch command +and describe what it needs to run. You can run the resulting kit directly or +include it in a set with additional tools. + +Create a directory with these two files: + +```text +opencode-workload/ +├── opencode-workload.yaml +└── opencode-workload.dockerfile +``` + +The Dockerfile selects the base image and tells Docker Sandboxes to run +OpenCode as the `agent` user: + +```dockerfile {title="opencode-workload/opencode-workload.dockerfile"} +FROM docker/sandbox-templates:opencode +USER agent +ENTRYPOINT ["opencode"] +CMD [] +``` + +The template supplies OpenCode, Python, uv, and the `agent` user. Create a +YAML descriptor to identify this as a workload and declare what OpenCode +needs: network access, an Anthropic API key, and instructions about its +environment: + +```yaml {title="opencode-workload/opencode-workload.yaml"} +# syntax=docker/sandbox-kit:3 +schemaVersion: "3" +kind: workload + +capabilities: + - type: com.docker.sandbox/sbx@1 + - type: com.docker.sandbox/network-policy@1 + config: + runtime: + allow: + - api.anthropic.com + - opencode.ai + - models.dev + - registry.npmjs.org + - pypi.org + - files.pythonhosted.org + - type: com.docker.sandbox/credential@1 + config: + service: anthropic + phase: runtime + apiKey: + name: ANTHROPIC_API_KEY + proxyManaged: true + inject: + - domain: api.anthropic.com + header: x-api-key + format: "%s" + - type: com.docker.sandbox/agent-context@1 + config: + filename: AGENTS.md + content: | + OpenCode runs as the agent user. Python and uv are available. + Use the project's environment and dependency configuration. +``` + +The credential entry names the service and describes how to authenticate API +requests. Store the actual API key on your host. + +`sbx` can build this directory when you create a sandbox. The result is a +container image with the kit's files and descriptor, which you can also +publish to a registry for others to use. + +## Use your own Linux image + +If you need a different operating system or set of packages, start from a +Linux image of your choice. You'll need to add the tools and user account +that Docker Sandboxes expects, then install your agent. + +The following requirements help you prepare that image. For a step-by-step +example, follow [Build an agent workload](/manuals/ai/sandboxes/customize/author/build-an-agent.md). + +### Base image requirements + +Prepare your image with the following: + +- Tools: Include `curl`, `git`, and trusted CA certificates for accessing + source repositories and making HTTPS requests. +- Shells: Provide executable `/bin/sh` and `/bin/bash` files for setup commands + and agent launch. +- User account: Create a non-root `agent` account with UID 1000 and home + directory `/home/agent`. Add the account to `/etc/passwd` and set `USER + agent` in the image. +- Launch command: Set `ENTRYPOINT` or `CMD` to the agent or shell you want the + sandbox to launch. + +Docker Sandboxes uses the account's entry in `/etc/passwd` to determine +the user ID, group ID, and home directory when running commands and writing +files. + +For a sandbox with a mounted workspace, `WORKDIR` doesn't choose the mount +location. For a sandbox without a mounted workspace, `sbx` uses the image's +absolute `WORKDIR` as the working directory. If the image doesn't specify a +usable absolute path, `sbx` falls back to `/home/agent/workspace`. + +### Declare the agent launch contract + +`sbx` keeps the sandbox running and starts the agent as a separate process, +using the image's launch command. The `com.docker.sandbox/sbx@1` capability +declares that your workload is prepared to run this way: + +```yaml +capabilities: + - type: com.docker.sandbox/sbx@1 +``` + +This capability takes no `config` and doesn't request extra permissions. It +lets the upstream conformance tests check that your image meets the shell and +user account requirements before you publish. + +The host launches the agent through non-interactive Bash. To load persistent +environment settings at launch, set `BASH_ENV` to an absolute path and include +that file in the image. Bash reads this file instead of login profiles or +`.bashrc`. + +For the complete contract, see the upstream +[`sbx@1` definition](https://github.com/docker/sandbox-kit-spec/blob/main/docs/spec/capabilities/com.docker.sandbox/sbx@1.md). diff --git a/content/manuals/ai/sandboxes/customize/author/build-an-agent.md b/content/manuals/ai/sandboxes/customize/author/build-an-agent.md new file mode 100644 index 0000000000..68f1978d37 --- /dev/null +++ b/content/manuals/ai/sandboxes/customize/author/build-an-agent.md @@ -0,0 +1,419 @@ +--- +title: Build an agent workload +linkTitle: Build an agent workload +description: Build a schema v3 agent workload from your own Linux base image, prepare its sandbox environment, and configure credentials and agent instructions. +keywords: sandboxes, sbx, kits, agent, tutorial, claude, workload, build +weight: 20 +aliases: + - /ai/sandboxes/customize/build-an-agent/ +--- + +{{< summary-bar feature_name="Docker Sandboxes sbx" >}} + +Build a kit that runs Claude Code on a Linux base image of your choice. +You'll install the agent, give it access to the Anthropic API, and add model +settings and instructions for your team. The result is a v3 workload kit you +can run locally or publish for others to use. You can follow the same steps +for other agents or your organization's own base images. + +This tutorial prepares the whole environment, from system packages to the +command that starts the agent. If you already have a suitable agent image, +see [Package an existing agent image](/manuals/ai/sandboxes/customize/author/base-images.md#package-an-existing-agent-image). +To combine a published agent kit with tools, [author a kit set](/manuals/ai/sandboxes/customize/author/kit-sets.md). + +If you're starting with kits, read [Author kits](/manuals/ai/sandboxes/customize/author/_index.md) +for an introduction to the files you'll create. Field definitions are in the +[upstream v3 specification](https://github.com/docker/sandbox-kit-spec/blob/main/docs/spec/SPEC-v3.md). + +## Prepare the kit directory + +You need `sbx`, Docker with Buildx, and an Anthropic +API key. Create a directory beside the project you want the agent to work on: + +```console +$ mkdir claude-team +``` + +The completed directory contains three files: + +```text +claude-team/ +├── claude-team.yaml +├── claude-team.dockerfile +└── context.md +``` + +The Dockerfile installs the agent and sets the command to run it. The YAML +file, called the descriptor, tells Docker Sandboxes what the agent needs to +run, such as network access and credentials. The Markdown file contains +instructions for the agent. Give the YAML file and Dockerfile the same name +before the extension so the build can find both files. + +This kit uses v3 and is independent of the built-in `claude` kit, which uses +v2. Any mixins you add must also use v3. To customize the built-in kit, see +[Kits v2](/manuals/ai/sandboxes/customize/kits-v2.md). + +## Use your own base image + +This tutorial starts from Red Hat Universal Base Image (UBI) 9. The following +steps add the tools, user account, and certificates the sandbox needs. You can +use another Linux image, including one maintained by your organization. +Adjust the package and account commands for that image, following the same +[base image requirements](/manuals/ai/sandboxes/customize/author/base-images.md#base-image-requirements). + +### Install the system packages + +Create `claude-team/claude-team.dockerfile` with the base image and packages: + +```dockerfile {title="claude-team/claude-team.dockerfile"} +FROM registry.access.redhat.com/ubi9/ubi:9.8 + +USER root +RUN dnf install -y bash ca-certificates curl-minimal git shadow-utils tar gzip \ + && dnf clean all +``` + +Bash runs shell commands, Git accesses source repositories, and curl uses +the CA certificates to make HTTPS requests. The remaining packages create +the agent's user account and unpack its installer. Add any compilers, +libraries, or other tools your projects need here. + +### Create the agent account + +The sandbox needs a non-root `agent` user with UID 1000 and home directory +`/home/agent`. Append the following to the Dockerfile to create that account +and writable directories for its workspace, configuration, and state: + +```dockerfile {title="Append to claude-team/claude-team.dockerfile"} +RUN groupadd --gid 1000 agent \ + && useradd --uid 1000 --gid 1000 --create-home --shell /bin/bash agent \ + && mkdir -p /home/agent/workspace /home/agent/.local/bin \ + /home/agent/.local/share /home/agent/.local/state \ + /home/agent/.config/claude-team /home/agent/.docker/sandbox/locks \ + && chown -R agent:agent /home/agent +``` + +Creating these directories during the build makes the agent their owner +before Docker Sandboxes mounts the workspace and storage. The agent runs +without `sudo` in this example, so install system packages in the Dockerfile. +Use install hooks for setup that depends on an individual sandbox. + +### Prepare certificate trust + +HTTPS requests from the sandbox go through a proxy. Docker Sandboxes adds +the proxy's certificate authority (CA) to the sandbox's trusted certificates +when it starts. UBI keeps its certificates at a different path from the one +`sbx` uses. Copy them to the expected path, then tell tools to use that file +so they trust both public certificates and the proxy: + +```dockerfile {title="Append to claude-team/claude-team.dockerfile"} +RUN update-ca-trust \ + && mkdir -p /usr/local/share/ca-certificates /etc/ssl/certs \ + && cp /etc/pki/tls/certs/ca-bundle.crt /etc/ssl/certs/ca-certificates.crt + +ENV SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt \ + CURL_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt \ + REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt \ + NODE_EXTRA_CA_CERTS=/etc/ssl/certs/ca-certificates.crt +``` + +If you add corporate CA certificates during the build, add them to +`/etc/pki/ca-trust/source/anchors/` before running `update-ca-trust` and +copying the bundle. For another distribution, use its certificate management +command and source bundle path. + +### Prepare the shell environment + +An environment variable exported in one shell isn't automatically available +in another. Give the agent a file where it can save variables for later +shell sessions. The following lines create that file and arrange for login, +interactive, and non-interactive Bash shells to read it: + +```dockerfile {title="Append to claude-team/claude-team.dockerfile"} +RUN touch /etc/sandbox-persistent.sh \ + && chown agent:agent /etc/sandbox-persistent.sh \ + && chmod 0644 /etc/sandbox-persistent.sh \ + && printf '%s\n' '. /etc/sandbox-persistent.sh' \ + > /etc/profile.d/sandbox-persistent.sh \ + && printf '%s\n' '. /etc/sandbox-persistent.sh' >> /home/agent/.bashrc + +ENV HOME=/home/agent \ + PATH="/home/agent/.local/bin:${PATH}" \ + BASH_ENV=/etc/sandbox-persistent.sh +``` + +`BASH_ENV` tells non-interactive Bash to read the file. You'll include +instructions for the agent to use it later in the tutorial. + +## Build the agent into the image + +Append the following to the Dockerfile to install Claude Code as `agent` and +set its launch command: + +```dockerfile {title="Append to claude-team/claude-team.dockerfile"} +USER agent +ENV CLAUDE_ENV_FILE=/etc/sandbox-persistent.sh \ + IS_SANDBOX=1 +ARG CLAUDE_VERSION +RUN curl -fsSL https://claude.ai/install.sh -o /tmp/install-claude.sh \ + && bash /tmp/install-claude.sh "${CLAUDE_VERSION}" \ + && rm /tmp/install-claude.sh + +WORKDIR /home/agent/workspace +ENTRYPOINT ["claude", "--settings", "/home/agent/.config/claude-team/settings.json"] +CMD [] +``` + +Installing as `agent` puts Claude Code under `/home/agent/`, where that user +can access it. `CLAUDE_ENV_FILE` points Claude Code to the file you prepared +for persistent environment variables. You'll set `CLAUDE_VERSION` in the +descriptor in the next step. + +The Dockerfile also sets the user, working directory, environment variables, +and launch command. `CMD []` clears any arguments inherited from the base +image. The `--settings` option loads the model you choose for each sandbox. +You'll create its settings file in [Write the model settings](#write-the-model-settings). + +Each sandbox created from this image gets the same Claude Code binary. +The next steps configure how Docker Sandboxes runs it. Any mixins you add +must use v3 and contain tools compatible with this workload's operating +system and architecture. + +## Describe the workload and its inputs + +Create `claude-team/claude-team.yaml`. Start by identifying the workload and +declaring two arguments: + +- `version` selects the Claude Code version to install during the image build. +- `model` selects the model to use when creating a sandbox. + +```yaml {title="claude-team/claude-team.yaml"} +# syntax=docker/sandbox-kit:3 +schemaVersion: "3" +kind: workload +displayName: Team Claude Code +description: Claude Code with team defaults and API-key authentication + +args: + version: + default: "2.1.278" + pattern: '^[0-9]+\.[0-9]+\.[0-9]+$' + buildArg: CLAUDE_VERSION + model: + default: sonnet + enum: [sonnet, opus, haiku] + +provides: ["claude@${{ kit.args.version }}"] +``` + +`version` sets the Dockerfile's `CLAUDE_VERSION` build argument. The build +checks the version against `pattern`, then includes it in `provides` so +other kits can check which Claude Code version is installed. + +`model` lets you choose a model when creating each sandbox. The choice goes +into a settings file, so it doesn't change the installed agent. + +## Allow access to the API + +With the agent installed, the next step is to give it access to the Anthropic +API. Add a `capabilities` list at the top level of `claude-team.yaml`, after +`provides`: + +```yaml {title="Add to claude-team/claude-team.yaml"} +capabilities: + - type: com.docker.sandbox/sbx@1 + - type: com.docker.sandbox/network-policy@1 + config: + runtime: + allow: + - api.anthropic.com:443 +``` + +The network rule permits HTTPS requests to the Anthropic API while the +sandbox runs. Downloading Claude Code in the Dockerfile uses the builder's +network, so it doesn't need a rule here. + +The `sbx@1` entry declares that the workload is prepared for `sbx` to manage +the agent's launch. See [Declare the agent launch contract](/manuals/ai/sandboxes/customize/author/base-images.md#declare-the-agent-launch-contract) +for the shells and user account that this requires. + +## Declare the credential + +Claude Code can reach the API, but it also needs to authenticate. Add a +credential capability to tell Docker Sandboxes which key to use and how to +include it in requests. You'll store the key on your host, outside the kit. + +Append this entry to the same `capabilities` list: + +```yaml {title="Append under capabilities"} + - type: com.docker.sandbox/credential@1 + description: Anthropic API access + config: + service: anthropic + phase: runtime + apiKey: + name: ANTHROPIC_API_KEY + proxyManaged: true + inject: + - domain: api.anthropic.com + header: x-api-key + format: "%s" +``` + +The sandbox receives a placeholder in `ANTHROPIC_API_KEY`. When Claude Code +makes a request to `api.anthropic.com`, the host proxy inserts the real API +key into the `x-api-key` header. The key stays on the host. You'll supply +its value and approve its use when launching the kit. + +## Write the model settings + +The Dockerfile's launch command reads +`/home/agent/.config/claude-team/settings.json`. Use the lifecycle capability +to create that file with the model chosen for the sandbox. + +Append this entry to `capabilities`: + +```yaml {title="Append under capabilities"} + - type: com.docker.sandbox/lifecycle@1 + config: + files: + - path: /home/agent/.config/claude-team/settings.json + content: | + {"model": "${{ kit.args.model }}"} + mode: "0644" +``` + +Docker Sandboxes fills in the chosen `model` and writes the file before +Claude Code starts. Creating the file at this point lets each sandbox use a +different model with the same image. + +Docker Sandboxes writes these files as UID 1000 after running install hooks. +Use an absolute path the agent can write to, as in this example. Shell +variables such as `$HOME` aren't expanded in the path. + +## Add agent instructions + +The kit can also give Claude Code instructions about the environment. Save the +following Markdown alongside the descriptor and Dockerfile: + +```markdown {title="claude-team/context.md"} +## Team workflow + +Read the project's README before changing code. Run the project's checks +before reporting a task complete, and report any checks you couldn't run. + +Claude Code is installed in this sandbox. Its additional settings are at +`/home/agent/.config/claude-team/settings.json`. + +Use `/etc/sandbox-persistent.sh` for environment exports needed by later +Bash commands. Keep shell completion scripts out of that file because +non-interactive commands also source it. +``` + +Append an agent-context entry to `capabilities` to include these instructions: + +```yaml {title="Append under capabilities"} + - type: com.docker.sandbox/agent-context@1 + config: + filename: CLAUDE.md + contentFile: ./context.md +``` + +The build includes `context.md` in the image. When the sandbox runs, `sbx` +writes a `CLAUDE.md` file in the parent directory of the mounted workspace. +That file points Claude Code to your `context.md`. A `CLAUDE.md` in your +project stays in place. + +Use `contentFile`, as in this example, to keep longer instructions in a +separate Markdown file. You can also write instructions directly in the +workload's descriptor using `content` instead of `contentFile`. +For how instructions from multiple kits work together, see +[Runtime access and instructions](/manuals/ai/sandboxes/customize/use-kits.md#runtime-access-and-instructions). + +## Store the key and run + +Store your Anthropic API key on the host: + +```console +$ sbx secret set anthropic +``` + +From the directory containing `claude-team`, launch the kit: + +```console +$ sbx run --name claude-team ./claude-team +``` + +`sbx` builds the kit, mounts your current directory as the workspace, and +launches Claude Code. To work on another project, append its path to the command. +When prompted, approve the kit's request to use your stored key, then follow +Claude Code's first-run prompts. The agent needs both the stored key and your +approval to use it. See +[Credential bindings](/manuals/ai/sandboxes/configuration/credentials.md#credential-bindings). + +Choose a different model when creating a sandbox: + +```console +$ sbx run --name claude-team-opus ./claude-team \ + --kit-arg claude-team.model=opus +``` + +The `claude-team` prefix matches the local kit directory's name. Docker +Sandboxes checks that `opus` is one of the choices in `enum`, then writes it +to the settings file before Claude Code starts. + +## Iterate and publish + +Edit the descriptor, Dockerfile, or context file and create another sandbox +with a different name to test the changes: + +```console +$ sbx run --name claude-team-test-2 ./claude-team +``` + +Restarting an existing sandbox won't pick up your edits. To try another +agent version locally, update `args.version.default` in the descriptor and +create another sandbox. + +`sbx` reuses the local build when the source files and kit arguments are +unchanged. Changing either can trigger a build, even for arguments such as +`model` that only affect sandbox setup. BuildKit can still reuse unchanged +image layers. + +### Publish the workload + +When the kit is ready to share, sign in to Docker Hub, then build and push it +with Docker Buildx. Replace `` with a Docker Hub namespace you can +push to: + +```console +$ docker login +$ docker buildx build ./claude-team \ + --file ./claude-team/claude-team.yaml \ + --tag docker.io//claude-team:1.0.0 \ + --push +``` + +The `--file` option tells Buildx to read the descriptor. Its `syntax` line +selects the kit frontend, which reads the companion Dockerfile and includes +the descriptor in the published image. To publish a different agent version, +add `--build-arg version=`. This flag uses the kit argument +name, `version`, which the descriptor maps to the Dockerfile's `CLAUDE_VERSION`. + +Run the published kit by its image reference: + +```console +$ sbx run --name claude-team-shared docker.io//claude-team:1.0.0 +``` + +For multi-platform images and distribution details, see +[Build and distribute kits](/manuals/ai/sandboxes/customize/author/distribute.md). +To learn how to package a tool separately from its workload, see +[Build a tool mixin](/manuals/ai/sandboxes/customize/author/tool-mixins.md). +That tutorial also packages Claude Code, so use its mixin with a shell workload. +Combining it with this workload would give two kits that provide `claude`, +which Docker Sandboxes rejects. +You can also include the published workload in a +[kit set](/manuals/ai/sandboxes/customize/author/kit-sets.md) and add settings +and instructions there. The workload still defines how to prepare the base +image, install the agent, and launch it. diff --git a/content/manuals/ai/sandboxes/customize/author/distribute.md b/content/manuals/ai/sandboxes/customize/author/distribute.md new file mode 100644 index 0000000000..0d24a9fa1f --- /dev/null +++ b/content/manuals/ai/sandboxes/customize/author/distribute.md @@ -0,0 +1,117 @@ +--- +title: Build and distribute kits +description: Build and publish v3 kit images, share source through Git, and sign images for distribution. +keywords: sandboxes, sbx, kits, v3, workloads, mixins +weight: 40 +--- + +{{< summary-bar feature_name="Docker Sandboxes sbx" >}} + +Once you've [authored a kit](/manuals/ai/sandboxes/customize/author/_index.md), +share it by publishing an image to a registry or its source to Git. +Publishing an image saves others from building the kit themselves. Sharing +the source lets them build it when they create a sandbox. Either way, `sbx` +reads the kit's descriptor to configure the sandbox. + +This page shows how to publish and sign v3 kits. To run a kit someone else has +shared, see [Use kits](/manuals/ai/sandboxes/customize/use-kits.md). + +## Publish an image + +Use Docker Buildx to build and publish your kit as an OCI image. Pass the YAML +descriptor with `-f` and the source directory as the build context: + +```console +$ docker login +$ docker buildx build ./my-kit -f ./my-kit/my-kit.yaml \ + -t docker.io//my-kit:1.0.0 --push +``` + +Replace `` with a Docker Hub namespace you can push to. Buildx +uses your `docker login` credentials to push the image. + +Push the image before running it by its registry reference. `sbx` pulls the +published image. It can't use images stored only in your host's Docker image +store. During development, you can pass a local source directory to `sbx` +instead. For private images, configure +[registry credentials](/manuals/ai/sandboxes/configuration/credentials.md#registry-credentials) +for your sandbox. + +Use Buildx for v3 kits. The `sbx kit pack`, `push`, and `pull` commands are +for v1 and v2 kits. + +### Support both Linux architectures + +To share the kit with people who use different machines, build for both +supported Linux architectures: + +```console +$ docker buildx build ./my-kit -f ./my-kit/my-kit.yaml \ + --platform linux/amd64,linux/arm64 \ + -t docker.io//my-kit:1.0.0 --push +``` + +## Publish a kit set + +Publish a set with the same Buildx command, passing its YAML descriptor with +`-f`. The build fetches the published images listed in `kits:`, checks whether +their declarations are compatible, and combines their files and settings into +one image. See +[Compose a kit set](/manuals/ai/sandboxes/customize/author/kit-sets.md) for a complete example. + +The result is a workload or mixin image that people can use directly. It +records each component's manifest digest, which identifies the exact image +used in the build. Updating a component's tag doesn't change a published +set. To share the update, rebuild the set and publish another version. +If you want rebuilds to use the same component images, add a `digest` beside +each `ref` in `kits:`. + +## Share source through Git + +Commit the kit's source directory to a Git repository, then share a reference +in this format. Use `dir` to select the kit directory and `ref` to select the +commit: + +```text +git+https://github.com//.git#ref=&dir=my-kit +``` + +When someone creates a sandbox from that reference, `sbx` builds the kit +from the selected commit. + +## Sign and verify kits + +Sign your published image so others can verify who signed it: + +```console +$ sbx kit sign docker.io//my-kit:1.0.0 +$ sbx kit verify docker.io//my-kit:1.0.0 \ + --certificate-identity \ + --certificate-oidc-issuer +``` + +These commands use Sigstore signatures, which are compatible with Cosign. +The example signs without a key, so verification needs the signer's certificate +identity and OpenID Connect issuer. To sign with a key instead, pass +`--key cosign.key` to `sign` and `--key cosign.pub` to `verify`. + +To require a valid signature before using a kit, see +[Verify kit signatures](/manuals/ai/sandboxes/customize/use-kits.md#verify-kit-signatures). + +V3 kits shared as source directories or Git references can't be signed. +If you need signatures, publish and sign an OCI image. + +## Published format + +A published kit image contains both the kit's content and its descriptor. +Docker image tools can inspect and distribute it, and Docker Sandboxes reads +the descriptor when creating the sandbox. + +You can also inspect the descriptor inside the sandbox, under +`/usr/share/sandbox/kit//`. +For the image annotations and file layout, see +[Published image format](https://github.com/docker/sandbox-kit-spec/blob/main/docs/spec/SPEC-v3.md#10-the-oci-layout). + +Use `sbx` to run a workload with the settings and hooks declared in its kit +descriptor. Running it with `docker run` uses only the image configuration, +so those settings and hooks aren't applied. diff --git a/content/manuals/ai/sandboxes/customize/author/kit-sets.md b/content/manuals/ai/sandboxes/customize/author/kit-sets.md new file mode 100644 index 0000000000..712d09b0b8 --- /dev/null +++ b/content/manuals/ai/sandboxes/customize/author/kit-sets.md @@ -0,0 +1,244 @@ +--- +title: Compose a kit set +description: Combine published workloads and mixins into a kit set, configure shared settings and arguments, and publish it for your team. +keywords: sandboxes, sbx, kits, v3, sets, composition, workloads, mixins +weight: 5 +--- + +{{< summary-bar feature_name="Docker Sandboxes sbx" >}} + +A kit set gives your team one kit to run, with the tools and versions you've +chosen. You list the kits to include, add any settings the combined environment +needs, and publish the result. A set can also run setup commands, supply agent +instructions, and offer choices such as which model to use. + +Use a set when you want to share a combination of kits and manage its +settings in one place. The components can be kits your team publishes or +kits from other publishers. You need Docker Buildx and a registry namespace +you can push to when publishing the set. + +## Choose the components + +A set can contain one workload and any number of mixins. Together, they +provide a complete sandbox environment. You can also make a set of only +mixins, to share tools and settings that users add to a workload with `--kit`. + +Choose v3 kits that work together. For example, you could combine an agent +workload with a linter mixin and a mixin that adds your team's configuration. +To package a tool of your own, see +[Build a tool mixin](/manuals/ai/sandboxes/customize/author/tool-mixins.md). + +You can try a workload and mixins together with `sbx run` and `--kit` +before composing a set. See +[Add mixins](/manuals/ai/sandboxes/customize/use-kits.md#add-mixins). +If one kit depends on another, Docker Sandboxes applies the dependency first. +Changing the order of `--kit` flags or entries in a set doesn't change that +order. + +## Write the set descriptor + +A set descriptor uses `kind: set` and lists its components under `kits:`. +For example, this descriptor combines Docker's Codex workload with a +mixin: + +```yaml {title="codex-tools/codex-tools.yaml"} +# syntax=docker/sandbox-kit:3 +schemaVersion: "3" +kind: set +displayName: Codex with tools +version: "1.0.0" + +kits: + - ref: docker.io/docker/sbx-kit-codex:0.155.1 + - ref: +``` + +Replace `` with a published v3 mixin's full image reference. +Choose a different workload reference to use another agent or environment. +The components supply their own network rules and credential requests, so +the set doesn't need to repeat them. + +The set gets its software and files from the `kits:` list. It doesn't have a +Dockerfile, a `dockerfile:` field, or a `build:` block. To include more software +or static files, package them in a workload or mixin, publish that kit, and +add it to the list. + +Every `ref` must be a published registry reference. Local paths and Git URLs +aren't accepted as components, even when building the set from local source. + +## Add runtime access to the set + +You can give the combined environment access to services beyond those its +components request. For example, to let the agent download packages from an +internal registry, add this network capability to the set's descriptor: + +```yaml +capabilities: + - type: com.docker.sandbox/network-policy@1 + config: + runtime: + allow: + - packages.company.example:443 +``` + +Replace the example domain with your registry's host. The rule permits access +as long as the sandbox's policy allows it. If the registry also requires +authentication, add a credential request. See +[Services declared by kits](/manuals/ai/sandboxes/configuration/credentials.md#services-declared-by-kits). + +Keep access required by a tool in that tool's kit, so its access rules follow +it when used with another workload. Put settings shared by the combined +environment on the set, such as access to your team's package registry. +You can also add setup commands, generate configuration files, provide +instructions, and define arguments on the set. + +## Build and publish the set + +Before publishing, [check for file conflicts](#check-for-file-conflicts) +between the components. + +Build and publish a set by passing its descriptor to Docker Buildx. +For a descriptor at `codex-tools/codex-tools.yaml`: + +```console +$ docker login +$ docker buildx build ./codex-tools -f ./codex-tools/codex-tools.yaml \ + -t docker.io//codex-tools:1.0.0 --push +``` + +Replace the paths with your set's source directory and descriptor, and +`` with a Docker Hub namespace you can push to. + +The build pulls the listed kits, checks their declared requirements, and +combines their files and settings. It fails if a dependency is missing, two +kits declare the same feature in `provides`, or more than one kit is a workload. + +A set that includes a workload publishes as `kind: workload`. +A set containing only mixins publishes as `kind: mixin`. +Your team can use the result like any other workload or mixin. The published +kit records each component's exact image digest in `kits:`. Only the source +descriptor uses `kind: set`. + +## Run the set + +Run a published set that contains a workload by passing its image reference +to `sbx run`, as you would for an individual workload: + +```console +$ sbx run --name my-project +``` + +The sandbox includes the workload and all the mixins packaged in the set. +You don't need to list those mixins separately with `--kit`. + +For a set containing only mixins, add it to a workload with `--kit`: + +```console +$ sbx run --kit --name my-project +``` + +Authentication depends on the kits in the set. Check their documentation for +required credentials, store those credentials on the host, and approve access +when prompted. See +[Credential configuration](/manuals/ai/sandboxes/configuration/credentials.md) +for authentication options and preparing unattended runs. + +To control the agent's base image or launch command, see +[Build an agent workload](/manuals/ai/sandboxes/customize/author/build-an-agent.md). + +## Configure component arguments + +You can let your team change a setting without changing which kits are +included. For example, they might need to choose whether a linter checks or +fixes files while using the linter version you've selected. + +A set controls which component arguments users can change. You can fix an +argument's value when publishing the set, or expose it as an argument on the +set so users can choose a value when creating a sandbox. + +After changing the argument definitions in the descriptor, rebuild and publish +the set. + +### Fix an argument's value + +Suppose you have a linter kit with a `mode` argument that users normally set +when creating a sandbox. Add it to the set with a fixed value of `check`: + +```yaml +kits: + - ref: docker.io/my-org/linter-kit:1.0.0 + args: + mode: check +``` + +This excerpt fixes the linter's `mode` to `check` when you publish the set. +Use your linter's image reference and argument name. Other components in the +set can have their own argument values. + +### Let users choose a value + +To let users choose the mode when creating a sandbox, define an argument on +the set and pass its value to the linter: + +```yaml +args: + lint_mode: + default: check + enum: [check, fix] + +kits: + - ref: docker.io/my-org/linter-kit:1.0.0 + args: + mode: ${{ kit.args.lint_mode }} +``` + +This example assumes the linter defines `mode` with the same default and +allowed values. The set must preserve those constraints. Users can then pass +`--kit-arg lint_mode=fix` when running the published set. They can change only +arguments defined on the set, not other arguments on its components. +See [Set merge rules](https://github.com/docker/sandbox-kit-spec/blob/main/docs/spec/SPEC-v3.md#95-merging-a-set) +for the argument rules. + +### Change a build argument + +Arguments used to build a component, such as the tool version to install, +are fixed in its published image. To change one, rebuild and publish the +component, then update its reference in the set. + +## Review and update the composition + +### Check for file conflicts + +Before sharing a set, check that its components work together. Give each +component's files separate paths: if two components include the same path, +the file from the later image layer replaces the earlier one. The build +orders layers by kit dependencies, so reordering `kits:` doesn't choose +which file wins. Inspect the built image for unintended replacements. +When you combine kits with `--kit` instead, Docker Sandboxes rejects files +that collide when it creates the sandbox. + +### Check combined settings + +The set includes each component's network rules and agent instructions. +Lifecycle hooks run in dependency order, but startup hooks run alongside +the agent. The agent might start before those hooks finish. + +Use install hooks for setup that must finish during sandbox creation. For +setup that must finish before every agent launch, use the workload's +entrypoint. + +The workload chooses the instruction filename. If you add instructions with +an `agent-context` capability on the set, leave out the filename. + +### Update a component + +Change the component's reference, rebuild the set, and publish another +version. Create another sandbox to try the updated set. Existing sandboxes +keep the kit configuration they were created with. + +A published set keeps the files and settings it was built with, even if a +component's tag later points to a different image. To use those same images +when rebuilding, add a `digest` beside each `ref` in the source. + +For signing and multi-platform builds, see +[Build and distribute kits](/manuals/ai/sandboxes/customize/author/distribute.md). diff --git a/content/manuals/ai/sandboxes/customize/author/patterns.md b/content/manuals/ai/sandboxes/customize/author/patterns.md new file mode 100644 index 0000000000..4e5b004b48 --- /dev/null +++ b/content/manuals/ai/sandboxes/customize/author/patterns.md @@ -0,0 +1,147 @@ +--- +title: Kit authoring patterns +linkTitle: Authoring patterns +description: Build reusable kits that carry the access their tools need, prepare certificates and storage during setup, and offer useful options to your team. +keywords: sandboxes, sbx, kits, patterns, mixins, lifecycle, certificates +weight: 35 +--- + +{{< summary-bar feature_name="Docker Sandboxes sbx" >}} + +When you package a tool as a kit, aim to make it work wherever you add it. +These patterns show how to include the access it needs, prepare it for each +sandbox, and give your team useful options without asking them to assemble +the environment themselves. + +## Keep runtime access with the tool + +Keep a tool's network rules and credential request in the mixin that installs +it. For example, a Claude Code mixin can package the executable, allow access +to the Anthropic API, and request the API key. Those requirements follow the +tool when you add it to another workload. + +The user still needs to supply the credential and approve access. See +[Build a tool mixin](/manuals/ai/sandboxes/customize/author/tool-mixins.md) +for a complete example. + +## Leave build tools out of the mixin + +Build a tool in one Dockerfile stage, then copy the executable into an empty +stage. Each sandbox gets the tool without also getting its compiler and +source code: + +```yaml {title="gojq/gojq.yaml"} +# syntax=docker/sandbox-kit:3 +schemaVersion: "3" +kind: mixin +provides: ["gojq@0.12.17"] + +build: | + FROM golang:1.25 AS build + RUN CGO_ENABLED=0 go install github.com/itchyny/gojq/cmd/gojq@v0.12.17 + + FROM scratch + COPY --from=build /go/bin/gojq /usr/local/bin/gojq +``` + +`CGO_ENABLED=0` builds gojq without a dependency on the workload's C libraries. +`FROM scratch` starts the final stage empty, so it contains only the binary +you copy. The `provides` entry tells other kits which gojq version this mixin +installs. + +## Run setup after combining kits + +Some setup needs tools or files from the workload. Package what you can in the +mixin, then use an install hook to finish setup once all the kits' files are +in place. For example, bring an internal certificate authority (CA) certificate +in the mixin and register it in the workload's trust store: + +```yaml {title="internal-ca/internal-ca.yaml"} +# syntax=docker/sandbox-kit:3 +schemaVersion: "3" +kind: mixin + +build: | + FROM scratch + COPY internal-ca.crt /usr/local/share/ca-certificates/team-internal-ca.crt + +capabilities: + - type: com.docker.sandbox/lifecycle@1 + config: + install: + - command: update-ca-certificates + user: "0" +``` + +Save your PEM-encoded CA as `internal-ca.crt` beside the descriptor and use the +mixin with a workload that supplies `update-ca-certificates`, such as Docker's +shell kit. The hook updates the workload's trust store as root, after all kit +files are present and before the agent launches. + +```console +$ sbx run docker.io/docker/sbx-kit-shell:1.0.0 --kit ./internal-ca +``` + +## Seed storage after it is mounted + +Mounting storage at a path hides any files the image already has there. To +give a tool some initial data, keep that data elsewhere in the image and +copy it to the mounted directory in an install hook. Check whether the +destination file exists first so you preserve any changes the user has made: + +```yaml {title="tool-state/tool-state.yaml"} +# syntax=docker/sandbox-kit:3 +schemaVersion: "3" +kind: mixin + +build: | + FROM scratch + COPY defaults.json /usr/share/company-cli/defaults.json + +capabilities: + - type: com.docker.sandbox/volume@1 + config: + path: /home/agent/.company-cli + size: 1g + - type: com.docker.sandbox/lifecycle@1 + config: + install: + - command: | + set -eu + chown 1000:1000 /home/agent/.company-cli + if [ ! -e /home/agent/.company-cli/config.json ]; then + install -o 1000 -g 1000 -m 0644 /usr/share/company-cli/defaults.json /home/agent/.company-cli/config.json + fi + user: "0" +``` + +Save your tool's initial configuration as `defaults.json` beside the descriptor. +Use a workload with `chown` and `install`, such as Docker's shell kit. The hook +makes the directory and configuration file writable by the agent. If the +volume already has a configuration file, the hook leaves its contents intact. + +### Configure the volume + +The volume keeps the tool's data across sandbox restarts. A replacement +sandbox gets its own volume. This example allocates `1g` of space. If you +omit `size`, `sbx` allocates `512m`. + +Use an install hook to set ownership and permissions for persistent volumes, +as this example does. The volume capability's `mode` setting applies only +to tmpfs mounts. See the upstream +[volume definition](https://github.com/docker/sandbox-kit-spec/blob/main/docs/spec/capabilities/com.docker.sandbox/volume@1.md) +for storage options. + +To copy initial files into a mounted workspace instead, use +`WORKSPACE_DIR` as the destination and +[declare it in the hook's environment](/manuals/ai/sandboxes/customize/author/_index.md#choose-when-setup-runs). + +## Publish fixed components with configurable options + +Choose compatible agent and tool versions for your team, then publish them +as a set. Expose arguments for settings users can change without replacing +those components, such as a model or linter mode. Keep version choices fixed +in the published images. + +For the argument syntax and constraints, see +[Configure component arguments](/manuals/ai/sandboxes/customize/author/kit-sets.md#configure-component-arguments). diff --git a/content/manuals/ai/sandboxes/customize/author/tool-mixins.md b/content/manuals/ai/sandboxes/customize/author/tool-mixins.md new file mode 100644 index 0000000000..69bc14701a --- /dev/null +++ b/content/manuals/ai/sandboxes/customize/author/tool-mixins.md @@ -0,0 +1,210 @@ +--- +title: Build a tool mixin +description: Package Claude Code as a reusable mixin with API access and credentials, test it in a shell workload, and publish it. +keywords: sandboxes, sbx, kits, mixins, tools, credentials, build +weight: 30 +aliases: + - /ai/sandboxes/customize/kit-examples/ +--- + +{{< summary-bar feature_name="Docker Sandboxes sbx" >}} + +A tool mixin adds an executable and the settings it needs to an existing +workload. This tutorial packages Claude Code as a mixin, adds it to a shell +workload, and tests a request to the Anthropic API. The sandbox starts a shell, +and you choose when to run Claude Code. + +The example adapts the upstream +[Claude Code mixin](https://github.com/docker/sandbox-kit-spec/tree/main/examples/claude-mixin) +to use API-key authentication. The upstream example also includes OAuth, +session storage, and MCP configuration. + +You need `sbx`, Docker with Buildx, and an Anthropic API key. To publish the +mixin, you also need a registry namespace you can push to. Use a v3 workload +with this mixin. Built-in shortcuts such as `shell` and `claude` use v2. See +[Version compatibility](/manuals/ai/sandboxes/customize/_index.md#version-compatibility). + +## Package the executable + +Create a `claude-mixin` directory with a Dockerfile and YAML descriptor: + +```text +claude-mixin/ +├── claude-mixin.dockerfile +└── claude-mixin.yaml +``` + +The Dockerfile downloads the native Claude Code executable in a build stage, +then copies it into an empty image: + +```dockerfile {title="claude-mixin/claude-mixin.dockerfile"} +FROM debian:trixie-slim AS build +ARG CLAUDE_VERSION +ARG TARGETARCH +RUN apt-get update && apt-get install -y --no-install-recommends curl ca-certificates +RUN case "$TARGETARCH" in \ + amd64) platform=linux-x64 ;; \ + arm64) platform=linux-arm64 ;; \ + *) echo "unsupported TARGETARCH: $TARGETARCH" >&2; exit 1 ;; \ + esac \ + && mkdir -p /out/usr/local/bin \ + && curl -fsSL "https://downloads.claude.ai/claude-code-releases/${CLAUDE_VERSION}/${platform}/claude" \ + -o /out/usr/local/bin/claude \ + && chmod 0755 /out/usr/local/bin/claude + +FROM scratch +COPY --from=build /out/ / +``` + +BuildKit supplies `TARGETARCH` to select the download for the image's Linux +architecture. You'll set `CLAUDE_VERSION` in the descriptor. The final stage +contains only the executable, so the mixin doesn't add Debian or the download +tools to the workload. + +Docker Sandboxes adds the mixin's files to the workload's environment. The +workload keeps its own startup command, user, and working directory. This +example uses Docker's shell workload. When choosing another workload, check +that it supplies the Linux libraries and shell your tool needs. + +A mixin includes only the files its Dockerfile adds or changes. If you use +a larger base image instead of `scratch`, the mixin won't include that +image's unchanged files. + +## Declare runtime access + +Create the descriptor with the version to install and the API access Claude +Code needs: + +```yaml {title="claude-mixin/claude-mixin.yaml"} +# syntax=docker/sandbox-kit:3 +schemaVersion: "3" +kind: mixin +displayName: Claude Code mixin + +args: + version: + default: "2.1.278" + pattern: '^[0-9]+\.[0-9]+\.[0-9]+$' + buildArg: CLAUDE_VERSION + +provides: ["claude@${{ kit.args.version }}"] + +capabilities: + - type: com.docker.sandbox/network-policy@1 + config: + runtime: + allow: + - api.anthropic.com:443 + - type: com.docker.sandbox/credential@1 + config: + service: anthropic + phase: runtime + apiKey: + name: ANTHROPIC_API_KEY + proxyManaged: true + inject: + - domain: api.anthropic.com + header: x-api-key + format: "%s" +``` + +The `version` argument supplies `CLAUDE_VERSION` to the Dockerfile. The +`provides` entry identifies the installed Claude Code version so other kits +can check their requirements. + +The network rule permits HTTPS requests to the Anthropic API. The credential +entry requests the key stored under `anthropic` on your host. Inside the +sandbox, `ANTHROPIC_API_KEY` contains a placeholder. The host proxy inserts +the real key into the `x-api-key` header when Claude Code calls the API. + +Network access and credential access are separate: declaring a credential +doesn't allow connections to its service. This example pairs `phase: runtime` +with `runtime.allow`. The download in the Dockerfile uses the builder's +network and doesn't need a rule in the descriptor. + +Keep the tool's access requirements in the mixin so they follow it when you +use it with another workload. Access shared by a project's tools, such as a +package registry, can go in a +[kit set](/manuals/ai/sandboxes/customize/author/kit-sets.md). + +## Try the mixin + +Store your Anthropic API key on the host: + +```console +$ sbx secret set anthropic +``` + +From the directory containing `claude-mixin`, add the mixin to Docker's +published shell workload: + +```console +$ sbx run docker.io/docker/sbx-kit-shell:1.0.0 --name claude-mixin-test \ + --kit ./claude-mixin +``` + +Approve the mixin's credential request when prompted. `sbx` builds the mixin, +adds its executable to the workload, and opens a shell. The mixin doesn't +replace the workload's launch command. + +Inside the sandbox, check that Claude Code runs: + +```console +$ claude --version +``` + +Then send a request to check network access and authentication. This command +uses the Anthropic API and incurs usage charges: + +```console +$ claude -p "Reply with the word hello." +``` + +A response confirms that Claude Code can reach the API and authenticate with +your stored key. If authentication fails, check that you stored the key and +approved the kit's request to use it. See +[Credential bindings](/manuals/ai/sandboxes/configuration/credentials.md#credential-bindings). +Network requests must also meet the sandbox's +[network policy](/manuals/ai/sandboxes/governance/concepts.md#precedence). + +Run `claude` without arguments to start an interactive session. Follow its +first-run prompts. Exit Claude Code and the shell to return to your host. + +After editing the kit's files, create a sandbox with a different name to test +your changes. Reopening an existing sandbox uses the kits it was created with. + +## Publish the mixin + +Build and publish the mixin so others can use it without building from source: + +```console +$ docker login +$ docker buildx build ./claude-mixin -f ./claude-mixin/claude-mixin.yaml \ + -t docker.io//claude-mixin:1.0.0 --push +``` + +Replace `` with a Docker Hub namespace you can push to. Use the +published reference with `--kit` in place of `./claude-mixin`. + +Choose a workload that doesn't already provide Claude Code. Two kits that +declare the same feature in `provides` conflict. To share the shell workload +and this mixin as one kit, see +[Compose a kit set](/manuals/ai/sandboxes/customize/author/kit-sets.md). + +## More source examples + +The [sandbox-kit-spec examples](https://github.com/docker/sandbox-kit-spec/tree/main/examples) +contain complete kits you can study and adapt: + +- [Claude Code mixin](https://github.com/docker/sandbox-kit-spec/tree/main/examples/claude-mixin) + includes additional authentication options, session storage, and agent + instructions. +- [GitHub CLI](https://github.com/docker/sandbox-kit-spec/tree/main/examples/gh) + packages `gh` and its dependencies with network rules, credentials, and + agent instructions. +- [Message of the day](https://github.com/docker/sandbox-kit-spec/tree/main/examples/motd) + uses an inline Dockerfile and a build argument in a single-file mixin. + +For examples of building a tool from source, running setup scripts, and other +reusable approaches, see +[Kit authoring patterns](/manuals/ai/sandboxes/customize/author/patterns.md). diff --git a/content/manuals/ai/sandboxes/customize/build-an-agent.md b/content/manuals/ai/sandboxes/customize/build-an-agent.md deleted file mode 100644 index 3d7f111dc3..0000000000 --- a/content/manuals/ai/sandboxes/customize/build-an-agent.md +++ /dev/null @@ -1,326 +0,0 @@ ---- -title: Build your own agent kit -linkTitle: Build an agent -description: Walk through building an agent kit for Amp, from base image choice to invocation. -keywords: sandboxes, sbx, kits, agent, tutorial, amp, ampcode -weight: 30 ---- - -{{< summary-bar feature_name="Docker Sandboxes sbx" >}} - -> [!NOTE] -> Kits are experimental. The kit file format, CLI commands, and experience -> for creating, loading, and managing kits are subject to change as the -> feature evolves. Share feedback and bug reports in the -> [docker/sbx-releases](https://github.com/docker/sbx-releases) repository. - -This tutorial walks through building an agent kit for the -[Amp](https://ampcode.com/) coding agent. Each step explains the decision -behind a part of the spec, so you can apply the same reasoning to other agents. - -For reference on every field, see the [Kit spec reference](kit-reference.md). -This tutorial focuses on the journey. - -The finished kit is also published as a runnable sample at -[docker/sbx-kits-contrib](https://github.com/docker/sbx-kits-contrib/tree/main/amp) — -useful as a reference while you follow along. - -## Choose a base image - -An agent kit needs a container image that satisfies the -[base image requirements](kit-reference.md#base-image-requirements): non-root -`agent` user at UID 1000, passwordless sudo, `/home/agent/` home, and HTTP -proxy environment variable forwarding. - -Rather than build an image from scratch, extend one of the published -sandbox templates. Three common starting points: - -- `docker/sandbox-templates:shell`. Generic base with no pre-installed - agent. -- `docker/sandbox-templates:shell-docker`. Same, with Docker Engine inside - the sandbox. -- Agent-specific variants (`claude-code`, `codex`, etc.). Only useful if - you're extending that specific agent. - -For Amp, pick `shell-docker`: - -- Amp isn't pre-installed in any variant, so you need a generic base - (`shell`). -- Docker support is handy since coding agents often need to run containers. -- If you don't need Docker inside the sandbox, use the `shell` tag for a - lighter, non-privileged environment. - -## Plan authentication - -Amp authenticates with an API key in `AMP_API_KEY`. To keep the real key -out of the VM, you split the work in two: - -- The kit's network section maps the API host to a service identifier - and tells the proxy which header to inject. -- You provide your key once on the host, via sbx's secret store. The - real value stays on the host; only a placeholder reaches the sandbox. - -Inside the sandbox `AMP_API_KEY` is set to that placeholder. The proxy -substitutes the real key on outbound requests to the API host, so the -secret never enters the sandbox. A later section walks through the -specific command for storing the key. - -## Write the sandbox block - -The `sandbox:` block tells the sandbox how to launch Amp when the user -attaches. - -```yaml {title="amp/spec.yaml"} -schemaVersion: "1" -kind: sandbox -name: amp -displayName: Amp -description: The frontier coding agent. - -sandbox: - image: "docker/sandbox-templates:shell-docker" - aiFilename: AGENTS.md - entrypoint: - run: [amp, --dangerously-allow-all] -``` - -- `aiFilename: AGENTS.md` tells the sandbox to create `AGENTS.md` at launch - and append the [`agentContext`](#prime-amp-with-memory) block to it. Amp reads - this file for instructions. -- `entrypoint.run` runs `amp` in "YOLO-mode" when the sandbox starts. Adjust if - you want to pass different args on startup. - -## Install Amp - -Amp installs via a curl-to-bash script: - -```yaml -commands: - install: - - command: "curl -fsSL https://ampcode.com/install.sh | bash" - user: "1000" - description: Install Amp -``` - -Note `user: "1000"`. That's the agent user. Install commands run as root -(UID 0) by default, and Amp's installer puts the binary in the user's home -directory. Running as root would land the binary in `/root/` where the -agent can't reach it. - -## Allow network access - -The network block does two things: it lists the hosts the sandbox can -reach (`allowedDomains`), and it wires the kit-side half of the auth flow -from [Plan authentication](#plan-authentication) with `serviceDomains` and -`serviceAuth`. - -```yaml -network: - serviceDomains: - ampcode.com: amp - serviceAuth: - amp: - headerName: Authorization - valueFormat: "Bearer %s" - allowedDomains: - - "ampcode.com:443" - - "*.ampcode.com:443" -``` - -`allowedDomains` here covers the apex (`ampcode.com`) and the -install/CDN subdomains (`*.ampcode.com`). Treat it as a starting point; -Amp may reach other domains (model providers, analytics, updates) that -you'll discover by watching `sbx policy log` while testing. - -Kits can also declare `deniedDomains` for hosts the sandbox should not -reach, such as telemetry endpoints. Deny rules take precedence over -allow rules and apply only to sandboxes that use the kit. - -For the auth wiring, when the agent makes an outbound request to -`ampcode.com`, the proxy looks up the host in `serviceDomains` to find -the service id `amp`, then uses `serviceAuth.amp` to inject an -`Authorization: Bearer ` header. The `` value comes from the -secret you'll register in -[Register your API key](#register-your-api-key), matched by host. The -service id (`amp`) is just a label that ties the two blocks together — -pick any name. - -> [!IMPORTANT] -> Keep `serviceDomains` narrow. Mapping `*.ampcode.com` would push the -> proxy into TLS-intercepting mode for every subdomain — including the -> binary CDN the install script downloads from — which corrupts those -> downloads. List only the host that actually needs auth. - -## Prime Amp with memory - -The `agentContext` field appends markdown to `AGENTS.md` at sandbox creation. -Use it to tell Amp about the sandbox environment so it knows the -conventions when it starts. - -```yaml -agentContext: | - ## Sandbox environment - - You are running inside a Docker sandbox. The workspace is mounted at - its absolute host path. `sudo` is passwordless; use it for package - installs. Docker is available inside the sandbox; containers you start - are isolated in the microVM. -``` - -Keep this short and sandbox-specific. For project instructions, put a -regular `AGENTS.md` in the workspace. - -## The full spec - -Putting it all together: - -```yaml {title="amp/spec.yaml"} -schemaVersion: "1" -kind: sandbox -name: amp -displayName: Amp -description: The frontier coding agent. - -sandbox: - image: "docker/sandbox-templates:shell-docker" - aiFilename: AGENTS.md - entrypoint: - run: [amp, --dangerously-allow-all] - -network: - serviceDomains: - ampcode.com: amp - serviceAuth: - amp: - headerName: Authorization - valueFormat: "Bearer %s" - allowedDomains: - - "ampcode.com:443" - - "*.ampcode.com:443" - -commands: - install: - - command: "curl -fsSL https://ampcode.com/install.sh | bash" - user: "1000" - description: Install Amp - -agentContext: | - ## Sandbox environment - - You are running inside a Docker sandbox. The workspace is mounted at - its absolute host path. `sudo` is passwordless; use it for package - installs. -``` - -## Register your API key - -Register your Amp API key on the host with `sbx secret set-custom`. The -value goes into the host secret store, and a placeholder is exposed -inside every sandbox you launch from this kit. - -Amp validates `AMP_API_KEY`'s format at startup, so the placeholder needs -to look like a real Amp key. Pick a placeholder shape that matches Amp's -expected format: - -```console -$ sbx secret set-custom \ - --host ampcode.com \ - --env AMP_API_KEY \ - --placeholder "sgamp-{rand}" \ - --value "$AMP_API_KEY" -``` - -`{rand}` expands to a random suffix at registration time. Inside the -sandbox `AMP_API_KEY` is set to that placeholder; Amp accepts it as a -syntactically valid key, and the proxy substitutes the real secret on -outbound requests to `ampcode.com`. - -> [!TIP] -> `sbx secret set-custom` is only required because Amp validates the -> key's format. If your agent reads the env var without a local format -> check, you can declare `environment.proxyManaged: [AMP_API_KEY]` in -> the kit instead and skip this user-side step — the proxy uses a -> default sentinel value (`proxy-managed`) that the agent never sees -> rejected. - -> [!NOTE] -> `sbx secret set-custom` is experimental and may change in future -> releases. This tutorial surfaces it because there's no other path to -> register a custom-format placeholder. - -## Run it - -Validate the spec: - -```console -$ sbx kit validate ./amp/ -``` - -Launch the sandbox by passing the kit directory in place of a built-in agent -name: - -```console -$ sbx run ./amp/ -``` - -The published copy of this kit also runs directly from the contrib -repository: - -```console -$ sbx run "git+https://github.com/docker/sbx-kits-contrib.git#dir=amp" -``` - -## Iterate - -As you use the kit, you'll likely hit missing domains or install quirks. -Two loops help: - -- Watch the network policy log (`sbx policy log`) to catch blocked - requests, then add their domains to `allowedDomains`. -- Add domains to `deniedDomains` when the agent should stay blocked from - a host even if another policy permits it. -- Edit the spec and re-run `sbx run ./amp/` to pick up changes. - Remove the sandbox first (`sbx rm `) for a clean start. - -Flesh out the `agentContext` block as you refine how Amp should behave in the -sandbox. - -## Publish - -Once the kit works, share it by packaging as a ZIP, pushing to an OCI -registry, or committing to a Git repository. See -[Packaging and distribution](kits.md#packaging-and-distribution) for the -`sbx kit` subcommands. - -## Adapt this to another agent - -Most of the specifics here are Amp's. To port the pattern, work through -the same decisions for your agent: - -- **Base image**: `shell-docker` if you need Docker inside the sandbox, - `shell` otherwise. Or extend either with your own image if the install - is heavy. -- **Install**: a `commands.install` block at runtime, or bake the agent - into a custom image. Pick install if it's a one-line script; bake if - the install is slow or you need a pinned version. -- **Network mapping**: list only the API host in `serviceDomains`, not - a wildcard. Keep install/CDN paths out of TLS-intercepting mode. Use - `deniedDomains` for hosts the agent should not reach. -- **Credential injection**: if the agent validates the API key's format - locally, register with `sbx secret set-custom` and pick a matching - placeholder. If it accepts the env var as-is, declare - `environment.proxyManaged` in the kit and skip the user-side step. - -The rest — agent-context block, network-policy iteration, packaging — is the -same regardless of agent. - -## Remove the stored secret - -To remove the entry created earlier with `sbx secret set-custom`, pass -the host to `sbx secret rm`: - -```console -$ sbx secret rm --host ampcode.com -``` - -The `--host` flag is part of the experimental `set-custom` surface and doesn't appear in `sbx secret rm --help`. diff --git a/content/manuals/ai/sandboxes/customize/kit-examples.md b/content/manuals/ai/sandboxes/customize/kit-examples.md deleted file mode 100644 index 615b910870..0000000000 --- a/content/manuals/ai/sandboxes/customize/kit-examples.md +++ /dev/null @@ -1,467 +0,0 @@ ---- -title: Kit examples -linkTitle: Examples -description: Copy-and-adapt spec.yaml snippets for common mixin and sandbox kit patterns — static files, install commands, shell customization, background services, setup files, Claude Code skills, and agent forks. -keywords: sandboxes, sbx, kits, mixins, examples, patterns, skills -weight: 40 ---- - -{{< summary-bar feature_name="Docker Sandboxes sbx" >}} - -> [!NOTE] -> Kits are experimental. The kit file format, CLI commands, and experience -> for creating, loading, and managing kits are subject to change as the -> feature evolves. Share feedback and bug reports in the -> [docker/sbx-releases](https://github.com/docker/sbx-releases) repository. - -Each section below shows one `spec.yaml` snippet that demonstrates a -single kit pattern. These aren't complete, distributable kits — they're -small, focused examples you can lift into your own kit. For the full -spec reference, see [Kit spec reference](kit-reference.md). - -## Drop a shared config file - -Use static files under `files/workspace/` when the content is the same -across every sandbox and doesn't need any runtime values substituted -in. Typical use cases: linter rules, editor settings, a shared -`.editorconfig`, team dotfiles. - -```text -ruff-lint/ -├── spec.yaml -└── files/ - └── workspace/ - └── ruff.toml -``` - -```yaml {title="ruff-lint/spec.yaml"} -schemaVersion: "2" -kind: mixin -name: ruff-lint -displayName: Ruff -description: Python linting with shared team config - -setup: - install: - - command: "uv tool install ruff@latest" - user: "1000" -``` - -```toml {title="ruff-lint/files/workspace/ruff.toml"} -line-length = 80 - -[lint] -select = ["E", "F", "I"] -``` - -## Install a tool at sandbox creation - -`setup.install` runs once per sandbox, at creation time. It's where -anything that needs to land in the image goes — package managers -(`apt-get`, `pip`, `npm`), binary downloads, or vendor install scripts. - -> [!TIP] -> Each new sandbox runs all `setup.install` commands. The results aren't -> cached between sandboxes. Creating a kit avoids building and distributing an -> image, so kits work well for smaller, composable changes. For substantial -> build or installation steps, consider a -> [custom template](templates.md#build-a-custom-template). Sandboxes reuse -> template images from the local cache. - -```yaml -setup: - install: - - command: "apt-get update && apt-get install -y jq" - - command: "curl -fsSL https://example.com/install.sh | sh" -``` - -Install commands run as root by default. Set `user: "1000"` when the -step should run as the agent user — for example, `npm install -g` -against a user-scoped prefix, or anything that writes to -`/home/agent/`. - -Install steps run under `sh`, not bash, so bash-only builtins such as -`source` fail with `sh: source: not found`. Pipe explicitly to `bash` -(`curl … | bash`) or wrap the step in `bash -c '…'` when you need them. - -Downloads are subject to the sandbox's -[network access rules](../governance/access-controls/network.md). A domain that -resolves from your host can still be blocked inside the sandbox — for -example, `get.sdkman.io` returns a 403 until you allow it with -`sbx policy allow network get.sdkman.io`. A tool may also need base -packages that aren't in the image: [SDKMAN!](https://sdkman.io/), for -instance, needs `zip` and `unzip`, so add an -`apt-get install -y zip unzip` step (as root) before installing it. - -> [!WARNING] -> `curl … | bash` masks download failures. The pipe's exit status is -> bash's, and bash exits `0` on empty input, so a blocked or failed -> download still reports success — the sandbox is created with no error -> even though nothing was installed. Download first, then run, so a -> failed fetch fails the step: -> -> ```yaml -> setup: -> install: -> - command: "curl -fsSL https://example.com/install.sh -o /tmp/install.sh && bash /tmp/install.sh" -> user: "1000" -> ``` - -## Customize the shell environment - -Some tools install into a versioned directory and expect you to source -an init script from your shell profile so their commands land on `PATH`. -Version managers like [nvm](https://github.com/nvm-sh/nvm) and -[SDKMAN!](https://sdkman.io/) follow this pattern. To make the tool -available in every shell, append the source line to -`/etc/sandbox-persistent.sh` in an install command. - -`/etc/sandbox-persistent.sh` is the sandbox's persistent environment -file. It's sourced before every bash invocation — interactive shells and -non-interactive ones, including agents started with `sbx run` and -commands run with `sbx exec`. Appending here makes the tool available to -the agent regardless of how its shell is launched. Use -[`environment.variables`](kit-reference.md#environment) for ordinary variables -declared by a kit. To pass variables when creating a sandbox, use -[`-e` or `--env-file`](../usage.md#set-environment-variables). - -```yaml {title="nvm/spec.yaml"} -schemaVersion: "2" -kind: mixin -name: nvm -displayName: nvm -description: Node version manager available in every shell - -setup: - install: - - command: "curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash" - user: "1000" - description: Install nvm - - command: | - cat >> /etc/sandbox-persistent.sh <<'EOF' - export NVM_DIR="$HOME/.nvm" - unset NPM_CONFIG_PREFIX - [ -s "$NVM_DIR/nvm.sh" ] && source "$NVM_DIR/nvm.sh" - EOF - user: "1000" - description: Source nvm for every shell -``` - -Both install steps run as `user: "1000"`. This installs the tool under -`/home/agent/` and can update `/etc/sandbox-persistent.sh`, which the agent user -owns. The `$HOME` in the appended lines resolves per user at source time, so the -agent user finds its own install. Append to the file rather than overwriting it -— the sandbox relies on its existing contents. - -The base image ships its own Node and sets `NPM_CONFIG_PREFIX`, which -nvm won't activate alongside. `unset NPM_CONFIG_PREFIX` before sourcing -`nvm.sh` clears that conflict. Sourcing makes the `nvm` command -available; it doesn't put a Node version on `PATH`. Run -`nvm install --lts` to add one — wrap it in `bash -c '…'` if you script -it as an install step, since install steps run under `sh`. - -Append only the init script, not the tool's tab-completion script. -Because `/etc/sandbox-persistent.sh` is sourced before every command, -completion scripts — which rely on variables that exist only during -completion — can break non-interactive shells that agents rely on. - -## Install an internal CA certificate - -If your organization uses a proxy that inspects HTTPS traffic, install -the proxy's internal root CA in the sandbox trust store. This helps -agents and SDKs trust certificates signed by the proxy. - -```text -internal-ca/ -├── spec.yaml -└── files/ - └── home/ - └── internal-ca.crt -``` - -Use a PEM-encoded certificate with a `.crt` extension. Files under -`files/home/` land in `/home/agent/` in the sandbox, so -`files/home/internal-ca.crt` becomes `/home/agent/internal-ca.crt` — -which is the path the install command reads from. If traffic can be -signed by more than one internal proxy, include each proxy's root CA in -the kit and install each certificate before running -`update-ca-certificates`. - -```yaml {title="internal-ca/spec.yaml"} -schemaVersion: "2" -kind: mixin -name: internal-ca - -setup: - install: - - command: "install -m 0644 /home/agent/internal-ca.crt /usr/local/share/ca-certificates/internal-ca.crt && update-ca-certificates" - user: "0" - description: Install internal CA certificate -``` - -`update-ca-certificates` adds the certificate to the system trust -store, so tools and SDKs that read the system bundle trust the proxy's -certificates without further configuration. - -## Run a background service - -`setup.startup` runs on every sandbox start. To keep a long-running -service such as a dev server or daemon alive, set `background: true`. The -sandbox runs the command in the background and replays startup commands on -each start, so the service comes back after a stop/start cycle: - -```yaml -setup: - startup: - - command: ["my-service", "--port", "8080"] - user: "1000" - background: true -``` - -A background service doesn't write to your terminal. To capture its output -for debugging, wrap the command in a shell and redirect to a log file. Let -`background: true` run the command in the background rather than adding a -trailing `&` yourself: - -```yaml -setup: - startup: - - command: - - sh - - -c - - my-service --port 8080 > /tmp/my-service.log 2>&1 - user: "1000" - background: true -``` - -An empty log file tells you the wrapper ran; a populated one tells you why -the service failed. - -## Write runtime values to a file - -When a config file needs a value that isn't known until sandbox start -— most often the absolute workspace path — use `setup.files`. -The `${WORKDIR}` placeholder expands to the primary workspace path -when the file is written. - -```yaml -setup: - files: - - path: /home/agent/.local/bin/start-code-server.sh - content: | - exec code-server --bind-addr 0.0.0.0:8080 --auth none "${WORKDIR}" - mode: "0755" - startup: - - command: - - sh - - -c - - nohup /home/agent/.local/bin/start-code-server.sh > /tmp/code-server.log 2>&1 & - user: "1000" -``` - -`mode: "0755"` makes the generated file executable so the startup -command can invoke it directly. - -Use `setup.files` instead of a static file whenever the content depends -on a runtime value. Use a static file otherwise. - -> [!TIP] -> This snippet is lifted from the -> [code-server kit](https://github.com/docker/sbx-kits-contrib/tree/main/code-server) -> in the contrib repository, which is also a runnable sample that demonstrates -> the full pattern. - -## Ship a Claude Code skill - -Claude Code reads project-scoped skills from -`.claude/skills//SKILL.md` in the workspace. Drop one into -`files/workspace/` and it's available in the sandbox. - -```text -docker-review/ -├── spec.yaml -└── files/ - └── workspace/ - └── .claude/ - └── skills/ - └── docker-review/ - └── SKILL.md -``` - -```yaml {title="docker-review/spec.yaml"} -schemaVersion: "2" -kind: mixin -name: docker-review -displayName: Dockerfile review skill -description: Ships a Claude Code skill that reviews Dockerfiles -``` - -```markdown {title="docker-review/files/workspace/.claude/skills/docker-review/SKILL.md"} ---- -name: docker-review -description: Review a Dockerfile for best practices. Use when the user asks to review, audit, or improve a Dockerfile. ---- - -When reviewing a Dockerfile, check: - -1. Base image — pinned tag or digest, appropriate for the workload -2. Layer order — dependencies copied before application source -3. Image size — multi-stage builds, `.dockerignore`, package-manager cache flags -4. Security — non-root `USER`, no secrets in `ARG`/`ENV` -5. Reproducibility — pinned package versions, frontend directive where relevant -``` - -Kits have to target the workspace rather than `~/.claude/` because -sandboxes don't pick up user-level agent configuration from the host. -See the -[FAQ](../faq.md#why-doesnt-the-sandbox-use-my-user-level-agent-configuration) -for details. - -## Customize agent settings - -Some agents combine settings from several files. When the agent supports it, -place kit settings in a separate file instead of replacing -[sandbox-managed agent configuration](kits.md#sandbox-managed-agent-configuration). - -Claude Code's `--settings` option loads an additional settings file. Extend the -built-in `claude` kit to add the option without reproducing its configuration, -and place the additional file outside the path the sandbox manages: - -```text -claude-sonnet/ -├── spec.yaml -└── files/ - └── home/ - └── .config/ - └── claude/ - └── sonnet.json -``` - -```yaml {title="claude-sonnet/spec.yaml"} -schemaVersion: "2" -kind: sandbox -name: claude-sonnet -extends: claude - -sandbox: - command: - - --dangerously-skip-permissions - - --settings - - /home/agent/.config/claude/sonnet.json -``` - -```json {title="claude-sonnet/files/home/.config/claude/sonnet.json"} -{ - "model": "sonnet" -} -``` - -Claude Code merges the additional file with the sandbox-managed user settings. -Because the file is under `files/home/`, it stays inside the sandbox instead of -being written into a directly mounted host workspace. Launch the sandbox by -passing the child kit directory in place of a built-in agent name: - -```console -$ sbx run ./claude-sonnet -``` - -When you launch the kit for the first time, `sbx` prompts you to approve its -inherited Anthropic credentials. Because this is a third-party schema v2 kit, -`sbx` records your approval as a -[credential binding](../configuration/credentials.md#credential-bindings). - -OpenCode supports an additional config file through `OPENCODE_CONFIG`. Keep the -kit's config separate from the sandbox-managed -`/home/agent/.config/opencode/opencode.json`, for example at -`/home/agent/.config/opencode/team.json`: - -```text -opencode-team/ -├── spec.yaml -└── files/ - └── home/ - └── .config/ - └── opencode/ - └── team.json -``` - -```yaml {title="opencode-team/spec.yaml"} -schemaVersion: "2" -kind: mixin -name: opencode-team -requires: - agent: opencode - -environment: - variables: - OPENCODE_CONFIG: /home/agent/.config/opencode/team.json -``` - -```json {title="opencode-team/files/home/.config/opencode/team.json"} -{ - "$schema": "https://opencode.ai/config.json", - "autoupdate": false -} -``` - -OpenCode merges the custom file with its global and project config files. See -the OpenCode [config precedence](https://opencode.ai/docs/config/#precedence-order) -for the complete order. - -Agent settings mechanisms differ. If an agent doesn't support an additional -config file, launch option, or environment variable for the setting, kits can't -replace the sandbox-managed user settings before the agent launches. -`setup.startup` doesn't gate the agent entrypoint, so don't use it for settings -the agent must read during initialization. - -## Fork an existing agent - -Sandbox kits (`kind: sandbox`) define a full agent from scratch. The most -common variant is a fork of a built-in agent. Use `extends:` to inherit the -parent's complete configuration and declare only the fields you want to change. -This example replaces the built-in `claude` entrypoint so Claude Code uses -manual permission mode instead of bypassing approval prompts: - -```yaml {title="claude-safe/spec.yaml"} -schemaVersion: "2" -kind: sandbox -name: claude-safe -displayName: Claude Code (with approval prompts) -description: Claude Code in manual permission mode - -extends: claude - -sandbox: - entrypoint: [claude, "--permission-mode", "manual"] -``` - -The child inherits the built-in image, credentials, network permissions, -persistent volumes, settings, MCP integration, agent instructions, setup -entries, and environment variables. Its `sandbox.entrypoint` replaces the -inherited entrypoint. - -Launch by passing the sandbox kit in place of a built-in agent name: - -```console -$ sbx run ./claude-safe -``` - -For a step-by-step walkthrough of building a new sandbox kit from -scratch, see [Build an agent](build-an-agent.md). - -## More examples - -These patterns are all drawn from working kits in the -[sbx-kits-contrib](https://github.com/docker/sbx-kits-contrib) -repository, which contains each example as a complete, loadable kit. -Use it to study the full shape of a kit. Load a mixin with `--kit`: - -```console -$ sbx run claude --kit "git+https://github.com/docker/sbx-kits-contrib.git#dir=" -``` - -For a `kind: sandbox` kit, pass the reference in place of the agent name: - -```console -$ sbx run "git+https://github.com/docker/sbx-kits-contrib.git#dir=" -``` diff --git a/content/manuals/ai/sandboxes/customize/kit-reference.md b/content/manuals/ai/sandboxes/customize/kits-v2.md similarity index 62% rename from content/manuals/ai/sandboxes/customize/kit-reference.md rename to content/manuals/ai/sandboxes/customize/kits-v2.md index 42408a8bd3..4072ded2a4 100644 --- a/content/manuals/ai/sandboxes/customize/kit-reference.md +++ b/content/manuals/ai/sandboxes/customize/kits-v2.md @@ -1,96 +1,183 @@ --- -title: Kit spec reference -linkTitle: Spec reference -description: Field-by-field reference for a kit's spec.yaml, including arguments, credentials, network rules, environment, setup, files, agent instructions, and the sandbox block. -keywords: sandboxes, sbx, kits, spec.yaml, reference, schema, fields -weight: 50 +title: Kits v2 +linkTitle: Kits v2 +description: Reference for v2 kits, including usage, schema fields, maintenance examples, signing, and migration to v3. +keywords: sandboxes, sbx, kits, v2, migration, spec.yaml +weight: 60 +aliases: + - /ai/sandboxes/customize/kits/ + - /ai/sandboxes/customize/kit-reference/ --- {{< summary-bar feature_name="Docker Sandboxes sbx" >}} -> [!NOTE] -> Kits are experimental. The kit file format, CLI commands, and experience -> for creating, loading, and managing kits are subject to change as the -> feature evolves. Share feedback and bug reports in the -> [docker/sbx-releases](https://github.com/docker/sbx-releases) repository. +V2 kits remain supported. This page covers v2 usage, configuration, and the +specification. For new kit development, use [v3 kits](/manuals/ai/sandboxes/customize/_index.md). -This page documents every field in a kit's `spec.yaml`. For an overview of -what kits are and how to use them, see [Kits](kits.md). +Built-in shortcuts such as `claude` and `codex` select v2 kits and still work +with v2 mixins. V3 workloads and mixins can't be combined with v1 or v2 kits. +V1 also remains supported. -For the normative v2 grammar used by the parser and tests, see the -[`schemaVersion: "2"` specification](https://github.com/docker/sbx-kits-contrib/blob/main/spec/SPEC-v2.md) -in the `docker/sbx-kits-contrib` repository. +## Use existing kits -A kit directory has a required `spec.yaml` and an optional `files/` tree: +A v2 kit contains `spec.yaml` with `schemaVersion: "2"` and an optional `files/` +tree. A sandbox kit defines the agent environment. A mixin adds tools or +configuration to it. Pass a sandbox kit in place of the agent name and add +mixins with `--kit`: -```text -my-kit/ -├── spec.yaml # required -└── files/ # optional — static files to inject - ├── home/ - └── workspace/ +```console +$ sbx run ./my-agent --name my-project --kit ./team-config +$ sbx run claude --name claude-project --kit ./team-config ``` -## Schema versions +`sbx run` uses your current directory as the workspace. Append a project path +to use another directory. To create without launching the agent, use +`sbx create`; include a workspace path or `.` to mount a directory. +References can be local directories, ZIP files, OCI artifacts, or Git URLs. +Start relative paths with `./` or `../`. For Docker Hub kits, you can omit +`docker.io/` and use `/:`. In Git URLs, `ref` selects a +revision and `dir` the kit directory. Quote URLs containing `&`: -Starting with Docker Sandboxes version 0.36, two schema versions are supported. -Use `schemaVersion: "2"` for new kits. Version `"1"` remains accepted through -the legacy path. +```console +$ sbx run "git+https://github.com//.git#ref=&dir=my-agent" +``` -When migrating to `schemaVersion: "2"`, replace v1 fields with their v2 -equivalents: +`git+ssh://` URLs work with your local SSH agent and Git credentials. +For private registries, see +[Registry credentials](../configuration/credentials.md#registry-credentials). -| v1 | v2 | -| ------------------------------------------- | ---------------------------------------- | -| `credentials.sources.` | `credentials:` list entry with `service` | -| `network.allowedDomains` / `deniedDomains` | `permissions.network.allow` / `deny` | -| `network.serviceDomains` / `serviceAuth` | `credentials[].apiKey.inject` | -| `network.publishedPorts` / `publishedPorts` | top-level `ports` | -| standalone `oauth:` block | `credentials[].oauth` | -| `oauth.skipIfEnv` | Accepted but ignored | -| `environment.proxyManaged` | `credentials[].apiKey.proxyManaged` | -| `memory` / `agentContext` | `agentInstructions.content` | -| `kind: agent` / `agent:` block | `kind: sandbox` / `sandbox:` block | -| `sandbox.aiFilename` | `agentInstructions.filename` | -| `sandbox.entrypoint.run` | `sandbox.entrypoint` | -| `sandbox.entrypoint.args` | `sandbox.command.default` | -| `sandbox.entrypoint.ttyArgs` | `sandbox.command.interactive` | -| `tmpfs:` | `volumes:` entries with `type: tmpfs` | -| `volumes:` (mapping form) | `volumes:` sequence (`- path: `) | -| `commands:` / `commands.initFiles` | `setup:` / `setup.files` | -| `settings:` / `kitDir` / `persistence` | Removed | +Kit selection with `--kit` applies at creation. Recreate the sandbox to change +its kit set, except for the limited updates supported by +[`sbx kit add`](#execution-order). That command restarts the sandbox while +preserving packages, images, volumes, and agent history. Kits can't be +removed from a running sandbox. -Credential discovery also moved out of the kit in v2: a kit declares which -credentials it needs and how to inject them, but where each value comes from is -controlled by the user through -[credential bindings](../configuration/credentials.md#credential-bindings). +### Restrict kit sources -> [!NOTE] -> `mixins` and `sandbox.build` are accepted by the parser, but runtime support -> is pending. A kit that sets `sandbox.build` must also set `sandbox.image`. +See [Restrict kit sources](/manuals/ai/sandboxes/customize/use-kits.md#restrict-kit-sources) +for source policies. `kit.allowLocalKits` also governs v2 ZIP files. -## Top-level fields +## Image overrides for built-in agents + +Use `--template` to replace a built-in agent's image while keeping its +configuration and launch command. The replacement image must support the +same agent. For example, an image used with `claude` must have Claude Code +installed. + +To define an environment with its own launch command and sandbox settings, +see [Build an agent workload](/manuals/ai/sandboxes/customize/author/build-an-agent.md) +for the v3 workflow. + +### Choose a template + +Docker publishes agent images as `docker/sandbox-templates:`. +Choose the variant that matches your agent. See +[Base images](/manuals/ai/sandboxes/customize/author/base-images.md) +for the available variants. + +Variants with a `-docker` suffix, such as `claude-code-docker`, include +Docker Engine for building and running containers inside the sandbox. +Built-in agents use these variants by default when you don't specify a +custom template. + +If you don't need Docker inside the sandbox, select a variant without +the suffix. It uses fewer resources and doesn't require privileged mode: + +```console +$ sbx run claude --template docker.io/docker/sandbox-templates:claude-code +``` + +Include the registry domain in `--template` image references. Unlike kit +references, template references don't automatically expand to include +`docker.io`. + +### Build a custom template + +Building a custom template requires +[Docker Desktop](/manuals/desktop/_index.md). + +Extend the Docker-provided image for the agent you plan to run. For example, +this Dockerfile adds Rust and protocol buffer tools to the Claude Code image: + +```dockerfile +FROM docker/sandbox-templates:claude-code +USER root +RUN apt-get update && apt-get install -y protobuf-compiler +USER agent +RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y +``` + +Install system packages as `root`, then switch back to `agent` before +installing tools in the agent's home directory. + +Build the image and push it to a registry. Replace `` with a +Docker Hub namespace you can push to: + +```console +$ docker build -t docker.io//my-template:v1 --push . +``` + +For registry credentials and loading a locally built image, see +[Load a template](/manuals/ai/sandboxes/usage.md#load-a-template). + +Run the sandbox with your image: + +```console +$ sbx run claude --template docker.io//my-template:v1 +``` + +Because this image extends `claude-code`, use it with `claude`. For an +image based on `codex`, use `codex`. For one based on `shell`, use `shell` +to open Bash without an agent. + +If your added tools need network access, allow the domains they use in +the sandbox's network policy, unless you use the `allow-all` policy: + +```console +$ sbx policy allow network "*.example.com:443,example.com:443" +``` + +## Kit kinds + +### `kind: mixin` + +A mixin layers capabilities onto an existing sandbox. It must not declare a +`sandbox:` block, `extends:`, or `mixins:`. A mixin can declare `requires:` to +pin the base agent it is designed for: ```yaml schemaVersion: "2" -kind: -name: -version: -displayName: -description: -sourceURL: -licenses: - - MIT -locked: - - sandbox.image -security: - privileged: false -args: - channel: - default: stable - enum: [stable, beta] +kind: mixin +name: github-tools +requires: + agent: claude ``` +`requires.agent` takes one base-agent name. It is validated as a kit name and +enforced during composition. + +### `kind: sandbox` + +A sandbox kit defines a full agent. A root sandbox must declare a `sandbox:` +block. A sandbox that uses `extends:` can inherit the parent image and omit its +own `sandbox:` block: + +```yaml +schemaVersion: "2" +kind: sandbox +name: claude-safe +extends: claude +``` + +`extends:` is sandbox-only. The parent must resolve to a sandbox kit. `mixins:` +is also sandbox-only and accepted by the parser, but runtime composition support +is pending. + +## Top-level fields + +For the normative grammar, see the +[v2 specification](https://github.com/docker/sbx-kits-contrib/blob/main/spec/SPEC-v2.md). + | Field | Required | Description | | --------------- | -------- | ----------------------------------------------------------------------------------------------- | | `schemaVersion` | Yes | Spec schema version. Use `"2"` for this grammar. | @@ -152,45 +239,23 @@ Argument values are strings, but substitution happens before YAML decoding. Quote a placeholder in a string-valued field so a value such as `1.20` isn't decoded as a number. -Supply values with `--kit-arg` or `--kit-args-file` when loading the kit. See -[Pass arguments to kits](kits.md#pass-arguments-to-kits) for scoping, -precedence, and validation behavior. +### Pass arguments to kits -## Kit kinds +Use `--kit-arg name=value` for every kit declaring that argument, or prefix +with the kit's `name` to target one kit. Scoped values override shared values: -### `kind: mixin` - -A mixin layers capabilities onto an existing sandbox. It must not declare a -`sandbox:` block, `extends:`, or `mixins:`. A mixin can declare `requires:` to -pin the base agent it is designed for: - -```yaml -schemaVersion: "2" -kind: mixin -name: github-tools -requires: - agent: claude +```console +$ sbx run ./my-agent --kit ./my-mixin --kit-arg channel=stable \ + --kit-arg my-mixin.channel=beta ``` -`requires.agent` takes one base-agent name. It is validated as a kit name and -enforced during composition. - -### `kind: sandbox` - -A sandbox kit defines a full agent. A root sandbox must declare a `sandbox:` -block. A sandbox that uses `extends:` can inherit the parent image and omit its -own `sandbox:` block: - -```yaml -schemaVersion: "2" -kind: sandbox -name: claude-safe -extends: claude -``` - -`extends:` is sandbox-only. The parent must resolve to a sandbox kit. `mixins:` -is also sandbox-only and accepted by the parser, but runtime composition support -is pending. +`--kit-args-file ` reads `name=value` entries, ignoring blank lines and +`#` comments. Later files override earlier files; `--kit-arg` overrides files. +For repeated CLI keys, the last value wins. Missing required values, unknown +arguments, undeclared placeholders, and invalid values fail before creation. +Pass the same flags to `sbx kit validate` or `sbx kit inspect` when needed. +Argument values can remain in shell history and are stored unencrypted in +argument files. ## Sandbox block @@ -245,12 +310,7 @@ requirements. ## Agent instructions -```yaml -agentInstructions: - filename: CLAUDE.md - content: | - Ruff is installed. Run `ruff check` before committing. -``` +Declare these fields under `agentInstructions`: | Field | Description | | ---------- | --------------------------------------------------------------------------------------------------- | @@ -262,6 +322,11 @@ For mixins, the engine writes `content` to section to the base AI file. This keeps each mixin's instructions in a separate file. +The generated profile lives in the parent directory of the mounted workspace +inside the sandbox. It sits outside the mount and doesn't replace an +instruction file in the project. The sandbox kit's inline instructions go +directly into that profile. + ## Credentials A kit declares the credentials it needs and how the proxy injects them into @@ -270,41 +335,6 @@ provides the value through the secret store or the first-run prompt, and a [credential binding](../configuration/credentials.md) authorizes its use. A kit can't read arbitrary host environment variables or files. -```yaml -credentials: - - service: - description: # optional - required: # optional, default false - provider: # optional, reserved - apiKey: - name: - proxyManaged: true - inject: - - domain: - header:
- format: - - domain: - scheme: bearer - - domain: - scheme: basic - username: # required with scheme: basic - oauth: - tokenEndpoint: - host: - path: - sentinels: - accessToken: - refreshToken: - credentialFile: - path: - structure: - : - accessToken: "{{.AccessToken}}" - refreshToken: "{{.RefreshToken}}" - expiresAt: "{{.ExpiresAt}}" - scopes: "{{.Scopes}}" -``` - `credentials` is a list; each entry names a `service` and configures one or more auth mechanisms. @@ -363,13 +393,6 @@ their own domain mapping — the proxy injects a credential only into the domain its [`apiKey.inject`](#apikey) lists, and every domain the sandbox reaches must be allowed here. -```yaml -permissions: - network: - allow: [, ...] - deny: [, ...] -``` - | Field | Description | | --------------------------- | --------------------------------------------------------------------------------------------------------------- | | `permissions.network.allow` | Domains the sandbox can reach. | @@ -392,13 +415,7 @@ In v1 this was the `network:` block (`allowedDomains` / `deniedDomains`, plus ## Ports -Use `ports` to expose sandbox services to the host: - -```yaml -ports: - - container: 8080 - name: web -``` +Declare `ports` as a list of entries to expose sandbox services to the host: | Field | Description | | ----------- | ------------------------------------------------------------------- | @@ -415,15 +432,9 @@ in the sandbox is listening there. Users can pin host ports with ## Environment -```yaml -environment: - variables: - : -``` - | Field | Description | | ----------- | ---------------------------------------------- | -| `variables` | Key-value pairs set directly in the container. | +| `environment.variables` | Key-value pairs set directly in the container. | Do not set `DASH_`, `SBX_`, or `DOCKER_` variables, and avoid overriding `HOME`, `USER`, `SHELL`, `PATH`, `LD_PRELOAD`, and `LD_LIBRARY_PATH`. The @@ -431,24 +442,8 @@ runtime reserves these names and may override them. ## Setup -```yaml -setup: - install: - - command: - user: - description: - startup: - - command: [, ...] - user: - background: - description: - files: - - path: - content: - mode: - onlyIfMissing: - description: -``` +`setup.install`, `setup.startup`, and `setup.files` are lists of commands or +files with the fields described here. ### Execution order @@ -534,6 +529,14 @@ path must be writable by that user. To write to a root-owned path such as `/etc`, use an `install` command, which runs as root by default. Set ownership in the install command if the agent needs to modify the file later. +### Shell initialization and service logs + +With Docker templates, append shell initialization to +`/etc/sandbox-persistent.sh` in an install command. Keep existing content and +omit completion scripts: interactive and non-interactive Bash commands source +this file. For a background service, redirect startup output to a file and +read it with `sbx exec`. Use `background: true` instead of a trailing `&`. + ## Static files ```text @@ -551,18 +554,13 @@ Parent directories are created automatically. Existing files are overwritten. Absolute paths and path-traversal sequences (`../../`) are rejected. +Static files can supply linter settings, helper scripts, or agent skills. +For example, a Claude Code project skill belongs at +`files/workspace/.claude/skills//SKILL.md`. + ## Volumes -```yaml -volumes: - - path: /workspace - size: 10g - mode: "0755" - - path: /tmp/scratch - type: tmpfs - size: 512m - mode: "1777" -``` +Declare `volumes` as a list of mounts with these fields: | Field | Description | | ------ | ------------------------------------------------------------------- | @@ -573,3 +571,231 @@ volumes: Volumes are applied only when a sandbox is created. `sbx kit add` cannot attach volumes to a running container. + +## Fork an existing agent + +Sandbox kits (`kind: sandbox`) define a full agent from scratch. The most +common variant is a fork of a built-in agent. Use `extends:` to inherit the +parent's complete configuration and declare only the fields you want to change. +This example replaces the built-in `claude` entrypoint so Claude Code uses +manual permission mode instead of bypassing approval prompts: + +```yaml {title="claude-safe/spec.yaml"} +schemaVersion: "2" +kind: sandbox +name: claude-safe +displayName: Claude Code (with approval prompts) +description: Claude Code in manual permission mode + +extends: claude + +sandbox: + entrypoint: [claude, "--permission-mode", "manual"] +``` + +The child inherits the built-in image, credentials, network permissions, +persistent volumes, settings, MCP integration, agent instructions, setup +entries, and environment variables. Its `sandbox.entrypoint` replaces the +inherited entrypoint. + +Launch by passing the sandbox kit in place of a built-in agent name: + +```console +$ sbx run ./claude-safe +``` + +## Install an internal CA certificate + +Put each PEM-encoded root certificate under `files/home/` with a `.crt` +extension. For `files/home/internal-ca.crt`, use: + +```yaml {title="internal-ca/spec.yaml"} +schemaVersion: "2" +kind: mixin +name: internal-ca +setup: + install: + - command: "install -m 0644 /home/agent/internal-ca.crt /usr/local/share/ca-certificates/internal-ca.crt && update-ca-certificates" + user: "0" +``` + +This updates the system trust store. For several CAs, install every +certificate before running `update-ca-certificates`. + +## Sandbox-managed agent configuration + +Built-in agent kits reserve the following paths for sandbox setup. Treat these +paths as sandbox-managed, even if a file is only needed for a particular +feature. Don't target them with static files, `setup.files`, or install +commands. Later setup can replace your content or depend on settings that your +file removes. In this table, `~` is `/home/agent`. + +| Built-in agent kit | Managed configuration paths | +| ------------------ | --------------------------- | +| `claude` | `~/.claude.json`, `~/.claude/settings.json`, `~/.claude/.config.json` | +| `codex` | `~/.codex/config.toml` | +| `copilot` | `~/.copilot/config.json` | +| `cursor` | `~/.cursor/cli-config.json` | +| `devin` | `~/.config/devin/config.json`, `~/.config/devin/mcp_config.json` | +| `gemini` | `~/.gemini/settings.json` | +| `kiro` | `~/.kiro/settings/mcp.json` | +| `opencode` | `~/.config/opencode/opencode.json` | + +Use separate settings files when supported: Claude Code accepts `--settings`, +and OpenCode reads `OPENCODE_CONFIG`. Don't use `setup.startup` for settings +the agent must read during initialization; startup commands don't gate the +entrypoint. + +## Packaging and distribution + +The `sbx kit` subcommands validate, inspect, and publish kits: + +- `sbx kit validate ` — check that a kit directory or ZIP is + well-formed. +- `sbx kit inspect ` — display kit details. Add `--json` for + machine-readable output. +- `sbx kit pack -o ` — package a directory as a ZIP file + for sharing. +- `sbx kit push ` — publish to an OCI registry (for example, + `ghcr.io/myorg/my-kit:1.0`). +- `sbx kit pull ` — download a kit from a registry as a ZIP file to + the working directory. + +For Docker Hub, `sbx kit pull` and `sbx kit push` use the session from +`sbx login`. For other registries, they prefer credentials stored with +[`sbx secret set --registry`](../configuration/credentials.md#registry-credentials). +Both commands fall back to the Docker credential store, so credentials from +`docker login` also work. + +## Sign and verify kits + +Use cosign-compatible Sigstore signatures to verify who approved a kit and +that its signed content hasn't changed. Signing is keyless by default. Verify a +keyless signature with the certificate identity and OpenID Connect (OIDC) +issuer: + +```console +$ sbx kit sign ./my-kit/ +$ sbx kit verify \ + --certificate-identity user@example.com \ + --certificate-oidc-issuer https://accounts.google.com \ + ./my-kit/ +``` + +For key-based signing, use an ECDSA P-256 key pair: + +```console +$ sbx kit sign --key cosign.key ./my-kit/ +$ sbx kit verify --key cosign.pub ./my-kit/ +``` + +For a local directory, `sbx kit sign` writes a `kit.sig.bundle` file next to +`spec.yaml`. Commit this file so consumers can verify a kit loaded from the Git +repository. For an OCI kit, the signature is stored as an OCI referrer. You can +sign an OCI kit after pushing it, or push and sign it in one step: + +```console +$ sbx kit push ./my-kit/ ghcr.io/myorg/my-kit:1.0 --sign +``` + +ZIP kits can't carry verifiable signatures. + +### Require signed kits + +Set [`kit.trustedSigners`](../configuration/settings.md#kittrustedsigners) to +the identities or keys you trust before requiring signatures. Otherwise, `sbx` uses the default policy, which trusts +Docker employee identities attested by Google's OpenID Connect issuer. A +keyless policy must specify both the certificate identity and its OpenID +Connect issuer: + +```console +$ sbx settings set kit.trustedSigners \ + '[{"identity":"release-bot@example.com","issuer":"https://accounts.google.com"}]' +$ sbx settings set kit.requireSignature true +``` + +To trust a key-based signature, set the policy to the public key path: + +```console +$ sbx settings set kit.trustedSigners '[{"key":"/path/to/cosign.pub"}]' +$ sbx settings set kit.requireSignature true +``` + +When `kit.requireSignature` is `true`, `sbx` rejects unsigned kits, signatures +that don't match `kit.trustedSigners`, and ZIP kits. This policy applies when a +kit is loaded from a local directory, Git repository, or OCI registry. + +The signature covers `spec.yaml` and the kit's `files/` content, but not mutable +dependencies such as image tags or content downloaded by install and startup +commands. Pin those dependencies by digest or checksum when they must remain +immutable. + +## Schema versions + +Schema v2 is supported starting with Docker Sandboxes version 0.36. Use +`schemaVersion: "2"` for the syntax on this page. Version `"1"` also remains +accepted. V3 is a separate format for environments built entirely +with v3 workloads and mixins. V3 kits can't compose with v1 or v2 kits. +See [Kits v3](/manuals/ai/sandboxes/customize/_index.md) for that workflow. + +When migrating to `schemaVersion: "2"`, replace v1 fields with their v2 +equivalents: + +| v1 | v2 | +| ------------------------------------------- | ---------------------------------------- | +| `credentials.sources.` | `credentials:` list entry with `service` | +| `network.allowedDomains` / `deniedDomains` | `permissions.network.allow` / `deny` | +| `network.serviceDomains` / `serviceAuth` | `credentials[].apiKey.inject` | +| `network.publishedPorts` / `publishedPorts` | top-level `ports` | +| standalone `oauth:` block | `credentials[].oauth` | +| `oauth.skipIfEnv` | Accepted but ignored | +| `environment.proxyManaged` | `credentials[].apiKey.proxyManaged` | +| `memory` / `agentContext` | `agentInstructions.content` | +| `kind: agent` / `agent:` block | `kind: sandbox` / `sandbox:` block | +| `sandbox.aiFilename` | `agentInstructions.filename` | +| `sandbox.entrypoint.run` | `sandbox.entrypoint` | +| `sandbox.entrypoint.args` | `sandbox.command.default` | +| `sandbox.entrypoint.ttyArgs` | `sandbox.command.interactive` | +| `tmpfs:` | `volumes:` entries with `type: tmpfs` | +| `volumes:` (mapping form) | `volumes:` sequence (`- path: `) | +| `commands:` / `commands.initFiles` | `setup:` / `setup.files` | +| `settings:` / `kitDir` / `persistence` | Removed | + +Credential discovery also moved out of the kit in v2: a kit declares which +credentials it needs and how to inject them, but where each value comes from is +controlled by the user through +[credential bindings](../configuration/credentials.md#credential-bindings). + +> [!NOTE] +> `mixins` and `sandbox.build` are accepted by the parser, but runtime support +> is pending. A kit that sets `sandbox.build` must also set `sandbox.image`. + +## Move an environment to v3 + +Select a v3 workload, convert or replace its mixins, and create a separate +sandbox with a different `--name`. Use the explicit workload reference in +place of the built-in shortcut. Every selected kit must use v3. + +Changing `schemaVersion` alone doesn't convert a kit. Separate reusable image +content from sandbox initialization, and declare runtime capabilities: + +| V2 surface | V3 equivalent | +| --- | --- | +| `kind: sandbox` | `kind: workload` with a Dockerfile recipe | +| `sandbox.image` | Dockerfile `FROM` | +| `sandbox.entrypoint`, `sandbox.command`, `environment.variables` | Dockerfile `ENTRYPOINT`, `CMD`, and `ENV` | +| `extends` | A mixin for composition, or a derived workload image with its own descriptor | +| `setup.install` | Dockerfile `RUN` for reusable content; lifecycle `install` for sandbox initialization | +| `setup.startup` and `setup.files` | Lifecycle capability `startup` and `files` | +| `setup.files[].onlyIfMissing: true` | Lifecycle `files[].overwrite: false` | +| Automatic `files/home/` and `files/workspace/` injection | Dockerfile `COPY`, with lifecycle hooks for destinations provided by runtime mounts | +| `permissions.network` and `credentials` | Network-policy and credential capabilities | +| `agentInstructions` | Agent-context capability | + +Follow the [v3 authoring guidance](/manuals/ai/sandboxes/customize/author/_index.md) +when converting runtime setup and capability declarations. +Use a [kit set](/manuals/ai/sandboxes/customize/author/kit-sets.md) to combine +published v3 components with your settings. To rebuild the agent environment +from a base image, follow [Build an agent workload](/manuals/ai/sandboxes/customize/author/build-an-agent.md). +Running an existing sandbox keeps its recorded configuration. It doesn't +migrate the kit composition. diff --git a/content/manuals/ai/sandboxes/customize/kits.md b/content/manuals/ai/sandboxes/customize/kits.md deleted file mode 100644 index b6113892f7..0000000000 --- a/content/manuals/ai/sandboxes/customize/kits.md +++ /dev/null @@ -1,631 +0,0 @@ ---- -title: Kits -description: Extend a sandbox with tools, credentials, network rules, and configuration using declarative YAML artifacts. -keywords: sandboxes, sbx, kits, mixins, customization, extensions, agents -weight: 20 ---- - -{{< summary-bar feature_name="Docker Sandboxes sbx" >}} - -> [!NOTE] -> Kits are experimental. The kit file format, CLI commands, and experience -> for creating, loading, and managing kits are subject to change as the -> feature evolves. Share feedback and bug reports in the -> [docker/sbx-releases](https://github.com/docker/sbx-releases) repository. - -A kit packages a set of capabilities a sandbox can use, such as: - -- Tools to install -- Environment variables to set -- Credentials to inject -- Network rules to allow or deny domains -- Files to drop in -- Startup commands to run -- Memory instructions to give the agent - -You declare these in a single `spec.yaml` file, point the CLI at the -directory (or a ZIP, OCI artifact, or Git URL), and the sandbox applies -and enforces them at runtime. Credentials stay on the host and go through -a proxy instead of entering the VM, and outbound traffic is restricted to -the domains permitted by the kit's network rules. - -A kit is either a mixin or a sandbox: - -- Mixin kits (`kind: mixin`) extend an existing agent with extra - capabilities. Stack several on the same sandbox. -- Sandbox kits (`kind: sandbox`) define a full agent from scratch: its image, - entrypoint, network policies, and everything else the agent needs. - -## What kits can do - -### Run commands - -A kit can run commands inside the sandbox automatically. **Install -commands** run once at creation; **startup commands** run each time -the sandbox starts. - -Install commands are the place to put anything an agent needs into the -image, via `apt`, `pip`, `npm`, `curl | bash`, or whatever fits: - -```yaml -setup: - install: - - command: "apt-get update && apt-get install -y jq" -``` - -Startup commands are for work that can run alongside the agent, such as a -background service. They must be idempotent — see the -[`startup`](kit-reference.md#startup) spec reference: - -```yaml -setup: - startup: - - command: ["my-daemon"] - background: true -``` - -### Inject files - -Kits can inject files into the sandbox in two ways: **static files** bundled -with the kit, and **`setup.files`** written at startup with runtime values -substituted in. - -Static files work well for content that doesn't vary between sandboxes, such -as tool configurations, shared linter rules, helper scripts the agent can -invoke, or reference material like a style guide or API cheatsheet. - -```text -my-kit/ -├── spec.yaml -└── files/ - ├── home/ - │ └── .config/my-tool/settings.json - └── workspace/ - └── .editorconfig -``` - -`setup.files` cover content that depends on runtime values, such as an -absolute workspace path that a tool needs to bake into its config file -at startup: - -```yaml -setup: - files: - - path: /home/agent/.my-tool/config.json - content: '{"workspace": "${WORKDIR}"}' - onlyIfMissing: true -``` - -See [`setup.files`](kit-reference.md#files) in the spec reference for all -fields. - -#### Sandbox-managed agent configuration - -Built-in agent kits reserve the following paths for sandbox setup. Treat these -paths as sandbox-managed, even if a file is only needed for a particular -feature. Don't target them with static files, `setup.files`, or install -commands. Later setup can replace your content or depend on settings that your -file removes. In this table, `~` is `/home/agent`. - -| Built-in agent kit | Managed configuration paths | -| ------------------ | --------------------------- | -| `claude` | `~/.claude.json`, `~/.claude/settings.json`, `~/.claude/.config.json` | -| `codex` | `~/.codex/config.toml` | -| `copilot` | `~/.copilot/config.json` | -| `cursor` | `~/.cursor/cli-config.json` | -| `devin` | `~/.config/devin/config.json`, `~/.config/devin/mcp_config.json` | -| `gemini` | `~/.gemini/settings.json` | -| `kiro` | `~/.kiro/settings/mcp.json` | -| `opencode` | `~/.config/opencode/opencode.json` | - -Use a separate settings layer when the agent supports one. For example, Claude -Code can load an additional settings file with `--settings`, and OpenCode can -load one from the path in `OPENCODE_CONFIG`. See -[Customize agent settings](kit-examples.md#customize-agent-settings) for -examples. Don't use `setup.startup` for settings the agent must read during -initialization because startup commands don't gate the agent entrypoint. - -### Set environment variables - -Environment variables set by the kit are available to the agent at -runtime: - -```yaml -environment: - variables: - MY_TOOL_WORKSPACE: /home/agent/my-tool -``` - -For credentials, see -[Authenticate to external services](#authenticate-to-external-services). -Don't put secret values directly in `environment.variables` — they'd -be visible inside the sandbox VM. - -> [!IMPORTANT] -> The sandbox manages proxy settings for you. It sets `HTTP_PROXY`, -> `HTTPS_PROXY`, `NO_PROXY`, and their lowercase equivalents automatically so -> that traffic flows through its built-in forward proxy, which enforces -> network policy and injects credentials. Leave these variables to the -> sandbox — setting them in a kit points traffic away from the forward proxy, -> so it can no longer apply network policy or inject credentials, and those -> requests typically fail to connect. To send sandbox traffic through an -> upstream corporate proxy, configure it on the host. See -> [Upstream proxy](../architecture.md#upstream-proxy). - -### Control network access - -Network rules define which domains the sandbox can reach or block. Kit -network rules apply only to sandboxes that use the kit: - -```yaml -permissions: - network: - allow: - - api.example.com - - "*.cdn.example.com" - deny: - - telemetry.example.com -``` - -Use `allow` for hosts the agent needs, such as package -registries, install endpoints, or external APIs. Use `deny` for -hosts the agent should not reach, such as telemetry endpoints. If a domain -matches both an allow rule and a deny rule, the deny rule wins. - -> [!IMPORTANT] -> When organization governance is active, only organization allow rules grant -> access, so kit-defined `allow` rules are ignored — including any domains a kit -> allows for the agent to reach. Kit-defined `deny` rules still apply, because a -> deny can only restrict access further. For details, see -> [Policy precedence](../governance/concepts.md#precedence). - -For authenticated services, see -[Authenticate to external services](#authenticate-to-external-services). - -### Authenticate to external services - -A kit can attach credentials to outbound requests through the -host-side proxy. The agent inside the VM works with a sentinel value; -the proxy reads the real credential on the host and overwrites the -auth header before the request leaves the sandbox. - -A kit declares the service, the in-container environment variable, and how -to inject the credential. It doesn't declare a host discovery source. The user -provides the value through the secret store or first-run prompt, and a -[credential binding](../configuration/credentials.md) authorizes its use: - -```yaml -credentials: - - service: my-service - apiKey: - name: MY_SERVICE_API_KEY # in-VM env var, set to a sentinel - proxyManaged: true - inject: - - domain: api.example.com # inject on requests to this domain - header: Authorization # overwrite this header - format: "Bearer %s" - -permissions: - network: - allow: - - api.example.com # the domain must also be reachable -``` - -The agent boots with `MY_SERVICE_API_KEY=proxy-managed`, sends a -request with that sentinel in `Authorization`, and the proxy overwrites -the header with the real credential before forwarding. The real -secret never enters the VM. - -See [Credentials](../configuration/credentials.md) for how to provide the -credential value on your host, other approaches for cases the example -above doesn't fit, and what the proxy does at request time. See -[Credential bindings](../configuration/credentials.md) to approve the mechanisms -and domains declared by a third-party v2 kit. - -### Inject agent memory - -A kit can append content to the agent's memory file, such as `CLAUDE.md` -or `AGENTS.md`. The agent reads this file at startup. Use it to give -the agent project conventions, usage tips for a tool the kit installs, -or other guidance that should be in scope when the sandbox runs. - -```yaml -agentInstructions: - content: | - Ruff is installed. Run `ruff check` before committing. - Shared config lives at `/workspace/ruff.toml`. -``` - -Both mixin and sandbox kits can declare `agentInstructions.content`. The active -sandbox kit sets `agentInstructions.filename`, which determines the memory -file's name. The sandbox kit's content is written inline in that file. Each -mixin's content is written to its own `.md` file under a sibling -`kits-memory/` directory, and the main memory file gets a `## Kits` section that -points to each mixin file: - -```text -/Users/you/ -├── myproject/ # workspace -├── AGENTS.md # main memory file with a "## Kits" index -└── kits-memory/ - ├── ruff-lint.md - ├── vale.md - └── git-ssh-sign.md -``` - -See [`agentInstructions`](kit-reference.md#agent-instructions) in the spec -reference for the full field schema. - -### Define an agent - -Sandbox kits declare a `sandbox:` block with the image the agent runs in and -the command the user attaches to when they launch the sandbox: - -```yaml -sandbox: - image: "my-registry/my-agent:latest" - entrypoint: [my-agent, "--yolo"] -``` - -See [Sandbox kits](#sandbox-kits) for use cases and an example. - -## Mixin kits - -A mixin kit extends an existing agent with extra capabilities. Common use -cases: - -- Pre-install tools: linters, libraries, or other custom programs -- Grant the agent access to a new authenticated service (a database, a - vendor API) -- Inject shared team config (linter rules, editor settings, dotfiles) - -See [Drop a shared config file](kit-examples.md#drop-a-shared-config-file) and -[Install a tool at sandbox creation](kit-examples.md#install-a-tool-at-sandbox-creation) -for complete mixin examples. - -## Sandbox kits - -A sandbox kit defines a full agent from scratch — image, entrypoint, and -everything the agent needs. Common use cases: - -- Package a custom agent you've built so others can run it -- Ship a team-internal agent with defaults baked in -- Run a fork of an existing agent with your own config -- Prototype a new agent integration - -Sandbox kits declare everything a mixin kit can, plus an -[`sandbox:` block](kit-reference.md#sandbox-block) that tells the sandbox how to launch the -agent. For a step-by-step walkthrough, see -[Build your own agent kit](build-an-agent.md). - -### Extend a built-in agent - -Use `extends:` to create a variant of a built-in agent without reproducing its -configuration. The child kit inherits the parent's image, credentials, network -permissions, persistent volumes, settings, MCP integration, and agent -instructions. It also inherits the parent's environment variables and all -`setup.install`, `setup.startup`, and `setup.files` entries. Parent setup entries -run before child entries. If both kits set the same environment variable, the -child's value wins. Use `extends:` for a single parent agent; use a mixin to add -an independent capability that can work with one or more agents. See -[Fork an existing agent](kit-examples.md#fork-an-existing-agent) for an example -that changes Claude Code's permission mode. - -## Using kits - -Kits can be loaded from a local path (a directory or ZIP file), a Git -repository, or an OCI registry. To launch a sandbox kit, pass its reference in -place of a built-in agent name to `sbx run` or `sbx create`. Use `--kit` for -mixins, and repeat the flag to apply multiple mixins to the same sandbox. - -Starting with Docker Sandboxes version 0.42.0, pass the sandbox kit reference -as the first argument: - -```console -$ sbx run [PATH...] -$ sbx create [PATH...] -``` - -The previous form, `sbx run --kit `, is -deprecated. - -> [!IMPORTANT] -> A mixin passed with `--kit` only takes effect when a sandbox is created. -> Passing it against an -> existing sandbox name fails with -> `--kit can only be used when creating a new sandbox`. To add a supported -> mixin kit to a running sandbox, use [`sbx kit add`](#local) instead. -> `sbx kit add` restarts the sandbox to apply the updated kit set. -> VM state — installed packages, Docker images, volumes, and agent history -> — is preserved across the restart. It supports mixin kits limited to -> `environment.variables`, `setup.install`, and `permissions.network.allow`. -> To use other fields, recreate the sandbox with the mixin. - -### Pass arguments to kits - -A schema v2 kit can declare inputs in a top-level `args:` block and reference -them in `spec.yaml` or static files with `${{ kit.args. }}`. Supply a -value with `--kit-arg name=value`: - -```console -$ sbx run ./my-agent/ --kit-arg channel=beta -``` - -Kit argument values are plain text. Values supplied with `--kit-arg` can remain -in your shell history, and argument files store their values unencrypted. Don't -use kit arguments for secrets. Use [Credentials](../configuration/credentials.md) -instead. - -An argument without a kit name prefix applies to every kit that declares it. -To target one kit, prefix the argument with the value of that kit's `name` -field and a period: - -```console -$ sbx run ./my-agent/ \ - --kit ./my-mixin/ \ - --kit-arg version=1.2.3 \ - --kit-arg my-mixin.version=2.0.0 -``` - -The kit-specific value takes precedence over the shared value for `my-mixin`. - -Use `--kit-args-file` for a reusable set of `name=value` entries. Blank lines -and lines that start with `#` are ignored: - -```text {title="kit.args"} -version=1.2.3 -my-mixin.channel=beta -``` - -```console -$ sbx create ./my-agent/ . \ - --kit ./my-mixin/ \ - --kit-args-file ./kit.args \ - --kit-arg my-mixin.channel=stable -``` - -When you pass multiple argument files, a value in a later file overrides the -same key in an earlier file. Values passed with `--kit-arg` override every -file. For repeated `--kit-arg` entries with the same key, the last value wins. - -Argument validation happens before the sandbox is created. `sbx` rejects a -missing required value, a value outside its declared `enum` or `pattern`, a -placeholder without a declaration, and a supplied argument that no resolved -kit declares. Pass the same argument flags to `sbx kit validate` or -`sbx kit inspect` when the kit requires values. See -[Kit arguments](kit-reference.md#arguments) for the declaration fields. - -### Local - -Launch a local sandbox kit by passing its directory or ZIP file in place of the -agent name. Relative paths must start with `./` or `../` so `sbx` can -distinguish them from agent and sandbox names: - -```console -$ sbx run ./my-agent/ -$ sbx create ../my-agent-1.0.zip . -``` - -Pass a local mixin with `--kit`: - -```console -$ sbx run claude --kit ./my-mixin/ -$ sbx run claude --kit ../my-mixin-1.0.zip -``` - -While iterating on a supported mixin kit, apply changes to a running sandbox -with `sbx kit add`: - -```console -$ sbx kit add my-sandbox ./my-kit/ -``` - -`sbx kit add` restarts the sandbox to apply the updated kit set. -VM state — installed packages, Docker images, volumes, and agent history — is -preserved across the restart. Kits can't be removed from a running sandbox — -remove and recreate it to start clean. - -### Git repository - -Launch a sandbox kit from a Git repository: - -```console -$ sbx run "git+https://github.com/docker/sbx-kits-contrib.git#ref=v0.1.0&dir=amp" -``` - -Pass a Git-hosted mixin with `--kit`: - -```console -$ sbx run claude --kit "git+https://github.com/docker/sbx-kits-contrib.git#ref=v0.1.0&dir=code-server" -``` - -- `#ref=` pins to a specific revision. Defaults to the - repository's default branch. -- `#dir=` loads a kit from a subdirectory. -- `git+ssh://` URLs also work, using your local SSH agent, Git credential - helpers, and `.netrc`. -- Quote the URL in shells where `&` starts a background job. - -### OCI registry - -Launch a sandbox kit from an OCI registry: - -```console -$ sbx run docker.io/sbx/droid-kit:latest -``` - -Pass an OCI-hosted mixin with `--kit`: - -```console -$ sbx run claude --kit ghcr.io/myorg/my-kit:1.0 -``` - -For Docker Hub, include the full `docker.io` prefix. See -[Packaging and distribution](#packaging-and-distribution) for publishing. - -> [!IMPORTANT] -> For Docker Hub, `sbx` reuses your `sbx login` session to pull private -> kits. For other registries, store pull credentials with -> [`sbx secret set --registry`](../configuration/credentials.md#registry-credentials) -> before running the sandbox. These credentials take priority over credentials -> in the Docker credential store: -> -> ```console -> $ gh auth token | sbx secret set --registry ghcr.io --password-stdin -> ``` -> -> Without credentials from either store, pulls from non-Docker Hub registries -> are anonymous and private kits fail to pull. - -### Restrict kit sources - -`sbx` restricts which sources a kit can install from. A kit's install -commands run with root privileges inside the sandbox, so limiting where kits -come from reduces supply-chain risk. By default, only kits hosted on Docker -Hub (`docker.io/`) are allowed. Loading a kit from any other source fails: - -```console -$ sbx run claude --kit "git+https://github.com/docker/sbx-kits-contrib.git#dir=vale" -ERROR: resolve kits: kit "git+https://github.com/docker/sbx-kits-contrib.git#dir=vale" cannot be installed — its source is not in your allowlist. -``` - -To allow another publisher, add its host or host/path prefix to the -[`kit.allowedSources`](../configuration/settings.md#kitallowedsources) setting. -The setting replaces the whole list, so include the entries you want to keep: - -```console -$ sbx settings set kit.allowedSources '["docker.io/","github.com/docker/"]' -``` - -Entries match as prefixes on a path-segment boundary, so `github.com/docker/` -allows `github.com/docker/sbx-kits-contrib` but not `github.com/docker-evil/kit`. -To remove the restriction and allow any remote source, set the list to -`["*"]`. This isn't recommended. - -Installing from a local directory or ZIP file is governed separately by the -`kit.allowLocalKits` setting, which defaults to `true`. Set it to `false` to -require a remote source: - -```console -$ sbx settings set kit.allowLocalKits false -``` - -For defaults and environment variable equivalents, see the -[kit settings reference](../configuration/settings.md#kits). - -## Sign and verify kits - -Use cosign-compatible Sigstore signatures to verify who approved a kit and -that its signed content hasn't changed. Signing is keyless by default. Verify a -keyless signature with the certificate identity and OpenID Connect (OIDC) -issuer: - -```console -$ sbx kit sign ./my-kit/ -$ sbx kit verify \ - --certificate-identity user@example.com \ - --certificate-oidc-issuer https://accounts.google.com \ - ./my-kit/ -``` - -For key-based signing, use an ECDSA P-256 key pair: - -```console -$ sbx kit sign --key cosign.key ./my-kit/ -$ sbx kit verify --key cosign.pub ./my-kit/ -``` - -For a local directory, `sbx kit sign` writes a `kit.sig.bundle` file next to -`spec.yaml`. Commit this file so consumers can verify a kit loaded from the Git -repository. For an OCI kit, the signature is stored as an OCI referrer. You can -sign an OCI kit after pushing it, or push and sign it in one step: - -```console -$ sbx kit push ./my-kit/ ghcr.io/myorg/my-kit:1.0 --sign -``` - -ZIP kits can't carry verifiable signatures. - -### Require signed kits - -Set [`kit.trustedSigners`](../configuration/settings.md#kittrustedsigners) to -the identities or keys you trust before requiring signatures. Otherwise, `sbx` -uses the default policy, which trusts -Docker employee identities attested by Google's OpenID Connect issuer. A -keyless policy must specify both the certificate identity and its OpenID -Connect issuer: - -```console -$ sbx settings set kit.trustedSigners \ - '[{"identity":"release-bot@example.com","issuer":"https://accounts.google.com"}]' -$ sbx settings set kit.requireSignature true -``` - -To trust a key-based signature, set the policy to the public key path: - -```console -$ sbx settings set kit.trustedSigners '[{"key":"/path/to/cosign.pub"}]' -$ sbx settings set kit.requireSignature true -``` - -When `kit.requireSignature` is `true`, `sbx` rejects unsigned kits, signatures -that don't match `kit.trustedSigners`, and ZIP kits. This policy applies when a -kit is loaded from a local directory, Git repository, or OCI registry. - -The signature covers `spec.yaml` and the kit's `files/` content, but not mutable -dependencies such as image tags or content downloaded by install and startup -commands. Pin those dependencies by digest or checksum when they must remain -immutable. - -## Packaging and distribution - -The `sbx kit` subcommands validate, inspect, and publish kits: - -- `sbx kit validate ` — check that a kit directory or ZIP is - well-formed. -- `sbx kit inspect ` — display kit details. Add `--json` for - machine-readable output. -- `sbx kit pack -o ` — package a directory as a ZIP file - for sharing. -- `sbx kit push ` — publish to an OCI registry (for example, - `ghcr.io/myorg/my-kit:1.0`). -- `sbx kit pull ` — download a kit from a registry as a ZIP file to - the working directory. - -For Docker Hub, include the full `docker.io` prefix — `sbx` doesn't add it -automatically. - -For Docker Hub, `sbx kit pull` and `sbx kit push` use the session from -`sbx login`. For other registries, they prefer credentials stored with -[`sbx secret set --registry`](../configuration/credentials.md#registry-credentials). -Both commands fall back to the Docker credential store, so credentials from -`docker login` also work. - -## Spec reference - -For a field-by-field reference of every `spec.yaml` block — top-level -fields, arguments, credentials, network, environment, setup, static files, -agent instructions, and the sandbox block — see [Kit spec reference](kit-reference.md). - -## Debugging - -When a kit doesn't behave as expected, start with the network policy log -and direct inspection inside the sandbox: - -- `sbx policy log` shows every outbound request the sandbox proxy saw, - the rule it matched, extra context when available, and its `PROXY` - value, such as `forward`, `forward-bypass`, `transparent`, or - `browser-open`. Use it to diagnose install-time download failures, - blocked domains, and unexpected TLS interception. If downloads fail or - arrive corrupted after you add a credential's `apiKey.inject`, check - whether an injection domain is too broad. Inject only on the hosts that - need credentials. -- `sbx exec -- ` runs an arbitrary command inside an - existing sandbox. Useful for inspecting post-install state without - recreating: `which mytool`, `ls /home/agent/.local/bin/`, - `cat /home/agent/.config/...`, and so on. - -Install and startup command output is only emitted during `sbx run` or -`sbx create`; `sbx` doesn't retain it for later inspection. To repeat -setup with fresh output, remove and recreate the sandbox: -`sbx rm && sbx run ...`. diff --git a/content/manuals/ai/sandboxes/customize/templates.md b/content/manuals/ai/sandboxes/customize/templates.md deleted file mode 100644 index 87ae9b01a2..0000000000 --- a/content/manuals/ai/sandboxes/customize/templates.md +++ /dev/null @@ -1,270 +0,0 @@ ---- -title: Templates -weight: 10 -description: Build reusable sandbox images with tools and configuration baked in, or save a running sandbox as a template. -keywords: sandboxes, sbx, templates, images, dockerfile, snapshot, custom environments ---- - -{{< summary-bar feature_name="Docker Sandboxes sbx" >}} - -Every sandbox is customizable — agents install packages, pull images, and -configure tools as they work, and those changes persist for the sandbox's -lifetime. Templates capture a configured environment into a reusable image -so you don't have to set it up again every time. - -## Custom templates - -Custom templates are reusable sandbox images that extend one of the built-in -agent environments with additional tools and configuration baked in. Instead -of asking the agent to install packages every time, build a template once and -reuse it across sandboxes and team members. - -Templates make sense when multiple people need the same environment, when -setup involves steps that are tedious to repeat, or when you need pinned -versions of specific tools. For one-off work, the default image is fine — -ask the agent to install what's needed. - -> [!NOTE] -> Custom templates customize an existing agent's environment — they don't -> create new agent runtimes. The agent that launches inside the sandbox is -> determined by the base image variant you extend and the agent you specify -> in the `sbx run` command, not by binaries installed in the template. To -> define a new agent from scratch, see [Kits](kits.md#define-an-agent). - -### Base images - -All sandbox templates are published as -`docker/sandbox-templates:`. They are based on Ubuntu and run as a -non-root `agent` user with sudo access. Most variants include Git, Docker -CLI, and common development tools like Node.js, Python, Go, and Java. - -| Variant | Agent | -| --------------------- | -------------------------------------------------------------------- | -| `claude-code` | [Claude Code](https://claude.ai/download) | -| `claude-code-minimal` | Claude Code with a minimal toolset (no Node.js, Python, Go, or Java) | -| `codex` | [OpenAI Codex](https://github.com/openai/codex) | -| `copilot` | [GitHub Copilot](https://github.com/github/copilot-cli) | -| `cursor-agent` | [Cursor](https://cursor.com/cli) | -| `devin` | [Devin CLI](https://docs.devin.ai/work-with-devin/devin-cli) | -| `docker-agent` | [Docker Agent](https://github.com/docker/docker-agent) | -| `droid` | [Droid](https://www.factory.ai) | -| `gemini` | [Gemini CLI](https://github.com/google-gemini/gemini-cli) | -| `kiro` | [Kiro](https://kiro.dev) | -| `opencode` | [OpenCode](https://opencode.ai) | -| `shell` | No agent pre-installed. Use for manual agent setup. | - -Each variant also has a `-docker` version (for example, `claude-code-docker`) -that includes a full Docker Engine running inside the sandbox — no local Docker -daemon required. When you pick a built-in agent without specifying a custom -template, `sbx run` and `sbx create` use the `-docker` template variants by -default. - -The agent containers created from the `-docker` templates run in privileged -mode inside the microVM (not on your host), with a dedicated block volume at -`/var/lib/docker`, and `dockerd` starts automatically inside the sandbox. The -block volume defaults to 10 GB and uses a sparse file, so it only consumes -disk space as Docker writes to it. - -To change the volume size for a sandbox, set -`DOCKER_SANDBOXES_DOCKER_SIZE` when you create it: - -```console -$ DOCKER_SANDBOXES_DOCKER_SIZE=20g sbx run claude -``` - -The volume size must be at least 512 MiB. The environment variable doesn't -resize existing volumes. - -Use the non-Docker variant if you don't need to build or run containers -inside the sandbox and want a lighter, non-privileged environment. Specify -it explicitly with `--template`: - -```console -$ sbx run claude --template docker.io/docker/sandbox-templates:claude-code -``` - -### Build a custom template - -Building a custom template requires -[Docker Desktop](/manuals/desktop/_index.md). - -Write a Dockerfile that extends one of the base images. Pick the variant -that matches the agent you plan to run. For example, extend `claude-code` -to customize a Claude Code environment, or `codex` to customize an OpenAI -Codex environment. - -The following example creates a Claude Code template with Rust and -protocol buffer tools pre-installed: - -```dockerfile -FROM docker/sandbox-templates:claude-code -USER root -RUN apt-get update && apt-get install -y protobuf-compiler -USER agent -RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y -``` - -Use `root` for system-level package installations (`apt-get`), and switch -back to `agent` before installing user-level tools. Tools that install into -the home directory, such as `rustup`, `nvm`, or `pyenv`, must run as -`agent` — otherwise they install under `/root/` and aren't available in -the sandbox. - -Build the image and push it to an OCI registry, such as Docker Hub: - -```console -$ docker build -t my-org/my-template:v1 --push . -``` - -> [!NOTE] -> The Docker daemon used by Docker Sandboxes pulls templates from a -> registry directly; it doesn't share the image store of your local Docker -> daemon on the host. To route Docker Hub image pulls through your -> organization's registry infrastructure, configure a -> [registry mirror](../configuration/registry-mirror.md). - -> [!IMPORTANT] -> For Docker Hub, `sbx` reuses your `sbx login` session to pull private -> images. For other registries (GitHub Container Registry, ECR, ACR, a -> self-hosted Nexus, and so on), store pull credentials with -> [`sbx secret set --registry`](../configuration/credentials.md#registry-credentials) -> before running the sandbox: -> -> ```console -> $ gh auth token | sbx secret set --registry ghcr.io --password-stdin -> ``` -> -> Without stored credentials, pulls from non-Docker Hub registries are -> anonymous and private images fail to pull. - -For locally-built images, save the image to a tar and load it directly -into the sandbox runtime instead of pulling from a registry: - -```console -$ docker image save my-org/my-template:v1 -o my-template.tar -$ sbx template load my-template.tar -$ sbx run --template my-org/my-template:v1 claude -``` - -`sbx template load` imports the tar into the sandbox runtime's image -store, so the image doesn't need to be reachable from a registry at -sandbox creation time. - -Unless you use the permissive `allow-all` network policy, you may also need -to allow-list any domains that your custom tools depend on: - -```console -$ sbx policy allow network "*.example.com:443,example.com:443" -``` - -Then run a sandbox with your template. The agent you specify must match -the base image variant your template extends: - -```console -$ sbx run --template docker.io/my-org/my-template:v1 claude -``` - -Because this template extends the `claude-code` base image, you run it -with `claude`. If you extend `codex`, use `codex`; if you extend `shell`, -use `shell` (which drops you into a Bash shell with no agent). - -> [!NOTE] -> Unlike Docker commands, `sbx` does not automatically resolve the Docker -> Hub domain (`docker.io`) in image references. - -### Template caching - -When creating a sandbox, `sbx` checks the registry for the template image by -default and downloads missing or updated layers. If the pull fails and the -image is cached locally, it can use the cached image. Cached images persist -across sandbox creation and deletion, and are cleared when you run `sbx reset`. - -### Updating agents - -Agent templates include an agent version, which can differ from the agent's -latest release. Updating the `sbx` CLI or pulling an updated template doesn't -update agents inside existing sandboxes. - -To update an installed agent, run its documented update command inside the -sandbox, either from a sandbox shell or with `sbx exec`. Restart the agent -session to use the updated version. The update persists across sandbox stops -and starts, but is deleted when you remove the sandbox. To reuse the updated -agent in other sandboxes, [save a template](#saving-a-sandbox-as-a-template). - -## Saving a sandbox as a template - -Instead of writing a Dockerfile, you can save a running sandbox's state as -a template. This captures installed packages, configuration changes, and -files into a reusable image — useful when you've set up an environment -interactively and want to preserve it. - -> [!WARNING] -> Saving a sandbox captures its entire filesystem, including any secrets -> stored on it. If you manually added API keys, tokens, or other -> credentials to the sandbox, they're embedded in the saved template and -> shared with anyone you distribute it to. To keep credentials out of -> templates, manage them with `sbx secret set` instead — the proxy injects -> them at runtime so they're never written to the filesystem. For more -> information, see [Manage credentials](../configuration/credentials.md). - -### Save and reuse - -Stop the sandbox (or let the CLI prompt you), then save it with a name and -tag: - -```console -$ sbx template save my-sandbox my-template:v1 -``` - -The image is stored in the sandbox runtime's local image store. Create a -new sandbox from it with the `-t` flag: - -```console -$ sbx run -t my-template:v1 claude -``` - -### List and remove templates - -List all saved templates: - -```console -$ sbx template ls -``` - -Remove a template you no longer need: - -```console -$ sbx template rm my-template:v1 -``` - -### Export and import - -To share a saved template or move it to another machine, export it as a -tar file: - -```console -$ sbx template save my-sandbox my-template:v1 --output my-template.tar -``` - -On the other machine, load the tar file and use it: - -```console -$ sbx template load my-template.tar -$ sbx run -t my-template:v1 claude -``` - -### Limitations - -Agent configuration files are always recreated when a sandbox is created. -Changes to user-level agent configuration files, such as -`/home/agent/.claude/settings.json` and `/home/agent/.claude.json`, do not -persist in saved templates. - -If the saved template was built for a different agent than the one you -specify in `sbx run`, you get a warning. For example, saving a Claude -sandbox and running it with `codex` produces: - -```text -⚠ WARNING: template "my-template:v1" was built for the "claude" agent but you are using "codex". - The sandbox may not work correctly. Consider using: sbx run -t my-template:v1 claude -``` diff --git a/content/manuals/ai/sandboxes/customize/use-kits.md b/content/manuals/ai/sandboxes/customize/use-kits.md new file mode 100644 index 0000000000..c2800e303d --- /dev/null +++ b/content/manuals/ai/sandboxes/customize/use-kits.md @@ -0,0 +1,302 @@ +--- +title: Use kits +description: Run published v3 kit sets and workloads, add compatible mixins, and configure kit arguments and runtime access. +keywords: sandboxes, sbx, kits, v3, workloads, mixins +weight: 10 +--- + +{{< summary-bar feature_name="Docker Sandboxes sbx" >}} + +If you've run `sbx run claude` or `sbx run codex`, you've already used a kit. +The built-in agents are kits that package an environment, tools, and runtime +settings. You run kits you build yourself or get from another publisher in the +same way: give `sbx` a reference, and Docker Sandboxes prepares the environment +and applies the kit's settings. + +This page shows how to run published kits, combine them with mixins, and +customize their settings. + +## Run a kit + +The built-in agent names are shortcuts for kit references. To run another kit, +replace the agent name with that kit's reference. For example, run Docker's +published v3 Codex workload: + +```console +$ sbx run docker.io/docker/sbx-kit-codex:0.155.1 --name codex-v3-kit +``` + +This starts Codex using a v3 kit from Docker Hub. The built-in `codex` +shortcut uses a v2 kit to preserve compatibility with existing customizations. + +### Choose a kit source + +The previous example uses a published image from Docker Hub. You can also +run a kit from a local directory or a Git repository. The same source types +work for mixins added with `--kit`: + +| Source | Example reference | +| --- | --- | +| Published image | `docker.io/my-org/agent-kit:1.0.0` | +| Local directory | `./my-agent` | +| Git repository | `git+https://github.com//.git#ref=&dir=my-agent` | + +For Git sources, `ref` selects a revision and `dir` selects the kit's +subdirectory. Quote Git URLs in shell commands because they can contain `&`: + +```console +$ sbx run "git+https://github.com//.git#ref=&dir=my-agent" +``` + +`sbx` pulls published images and builds local or Git sources when creating +the sandbox. Builds with unchanged source content and supplied kit arguments +reuse cached results. + +By default, remote kit sources are limited to Docker Hub. To use a Git +source or another registry, see [Restrict kit sources](#restrict-kit-sources). +For private images, see +[Registry credentials](/manuals/ai/sandboxes/configuration/credentials.md#registry-credentials). + +## Reuse a sandbox + +A sandbox keeps the kit configuration it was created with. To return to the +sandbox from the previous example, specify its name: + +```console +$ sbx run --name codex-v3-kit +``` + +You don't need to specify the kit reference again. To try a different workload, +mixin combination, or argument value, create a sandbox with a different name +or recreate the existing one. To add a mixin to an existing sandbox, see +[Add mixins](#add-mixins). + +## Runtime access and instructions + +A kit can request access to the services it needs. For example, the Codex +workload needs to reach OpenAI and authenticate. If you use an API key, +store it on your host and approve the kit's request to use it. These are +separate steps: storing a secret doesn't give a third-party kit permission to +use it. See +[Credential bindings](/manuals/ai/sandboxes/configuration/credentials.md#credential-bindings) +for preparing unattended runs. + +Check the kit's documentation for the services it contacts, the credentials +it needs, and the commands it runs at startup. For proxy-managed credentials, +the kit's credential binding tells the proxy which credential to add to +requests to the service. Once you approve the binding, the proxy adds the +credential to outgoing requests. The credential value stays on your host +and isn't exposed inside the sandbox. + +Network requests must also meet your sandbox's network policy. Kit allow rules +can't grant access beyond your organization's policy. If a connection fails, +check the [policy log](#debug-kits) to see which rule blocked it. + +Kits can also give the agent instructions for using their tools. The workload +chooses the instruction file, and mixins add their guidance to it. Docker +Sandboxes writes that file outside your workspace, leaving your project's +instructions intact. + +## Add mixins + +Mixins add tools and configuration to a workload. Use `--kit` to add a mixin +when creating a sandbox. For v3 kits, both the workload and the mixin must +use v3. + +For example, an internal CLI mixin can package your company's executable +along with network rules and a credential request for its API: + +```console +$ sbx run docker.io/docker/sbx-kit-codex:0.155.1 --name codex-tools \ + --kit docker.io//company-cli:1.0.0 +``` + +Replace the mixin reference with one your organization has published. +To build your own, see +[Build a tool mixin](/manuals/ai/sandboxes/customize/author/tool-mixins.md). +Store the credential requested by the mixin on the host and approve access +when prompted. + +Codex starts with `company-cli` available to use. Docker Sandboxes +applies the files and settings from both the workload and the mixin. + +Built-in shortcuts such as `claude` and `codex` use v2 kits and require +[v2 mixins](/manuals/ai/sandboxes/customize/kits-v2.md). +See [Version compatibility](/manuals/ai/sandboxes/customize/_index.md#version-compatibility) +for details. + +### Combine multiple mixins + +Repeat `--kit` to add more mixins. You can also add compatible mixins to a +published workload set, or pass a set containing only mixins with `--kit`. + +Avoid adding a kit that's already in the set. If two kits provide the same +feature, Docker Sandboxes can reject the combination. + +To publish your combination as one reference, see +[Compose a kit set](/manuals/ai/sandboxes/customize/author/kit-sets.md). + +### Change a sandbox's mixins + +For v3 kits, you choose the mixins when you create the sandbox. To use a +different combination, create another sandbox with a different name. +Specify the workload and all the mixins you want to include. + +The `sbx kit add` command can't add mixins to an existing v3 sandbox. + +The new sandbox doesn't inherit changes or kit volume data from the previous sandbox. + +## Compose kits + +Some mixins need a tool another kit supplies. For example, a mixin whose +scripts call `gojq` can declare that dependency: + +```yaml +requires: [gojq] +``` + +The [gojq mixin example](/manuals/ai/sandboxes/customize/author/patterns.md#leave-build-tools-out-of-the-mixin) +declares the feature it provides: + +```yaml +provides: ["gojq@0.12.17"] +``` + +Include both mixins when you create the sandbox. Docker Sandboxes applies +the gojq mixin before the mixin whose scripts need it, regardless of the order +of your `--kit` flags. If you leave out gojq, sandbox creation fails. + +A `requires` entry tells Docker Sandboxes what a kit needs. You still choose +and include the kit that provides it. Docker Sandboxes doesn't download a +kit for you based on this entry. A kit can also require a minimum feature +version or rule out incompatible kits. + +With `--kit`, Docker Sandboxes checks and combines the kits when it creates +the sandbox. For a set, this happens when the publisher builds it. The +published kit includes a record of the exact components used, identified by +their image digests. + +To declare these relationships in your own kits, see +[Composition fields](https://github.com/docker/sandbox-kit-spec/blob/main/docs/spec/SPEC-v3.md#5-provides-requires-integrates-conflicts). + +## Pass arguments to kits + +Kits can expose arguments for settings such as a linter's mode. Check the +kit's documentation for argument names, defaults, and accepted values. +Use `--kit-arg name=value` to set an argument: + +```console +$ sbx run docker.io//codex-tools:1.0.0 \ + --name codex-tools-fix --kit-arg lint_mode=fix +``` + +This example uses a workload set that exposes a `lint_mode` argument. +Replace the image reference with your set's published reference. To expose +arguments in your own set, see +[Configure component arguments](/manuals/ai/sandboxes/customize/author/kit-sets.md#configure-component-arguments). + +Argument values are plain text and can be recorded in shell history and +sandbox state. Use +[stored credentials](/manuals/ai/sandboxes/configuration/credentials.md) +for secrets. + +### Target a specific kit + +An argument without a kit prefix applies to every selected kit that declares +it. To target one kit, use `--kit-arg .=`: + +```console +$ sbx run docker.io//codex-tools:1.0.0 \ + --name codex-tools-fix --kit-arg codex-tools.lint_mode=fix +``` + +The handle identifies the kit and comes from its reference: + +| Kit source | Handle | +| --- | --- | +| Published image | Final part of the repository name, such as `codex-tools` | +| Local directory | Directory name | +| Git repository | Selected subdirectory name, or repository name if no subdirectory is selected | + +A value targeted at one kit overrides a value supplied to all kits. + +### Load arguments from a file + +Use `--kit-args-file ` to load arguments from a reusable file. +Write one `name=value` entry per line. You can prefix names with a kit +handle, as with `--kit-arg`. + +Values passed with `--kit-arg` override those in the file. + +### Which settings can you change? + +For a kit set, you can change only the arguments the author has exposed. +Other component arguments are fixed when the set is published. + +Settings chosen during the image build, such as a tool's version, require +rebuilding the image. + +## Restrict kit sources + +[`kit.allowedSources`](../configuration/settings.md#kitallowedsources) controls +permitted remote kit sources. Its default permits +Docker Hub. To include a Git publisher, set the complete list of prefixes you +want to permit: + +```console +$ sbx settings set kit.allowedSources '["docker.io/","github.com/docker/"]' +``` + +Prefixes match at path-segment boundaries. Local source directories are +controlled separately by `kit.allowLocalKits`, which defaults to `true`: + +```console +$ sbx settings set kit.allowLocalKits false +``` + +For defaults and environment variable equivalents, see the +[kit settings reference](../configuration/settings.md#kits). + +## Verify kit signatures + +To verify a published kit against its author's signing identity: + +```console +$ sbx kit verify docker.io//my-kit:1.0.0 \ + --certificate-identity \ + --certificate-oidc-issuer +``` + +For key-based signatures, use `--key cosign.pub` instead of the certificate +identity and issuer options. Obtain the expected identity or public key from +the publisher. + +To require trusted signatures when loading kits, configure the trusted signer +policy, then turn on the requirement: + +```console +$ sbx settings set kit.trustedSigners \ + '[{"identity":"release-bot@example.com","issuer":"https://accounts.google.com"}]' +$ sbx settings set kit.requireSignature true +``` + +V3 source directories and Git sources don't support the source-signing +workflow. Use a signed OCI image when signatures are required. + +## Debug kits + +When a tool is missing or a request fails, inspect the running sandbox: + +```console +$ sbx exec -- which +$ sbx exec -- cat /home/agent/.config//settings.json +$ sbx policy log +``` + +The policy log shows outbound requests and the rules they matched. Use it to +find blocked package registries or API hosts. If downloads fail after adding a kit that requests +credentials, ask its author to check that credential injection targets only +the service hosts that need it. + +To try an updated v3 kit, create a sandbox with a different name. Reusing +an existing sandbox keeps its recorded kit configuration. diff --git a/content/manuals/ai/sandboxes/faq.md b/content/manuals/ai/sandboxes/faq.md index 6c4e8dc02e..a418eda7ff 100644 --- a/content/manuals/ai/sandboxes/faq.md +++ b/content/manuals/ai/sandboxes/faq.md @@ -114,23 +114,13 @@ inside the session. Most agents let you switch permission modes after startup. In Claude Code, use the `/permissions` command to change the mode interactively. -To make approval prompts the default for every session, define a custom -sandbox kit that overrides the agent's entrypoint to drop the -permission-skipping flag. For example, a kit that launches Claude Code -without `--dangerously-skip-permissions`: +To make approval prompts the default for every session, create a v2 sandbox +kit that extends the built-in agent and changes its launch options. See +[Fork an existing agent](customize/kits-v2.md#fork-an-existing-agent) +for a complete example. -```yaml {title="claude-safe/spec.yaml"} -schemaVersion: "1" -kind: sandbox -name: claude-safe -sandbox: - image: "docker/sandbox-templates:claude-code-docker" - entrypoint: - run: [claude] -``` - -Run it with `sbx run ./claude-safe/`. See -[Sandbox kits](customize/kits.md#sandbox-kits) for the full pattern. +For an environment built entirely with v3 kits, set the launch command in +the workload's Dockerfile. See [Build a v3 agent kit](/manuals/ai/sandboxes/customize/author/build-an-agent.md). ## How do I know if my agent is running in a sandbox? diff --git a/content/manuals/ai/sandboxes/governance/concepts.md b/content/manuals/ai/sandboxes/governance/concepts.md index f1efd9182e..227f87ae6c 100644 --- a/content/manuals/ai/sandboxes/governance/concepts.md +++ b/content/manuals/ai/sandboxes/governance/concepts.md @@ -242,8 +242,7 @@ from those sources do still apply. See [Precedence](#precedence). What applies depends on whether your organization has governance enabled: -- No organization governance: local rules and any - [kit-defined network rules](../customize/kits.md#control-network-access) +- No organization governance: local rules and any kit-defined network rules determine what sandboxes can access. - Organization governance active: organization policy determines what access can be granted. Only organization allow rules grant access, so local and @@ -251,6 +250,10 @@ What applies depends on whether your organization has governance enabled: permits. Deny rules apply from every source, so a local or kit-defined deny can still restrict access further. +For kit-defined rules, see +[Network policies](https://github.com/docker/sandbox-kit-spec/blob/main/docs/spec/capabilities/com.docker.sandbox/network-policy@1.md) +in the kit specification. + Precedence is decided by a rule's decision rather than its source: | Rule | Evaluated under organization governance | diff --git a/content/manuals/ai/sandboxes/governance/monitor-and-enforce/monitoring.md b/content/manuals/ai/sandboxes/governance/monitor-and-enforce/monitoring.md index 297c0cf384..5444b32ce6 100644 --- a/content/manuals/ai/sandboxes/governance/monitor-and-enforce/monitoring.md +++ b/content/manuals/ai/sandboxes/governance/monitor-and-enforce/monitoring.md @@ -29,7 +29,7 @@ The columns are: - `POLICY`: the policy name. - `SOURCE`: where the policy came from. `local` means your local configuration — a preset or rules you added with `sbx policy`. `kit` means a - [kit](../../customize/kits.md#control-network-access). `org` means your + [kit](/manuals/ai/sandboxes/governance/concepts.md#precedence). `org` means your organization. - `APPLIES TO`: which sandboxes the policy applies to. `all` means the policy is global. `sandbox:` scopes it to a single sandbox; a profile name diff --git a/content/manuals/ai/sandboxes/integrations/t3-code.md b/content/manuals/ai/sandboxes/integrations/t3-code.md index fe7ddffb57..efcb35b339 100644 --- a/content/manuals/ai/sandboxes/integrations/t3-code.md +++ b/content/manuals/ai/sandboxes/integrations/t3-code.md @@ -49,8 +49,8 @@ $ sbx exec -- sh -lc 'command -v g++ && command -v make && command -v A manual install lasts only until the sandbox is recreated, and the first connection still builds `node-pty` from source. For a setup that persists, -recreate the sandbox with the [kit](../customize/kits.md) or a custom -[template](../customize/templates.md). +recreate the sandbox with the [v2 kit](../customize/kits-v2.md) or a custom +[template](/manuals/ai/sandboxes/customize/author/base-images.md). ## Connect diff --git a/content/manuals/ai/sandboxes/security/_index.md b/content/manuals/ai/sandboxes/security/_index.md index 3d4db10f41..6ef8444d28 100644 --- a/content/manuals/ai/sandboxes/security/_index.md +++ b/content/manuals/ai/sandboxes/security/_index.md @@ -119,7 +119,7 @@ see the full list of active rules, and remove entries you don't need. See Kits run install commands with root privileges inside the sandbox. To limit supply-chain risk, `sbx` restricts kit installs to an allowlist of sources that defaults to Docker Hub only. See -[Restrict kit sources](../customize/kits.md#restrict-kit-sources). +[Restrict kit sources](/manuals/ai/sandboxes/customize/use-kits.md#restrict-kit-sources). Shared agent skills create a narrow exception to cross-sandbox isolation. The store can be mounted with `readwrite` access, so one sandbox can modify diff --git a/content/manuals/ai/sandboxes/troubleshooting.md b/content/manuals/ai/sandboxes/troubleshooting.md index 1ffae351f5..05ba9b29ae 100644 --- a/content/manuals/ai/sandboxes/troubleshooting.md +++ b/content/manuals/ai/sandboxes/troubleshooting.md @@ -136,7 +136,7 @@ $ sbx settings set kit.allowedSources '["docker.io/","github.com/docker/"]' ``` Then run the command again. For details, including how to allow local kits or -any remote source, see [Restrict kit sources](customize/kits.md#restrict-kit-sources). +any remote source, see [Restrict kit sources](/manuals/ai/sandboxes/customize/use-kits.md#restrict-kit-sources). ## SSH and other non-HTTP connections fail @@ -220,9 +220,10 @@ your organization's internal root CA inside the sandbox so the agent and its SDKs trust certificates signed by the proxy. Certificate errors can stop a request before the credential proxy can inject credentials. -For repeatable setup, create a [sandbox kit](customize/kits.md) that installs -the CA when the sandbox is created. See -[Install an internal CA certificate](customize/kit-examples.md#install-an-internal-ca-certificate) +For repeatable setup with a built-in agent, create a +[v2 mixin kit](customize/kits-v2.md) that installs the CA when the +sandbox is created. See +[Install an internal CA certificate](customize/kits-v2.md#install-an-internal-ca-certificate) for an example kit. Use a PEM-encoded certificate with a `.crt` extension. If traffic can be signed diff --git a/content/manuals/ai/sandboxes/usage.md b/content/manuals/ai/sandboxes/usage.md index 7a3bf9654c..c818c39a73 100644 --- a/content/manuals/ai/sandboxes/usage.md +++ b/content/manuals/ai/sandboxes/usage.md @@ -2,7 +2,7 @@ title: Usage weight: 30 description: Basic sbx commands for creating, managing, and connecting to Docker Sandboxes. -keywords: docker sandboxes, sbx, usage, run, create, stop, remove, ports, workspaces +keywords: docker sandboxes, sbx, usage, run, create, stop, remove, ports, workspaces, templates, save, load --- Use this page as a command-oriented guide to day-to-day `sbx` operations. For @@ -397,5 +397,154 @@ changes, command history, and mountless workspace files all persist across stops and restarts. When you remove a sandbox, everything inside is deleted. Host workspace files, including repositories used as clone sources, and the [shared agent skills store](workflows/agent-skills.md) remain on your host. To -preserve a configured environment, create a [custom -template](customize/templates.md) or use a [kit](customize/kits.md). +capture changes in the container filesystem, [save a template](#saving-a-sandbox-as-a-template). +For a reproducible environment defined in source, +[author a kit](/manuals/ai/sandboxes/customize/author/_index.md). + +## Saving a sandbox as a template + +Save a sandbox's container filesystem as a reusable template image after +setting up tools or configuration interactively. A template contains image +content; the agent kit still supplies runtime settings such as credentials +and network rules. The examples here reuse templates with built-in agents. + +A saved template isn't a backup of the whole sandbox. Mounted filesystems, +including host workspaces and the Docker store at `/var/lib/docker`, aren't +included. Save any data from those mounts separately. + +> [!WARNING] +> Saving a sandbox captures files in its container filesystem, including any +> secrets stored there. If you manually added API keys, tokens, or other +> credentials to the sandbox, they're embedded in the saved template and +> shared with anyone you distribute it to. To keep credentials out of +> templates, manage them with `sbx secret set` instead — the proxy injects +> them at runtime so they're never written to the filesystem. For more +> information, see [Manage credentials](configuration/credentials.md). + +### Save and reuse + +Stop the sandbox (or let the CLI prompt you), then save it with a name and +tag: + +```console +$ sbx template save my-sandbox my-template:v1 +``` + +The image is stored in the sandbox runtime's local image store. Create a +new sandbox from it with the `-t` flag: + +```console +$ sbx run -t my-template:v1 claude +``` + +### List and remove templates + +List all saved templates: + +```console +$ sbx template ls +``` + +Remove a template you no longer need: + +```console +$ sbx template rm my-template:v1 +``` + +### Export and import + +To share a saved template or move it to another machine, export it as a +tar file: + +```console +$ sbx template save my-sandbox my-template:v1 --output my-template.tar +``` + +On the other machine, load the tar file and use it: + +```console +$ sbx template load my-template.tar +$ sbx run -t my-template:v1 claude +``` + +### Limitations + +Agent configuration files are always recreated when a sandbox is created. +Changes to user-level agent configuration files, such as +`/home/agent/.claude/settings.json` and `/home/agent/.claude.json`, do not +persist in saved templates. + +If the saved template was built for a different agent than the one you +specify in `sbx run`, you get a warning. For example, saving a Claude +sandbox and running it with `codex` produces: + +```text +⚠ WARNING: template "my-template:v1" was built for the "claude" agent but you are using "codex". + The sandbox may not work correctly. Consider using: sbx run -t my-template:v1 claude +``` + +## Load a template + +To create a sandbox from a template image in a registry, pass its full image +reference to `--template`. Use the agent the image was prepared for: + +```console +$ sbx run --template docker.io/my-org/my-template:v1 claude +``` + +Unlike Docker commands, `sbx` doesn't automatically add the Docker Hub domain +(`docker.io`) to image references. For available images and the built-in agent +workflow, see [Base images](/manuals/ai/sandboxes/customize/author/base-images.md). + +> [!NOTE] +> The Docker daemon used by Docker Sandboxes pulls templates from a +> registry directly; it doesn't share the image store of your local Docker +> daemon on the host. To route Docker Hub image pulls through your +> organization's registry infrastructure, configure a +> [registry mirror](configuration/registry-mirror.md). + +> [!IMPORTANT] +> For Docker Hub, `sbx` reuses your `sbx login` session to pull private +> images. For other registries (GitHub Container Registry, ECR, ACR, a +> self-hosted Nexus, and so on), store pull credentials with +> [`sbx secret set --registry`](configuration/credentials.md#registry-credentials) +> before running the sandbox: +> +> ```console +> $ gh auth token | sbx secret set --registry ghcr.io --password-stdin +> ``` +> +> Without stored credentials, pulls from non-Docker Hub registries are +> anonymous and private images fail to pull. + +For locally-built images, save the image to a tar and load it directly +into the sandbox runtime instead of pulling from a registry: + +```console +$ docker image save my-org/my-template:v1 -o my-template.tar +$ sbx template load my-template.tar +$ sbx run --template my-org/my-template:v1 claude +``` + +`sbx template load` imports the tar into the sandbox runtime's image +store, so the image doesn't need to be reachable from a registry at +sandbox creation time. + +### Template caching + +When creating a sandbox, `sbx` checks the registry for the template image by +default and downloads missing or updated layers. If the pull fails and the +image is cached locally, it can use the cached image. Cached images persist +across sandbox creation and deletion, and are cleared when you run `sbx reset`. + +### Updating agents + +Agent templates include an agent version, which can differ from the agent's +latest release. Updating the `sbx` CLI or pulling an updated template doesn't +update agents inside existing sandboxes. + +To update an installed agent, run its documented update command inside the +sandbox, either from a sandbox shell or with `sbx exec`. Restart the agent +session to use the updated version. The update persists across sandbox stops +and starts, but is deleted when you remove the sandbox. To reuse the updated +agent in other sandboxes, [save a template](#saving-a-sandbox-as-a-template). diff --git a/content/manuals/ai/sandboxes/workflows/authentication.md b/content/manuals/ai/sandboxes/workflows/authentication.md index 000385563d..cf5abe48c7 100644 --- a/content/manuals/ai/sandboxes/workflows/authentication.md +++ b/content/manuals/ai/sandboxes/workflows/authentication.md @@ -47,7 +47,7 @@ The token is never stored in plaintext inside the sandbox. See When using Docker Hub, authentication is handled automatically; `sbx` reuses your existing login session. For other registries, you need to configure -credentials for `sbx` so it can pull private [templates](../customize/templates.md) +credentials for `sbx` so it can pull private [templates](../usage.md#load-a-template) and kits when creating a sandbox: ```console diff --git a/content/manuals/ai/sandboxes/workflows/git.md b/content/manuals/ai/sandboxes/workflows/git.md index 0d8f555a4c..eb97afe5dc 100644 --- a/content/manuals/ai/sandboxes/workflows/git.md +++ b/content/manuals/ai/sandboxes/workflows/git.md @@ -213,8 +213,8 @@ you turned off forwarding or use a fixed SSH agent socket, see To apply this configuration automatically to every sandbox, use the [`git-ssh-sign`](https://github.com/docker/sbx-kits-contrib/tree/main/git-ssh-sign) -community kit, which handles all of the above setup. See [Kits](../customize/kits.md) -if you want to package it alongside other sandbox customizations. +community kit, which handles all of the above setup. For using it with the +built-in agents, see [Kits v2](../customize/kits-v2.md). For troubleshooting, see [Sandbox commits aren't signed](../troubleshooting.md#sandbox-commits-arent-signed). diff --git a/content/manuals/docker-hub/image-library/catalogs.md b/content/manuals/docker-hub/image-library/catalogs.md index 585bf989df..a717cbd8b2 100644 --- a/content/manuals/docker-hub/image-library/catalogs.md +++ b/content/manuals/docker-hub/image-library/catalogs.md @@ -67,6 +67,9 @@ simplifies the model management experience. coding agent needs to run in a [Docker Sandbox](../../ai/sandboxes/_index.md): its image, tools, credentials, network rules, and startup commands. -Each kit's Hub page shows the command to run it, in the form -`sbx run --kit docker.io//`. To learn more about -building and running kits, see [Kits](../../ai/sandboxes/customize/kits.md). +Follow the publisher's instructions for the kit's schema version and role. +A kit that defines a complete environment is the main reference passed to +`sbx run`. Add mixins with `--kit`. Components in one sandbox must use +compatible kit formats. See [Kits](/manuals/ai/sandboxes/customize/_index.md) for +the v3 model and [Kits v2](/manuals/ai/sandboxes/customize/kits-v2.md) for +kits used with built-in agents. diff --git a/content/manuals/docker-hub/image-library/search.md b/content/manuals/docker-hub/image-library/search.md index b11f9492b4..b90414bfea 100644 --- a/content/manuals/docker-hub/image-library/search.md +++ b/content/manuals/docker-hub/image-library/search.md @@ -77,14 +77,17 @@ Extensions](/manuals/extensions/_index.md). Docker Hub hosts kits for [Docker Sandboxes](/manuals/ai/sandboxes/_index.md), which run AI coding agents in isolated microVM sandboxes. A kit packages what an agent needs to run in a sandbox, such as its image, tools, credentials, -network rules, and startup commands. Sandbox kits come in two kinds: +network rules, and startup commands. In the v2 format, kits have two kinds: - Sandbox: Defines a full agent from scratch, including its image and entrypoint. - Mixin: Layers tools, credentials, or configuration onto an existing agent. -To learn more about building and running kits, see -[Kits](/manuals/ai/sandboxes/customize/kits.md). +For these kits, see the [v2 reference](/manuals/ai/sandboxes/customize/kits-v2.md). +The experimental v3 format uses workloads and mixins, and adds sets for +publishing a composition as one kit. See the +[Kits overview](/manuals/ai/sandboxes/customize/_index.md) for the v3 model and +version compatibility. #### Helm charts diff --git a/data/whats-new.json b/data/whats-new.json index bae984ffc2..4975a0e057 100644 --- a/data/whats-new.json +++ b/data/whats-new.json @@ -51,7 +51,7 @@ "product": "Docker Sandboxes", "title": "Sign and enforce trusted sandbox kits", "description": "Sign kits with cosign-compatible Sigstore signatures, verify keyless or key-based signatures, and reject kits outside a trusted-signer policy.", - "url": "/ai/sandboxes/customize/kits/#sign-and-verify-kits", + "url": "/ai/sandboxes/customize/kits-v2/#sign-and-verify-kits", "published": "2026-08-20", "source_prs": [25791, 25896], "featured": false