mirror of
https://github.com/docker/docs.git
synced 2026-10-23 18:09:02 +03:00
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/
This commit is contained in:
@@ -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 <key>` 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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -69,5 +69,5 @@ $ sbx run --name <sandbox-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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 <host>` 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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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}
|
||||
|
||||
|
||||
@@ -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).
|
||||
|
||||
188
content/manuals/ai/sandboxes/customize/author/_index.md
Normal file
188
content/manuals/ai/sandboxes/customize/author/_index.md
Normal file
@@ -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.
|
||||
190
content/manuals/ai/sandboxes/customize/author/base-images.md
Normal file
190
content/manuals/ai/sandboxes/customize/author/base-images.md
Normal file
@@ -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:<variant>`. 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).
|
||||
419
content/manuals/ai/sandboxes/customize/author/build-an-agent.md
Normal file
419
content/manuals/ai/sandboxes/customize/author/build-an-agent.md
Normal file
@@ -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 `<NAMESPACE>` 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/<NAMESPACE>/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=<CLAUDE_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/<NAMESPACE>/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.
|
||||
117
content/manuals/ai/sandboxes/customize/author/distribute.md
Normal file
117
content/manuals/ai/sandboxes/customize/author/distribute.md
Normal file
@@ -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/<NAMESPACE>/my-kit:1.0.0 --push
|
||||
```
|
||||
|
||||
Replace `<NAMESPACE>` 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/<NAMESPACE>/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/<ORG>/<REPOSITORY>.git#ref=<COMMIT>&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/<NAMESPACE>/my-kit:1.0.0
|
||||
$ sbx kit verify docker.io/<NAMESPACE>/my-kit:1.0.0 \
|
||||
--certificate-identity <SIGNER_IDENTITY> \
|
||||
--certificate-oidc-issuer <ISSUER_URL>
|
||||
```
|
||||
|
||||
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/<stem>/`.
|
||||
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.
|
||||
244
content/manuals/ai/sandboxes/customize/author/kit-sets.md
Normal file
244
content/manuals/ai/sandboxes/customize/author/kit-sets.md
Normal file
@@ -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: <MIXIN_REFERENCE>
|
||||
```
|
||||
|
||||
Replace `<MIXIN_REFERENCE>` 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/<NAMESPACE>/codex-tools:1.0.0 --push
|
||||
```
|
||||
|
||||
Replace the paths with your set's source directory and descriptor, and
|
||||
`<NAMESPACE>` 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 <SET_REFERENCE> --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 <WORKLOAD_REFERENCE> --kit <SET_REFERENCE> --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).
|
||||
147
content/manuals/ai/sandboxes/customize/author/patterns.md
Normal file
147
content/manuals/ai/sandboxes/customize/author/patterns.md
Normal file
@@ -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).
|
||||
210
content/manuals/ai/sandboxes/customize/author/tool-mixins.md
Normal file
210
content/manuals/ai/sandboxes/customize/author/tool-mixins.md
Normal file
@@ -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/<NAMESPACE>/claude-mixin:1.0.0 --push
|
||||
```
|
||||
|
||||
Replace `<NAMESPACE>` 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).
|
||||
@@ -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 <key>` header. The `<key>` 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 <name>`) 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`.
|
||||
@@ -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/<name>/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=<kit>"
|
||||
```
|
||||
|
||||
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=<kit>"
|
||||
```
|
||||
@@ -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 `<NAMESPACE>/<KIT>:<TAG>`. 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/<ORG>/<REPOSITORY>.git#ref=<COMMIT>&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.<id>` | `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: <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:<variant>`.
|
||||
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 `<NAMESPACE>` with a
|
||||
Docker Hub namespace you can push to:
|
||||
|
||||
```console
|
||||
$ docker build -t docker.io/<NAMESPACE>/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/<NAMESPACE>/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: <mixin | sandbox>
|
||||
name: <name>
|
||||
version: <version>
|
||||
displayName: <name>
|
||||
description: <text>
|
||||
sourceURL: <url>
|
||||
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 <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: <service-id>
|
||||
description: <text> # optional
|
||||
required: <true | false> # optional, default false
|
||||
provider: <provider> # optional, reserved
|
||||
apiKey:
|
||||
name: <ENV_VAR>
|
||||
proxyManaged: true
|
||||
inject:
|
||||
- domain: <domain>
|
||||
header: <header>
|
||||
format: <format>
|
||||
- domain: <domain>
|
||||
scheme: bearer
|
||||
- domain: <domain>
|
||||
scheme: basic
|
||||
username: <user> # required with scheme: basic
|
||||
oauth:
|
||||
tokenEndpoint:
|
||||
host: <host>
|
||||
path: <path>
|
||||
sentinels:
|
||||
accessToken: <sentinel>
|
||||
refreshToken: <sentinel>
|
||||
credentialFile:
|
||||
path: <path>
|
||||
structure:
|
||||
<key>:
|
||||
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: [<domain>, ...]
|
||||
deny: [<domain>, ...]
|
||||
```
|
||||
|
||||
| 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:
|
||||
<NAME>: <value>
|
||||
```
|
||||
|
||||
| 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: <shell-string>
|
||||
user: <uid>
|
||||
description: <text>
|
||||
startup:
|
||||
- command: [<argv>, ...]
|
||||
user: <uid>
|
||||
background: <true | false>
|
||||
description: <text>
|
||||
files:
|
||||
- path: <path>
|
||||
content: <text>
|
||||
mode: <octal>
|
||||
onlyIfMissing: <true | false>
|
||||
description: <text>
|
||||
```
|
||||
`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/<NAME>/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 <path>` — check that a kit directory or ZIP is
|
||||
well-formed.
|
||||
- `sbx kit inspect <path>` — display kit details. Add `--json` for
|
||||
machine-readable output.
|
||||
- `sbx kit pack <path> -o <file.zip>` — package a directory as a ZIP file
|
||||
for sharing.
|
||||
- `sbx kit push <path> <ref>` — publish to an OCI registry (for example,
|
||||
`ghcr.io/myorg/my-kit:1.0`).
|
||||
- `sbx kit pull <ref>` — 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.<id>` | `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: <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.
|
||||
@@ -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 `<kit-name>.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 <sandbox-kit-ref> [PATH...]
|
||||
$ sbx create <sandbox-kit-ref> [PATH...]
|
||||
```
|
||||
|
||||
The previous form, `sbx run <sandbox-kit-name> --kit <sandbox-kit-ref>`, 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.<name> }}`. 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=<branch|tag|commit>` pins to a specific revision. Defaults to the
|
||||
repository's default branch.
|
||||
- `#dir=<path>` 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 <path>` — check that a kit directory or ZIP is
|
||||
well-formed.
|
||||
- `sbx kit inspect <path>` — display kit details. Add `--json` for
|
||||
machine-readable output.
|
||||
- `sbx kit pack <path> -o <file.zip>` — package a directory as a ZIP file
|
||||
for sharing.
|
||||
- `sbx kit push <path> <ref>` — publish to an OCI registry (for example,
|
||||
`ghcr.io/myorg/my-kit:1.0`).
|
||||
- `sbx kit pull <ref>` — 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 <sandbox> -- <cmd>` 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 <sandbox> && sbx run ...`.
|
||||
@@ -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:<variant>`. 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
|
||||
```
|
||||
302
content/manuals/ai/sandboxes/customize/use-kits.md
Normal file
302
content/manuals/ai/sandboxes/customize/use-kits.md
Normal file
@@ -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/<ORG>/<REPOSITORY>.git#ref=<COMMIT>&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/<ORG>/<REPOSITORY>.git#ref=<COMMIT>&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/<NAMESPACE>/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/<NAMESPACE>/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 <HANDLE>.<ARGUMENT>=<VALUE>`:
|
||||
|
||||
```console
|
||||
$ sbx run docker.io/<NAMESPACE>/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 <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/<NAMESPACE>/my-kit:1.0.0 \
|
||||
--certificate-identity <SIGNER_IDENTITY> \
|
||||
--certificate-oidc-issuer <ISSUER_URL>
|
||||
```
|
||||
|
||||
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 <SANDBOX> -- which <TOOL>
|
||||
$ sbx exec <SANDBOX> -- cat /home/agent/.config/<TOOL>/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.
|
||||
@@ -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?
|
||||
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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:<name>` scopes it to a single sandbox; a profile name
|
||||
|
||||
@@ -49,8 +49,8 @@ $ sbx exec <sandbox> -- 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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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 <agent> --kit docker.io/<namespace>/<kit-name>`. 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.
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user