Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions content/manuals/ai/sandboxes/customize/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,27 @@ 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.

## Templates and kits, side by side

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 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 agent 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.

Templates and kits work together. An agent kit's `agent.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.

## When to use which

| Goal | Option |
Expand Down
11 changes: 11 additions & 0 deletions content/manuals/ai/sandboxes/customize/build-an-agent.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ behind a part of the spec, so you can apply the same reasoning to other agents.
For reference on every field, see the [Kits](kits.md) page. 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
Expand Down Expand Up @@ -261,6 +265,13 @@ agent argument:
$ sbx run --kit ./amp/ amp
```

The published copy of this kit also runs directly from the contrib
repository:

```console
$ sbx run --kit "git+https://github.com/docker/sbx-kits-contrib.git#dir=amp" amp
```

## Iterate

As you use the kit, you'll likely hit missing domains or install quirks.
Expand Down
17 changes: 17 additions & 0 deletions content/manuals/ai/sandboxes/customize/kit-examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,12 @@ command can invoke it directly.
Use `initFiles` 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
Expand Down Expand Up @@ -223,3 +229,14 @@ $ sbx run claude-safe --kit ./claude-safe

For a step-by-step walkthrough of building a new agent 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, or load one directly:

```console
$ sbx run claude --kit "git+https://github.com/docker/sbx-kits-contrib.git#dir=<kit>"
```
76 changes: 55 additions & 21 deletions content/manuals/ai/sandboxes/customize/kits.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,50 +98,74 @@
### Set environment variables

Environment variables set by the kit are available to the agent at
runtime. Sensitive values can be marked proxy-managed, so the real
credential is substituted only when the proxy forwards a request. The
secret itself never enters the VM:
runtime:

```yaml
environment:
variables:
MY_TOOL_WORKSPACE: /home/agent/my-tool
proxyManaged:
- MY_TOOL_API_KEY
```

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.

### Control network access

Network rules define which domains the sandbox can reach. For
authenticated services, a domain can be mapped to a service identifier,
and the proxy injects the auth header on forwarded requests:
Network rules define which domains the sandbox can reach:

```yaml
network:
allowedDomains:
- api.example.com
serviceDomains:
api.example.com: my-service
serviceAuth:
my-service:
headerName: Authorization
valueFormat: "Bearer %s"
- "*.cdn.example.com"
```

### Declare credential sources
For authenticated services, see
[Authenticate to external services](#authenticate-to-external-services).

Credential sources tell the proxy where to find secrets on the host. The
sandbox never sees the value itself. The proxy reads it and injects it
into outbound requests:
### 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.

The standard pattern uses four blocks tied to a service identifier
you choose (here, `my-service`):

```yaml
network:
allowedDomains:
- api.example.com
serviceDomains:
api.example.com: my-service # Tag traffic to this domain
serviceAuth:
my-service:
headerName: Authorization # Overwrite this header
valueFormat: "Bearer %s"

credentials:
sources:
my-service:
env:
- MY_SERVICE_API_KEY
- MY_SERVICE_API_KEY # Host-side credential lookup

environment:
proxyManaged:
- MY_SERVICE_API_KEY # Set the in-VM env var to "proxy-managed"
```

The agent boots with `MY_SERVICE_API_KEY=proxy-managed`, sends a
request with that value in `Authorization`, and the proxy overwrites
the header with the real credential before forwarding. The real
secret never enters the VM.

See [Credentials](../security/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.

Check warning on line 167 in content/manuals/ai/sandboxes/customize/kits.md

View workflow job for this annotation

GitHub Actions / validate (vale)

[vale] reported by reviewdog 🐶 [Docker.RecommendedWords] Consider using 'previous' instead of 'above' Raw Output: {"message": "[Docker.RecommendedWords] Consider using 'previous' instead of 'above'", "location": {"path": "content/manuals/ai/sandboxes/customize/kits.md", "range": {"start": {"line": 167, "column": 1}}}, "severity": "INFO"}

### Define an agent

Agent kits declare an `agent:` block with the image the agent runs in and
Expand Down Expand Up @@ -209,12 +233,16 @@
> The templates for the built-in agents (`claude`, `codex`, etc) already
> includes `uv`, so this mixin can use it without installing it separately.

To run an agent with this mixin:
To start a new sandbox with this mixin:

```console
$ sbx run claude --kit /path/to/ruff-lint/
```

To apply the mixin to a sandbox that's already running, use
[`sbx kit add`](#local) instead. The `--kit` flag only takes effect when a
sandbox is created.

## Agent kits

An agent kit defines a full agent from scratch — image, entrypoint, and
Expand Down Expand Up @@ -309,7 +337,7 @@
### Git repository

```console
$ sbx run claude --kit "git+https://github.com/<owner>/<repo>.git#ref=v0.1.0&dir=code-server"
$ 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
Expand All @@ -328,6 +356,12 @@
For Docker Hub, include the full `docker.io` prefix. See
[Packaging and distribution](#packaging-and-distribution) for publishing.

> [!IMPORTANT]
> Private kits are only supported on Docker Hub. `sbx` reuses your
> `sbx login` session to pull private artifacts from Docker Hub. Other
> registries are pulled anonymously, so private kits hosted on
> registries other than Docker Hub fail to pull.

## Packaging and distribution

The `sbx kit` subcommands validate, inspect, and publish kits:
Expand Down
21 changes: 21 additions & 0 deletions content/manuals/ai/sandboxes/customize/templates.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,27 @@ $ docker build -t my-org/my-template:v1 --push .
> registry directly; it doesn't share the image store of your local Docker
> daemon on the host.

> [!IMPORTANT]
> Private templates are only supported on Docker Hub. `sbx` reuses your
> `sbx login` session to pull private images from Docker Hub. Other
> registries (such as GitHub Container Registry, ECR, or a self-hosted
> registry like Nexus) are pulled anonymously, so private images on those
> registries fail to pull.

For locally-built images or private images on registries that `sbx`
can't authenticate against, 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:

Expand Down
20 changes: 19 additions & 1 deletion content/manuals/ai/sandboxes/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ $ export SBX_NO_TELEMETRY=1
## How do I set custom environment variables inside a sandbox?

The [`sbx secret`](/reference/cli/sbx/secret/) command only supports a fixed set
of [services](security/credentials.md#supported-services) (Anthropic, OpenAI,
of [services](security/credentials.md#built-in-services) (Anthropic, OpenAI,
GitHub, and others). If your agent needs an environment variable that isn't
tied to a supported service, such as `BRAVE_API_KEY` or a custom internal
token, write it to `/etc/sandbox-persistent.sh` inside the sandbox. This
Expand Down Expand Up @@ -98,6 +98,24 @@ 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
agent 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`:

```yaml {title="claude-safe/spec.yaml"}
schemaVersion: "1"
kind: agent
name: claude-safe
agent:
image: "docker/sandbox-templates:claude-code-docker"
entrypoint:
run: [claude]
```

Run it with `sbx run claude-safe --kit ./claude-safe/`. See
[Agent kits](customize/kits.md#agent-kits) for the full pattern.

## How do I know if my agent is running in a sandbox?

Ask the agent. The agent can see whether or not it's running inside a sandbox.
Expand Down
Loading