Kits
NoteKits 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 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:
commands:
install:
- command: "apt-get update && apt-get install -y jq"Startup commands cover things like launching background services,
warming caches, or refreshing config on each start. They must be
idempotent — see the startup spec reference:
commands:
startup:
- command: ["my-daemon"]
background: trueInject files
Kits can inject files into the sandbox in two ways: static files bundled
with the kit, and initFiles 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.
my-kit/
├── spec.yaml
└── files/
├── home/
│ └── .config/my-tool/settings.json
└── workspace/
└── .editorconfiginitFiles 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:
commands:
initFiles:
- path: /home/agent/.my-tool/config.json
content: '{"workspace": "${WORKDIR}"}'
onlyIfMissing: trueSee initFiles in the spec reference for all fields.
Sandboxes seed settings files for some built-in agents during setup.
For example, the sandbox writes /home/agent/.claude/settings.json
for the claude agent. This happens after the kit's static files and
initFiles, so kit-injected files at those paths get overwritten.
Workspace files (such as <workspace>/.claude/settings.local.json)
aren't affected, and you can ship them under files/workspace/ as
usual. To override a path the sandbox writes to, use a
commands.startup script instead. See
Override agent settings for
an example.
Set environment variables
Environment variables set by the kit are available to the agent at runtime:
environment:
variables:
MY_TOOL_WORKSPACE: /home/agent/my-toolFor credentials, see
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 or block. Kit network rules apply only to sandboxes that use the kit:
network:
allowedDomains:
- api.example.com
- "*.cdn.example.com"
deniedDomains:
- telemetry.example.comUse allowedDomains for hosts the agent needs, such as package
registries, install endpoints, or external APIs. Use deniedDomains 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.
ImportantKit network rules don't apply when organization governance is active. In that case, only organization rules are evaluated, so kit-defined allow and deny rules are ignored — including any domains a kit allows for the agent to reach. For details, see Policy precedence.
For authenticated services, see 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.
The standard pattern uses four blocks tied to a service identifier
you choose (here, my-service):
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 # 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 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.
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.
agentContext: |
Ruff is installed. Run `ruff check` before committing.
Shared config lives at `/workspace/ruff.toml`.Both mixin and sandbox kits can declare agentContext:. The content is written
only when the active sandbox kit sets sandbox.aiFilename,
which determines the memory file's name.
When more than one loaded kit declares an agentContext: block, each kit's
content is written to its own <kit-name>.md file under a sibling
kits-agent-context/ directory. The main memory file gets a ## Kits
section that points to each kit file:
/Users/you/
├── myproject/ # workspace
├── AGENTS.md # main memory file with a "## Kits" index
└── kits-agent-context/
├── ruff-lint.md
├── vale.md
└── git-ssh-sign.mdSee agentContext 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:
sandbox:
image: "my-registry/my-agent:latest"
entrypoint:
run: [my-agent, "--yolo"]See 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)
Example: Python linting kit
This kit installs Ruff and injects a shared configuration file, so every sandbox starts with the same linting setup.
ruff-lint/
├── spec.yaml
└── files/
└── workspace/
└── ruff.tomlschemaVersion: "1"
kind: mixin
name: ruff-lint
displayName: Ruff Linter
description: Python linting with shared team config
network:
allowedDomains:
- pypi.org
- files.pythonhosted.org
commands:
install:
- command: "uv tool install ruff@latest"
user: "1000"
description: Install Ruffline-length = 100
[lint]
select = ["E", "F", "I"]TipThe templates for the built-in agents (
claude,codex, and so on) already includeuv, so this mixin can use it without installing it separately.
To start a new sandbox with this mixin:
$ sbx run claude --kit /path/to/ruff-lint/
To apply the mixin to a sandbox that's already running, use
sbx kit add instead. The --kit flag only takes effect when a
sandbox is created.
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 that tells the sandbox how to launch the
agent. For a step-by-step walkthrough, see
Build your own agent kit.
Example: the built-in claude agent
The claude agent you get from sbx run claude is defined as a kit. Here
is an abbreviated version of its spec, showing how the sandbox block combines
with network, credentials, environment, and commands:
schemaVersion: "1"
kind: sandbox
name: claude
sandbox:
image: "docker/sandbox-templates:claude-code-docker"
aiFilename: CLAUDE.md
entrypoint:
run: [claude, "--dangerously-skip-permissions"]
network:
serviceDomains:
api.anthropic.com: anthropic
console.anthropic.com: anthropic
serviceAuth:
anthropic:
headerName: x-api-key
valueFormat: "%s"
allowedDomains:
- "claude.com:443"
credentials:
sources:
anthropic:
env:
- ANTHROPIC_API_KEY
environment:
variables:
IS_SANDBOX: "1"
commands:
install:
- command: "curl -fsSL https://claude.ai/install.sh | bash"
user: "1000"
description: Install Claude CodeUsing kits
Kits can be loaded from a local path (a directory or ZIP file), a Git
repository, or an OCI registry. Pass --kit more than once to stack
several kits on the same sandbox.
Important
--kitonly 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 extend a running sandbox with a kit, usesbx kit addinstead.
Local
Point --kit at a directory or ZIP file on disk:
$ sbx run claude --kit ./my-kit/
$ sbx run claude --kit ./my-kit-1.0.zip
While iterating on a kit, apply changes to a running sandbox with
sbx kit add instead of recreating it:
$ sbx kit add my-sandbox ./my-kit/
kit add re-runs install commands and re-copies files. Kits can't be
removed from a running sandbox — remove and recreate it to start clean.
Git repository
$ 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
$ sbx run claude --kit ghcr.io/myorg/my-kit:1.0
For Docker Hub, include the full docker.io prefix. See
Packaging and distribution for publishing.
ImportantFor Docker Hub,
sbxreuses yoursbx loginsession to pull private kits. For other registries, store pull credentials withsbx secret set --registrybefore running the sandbox:$ gh auth token | sbx secret set --registry ghcr.io --password-stdinWithout stored credentials, pulls from non-Docker Hub registries are anonymous and private kits fail to pull.
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--jsonfor 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.
sbx kit pull prefers credentials stored with
sbx secret set --registry,
falling back to the Docker credential store. sbx kit push only uses the
Docker credential store, so pushing to a private registry requires a prior
docker login.
Spec reference
For a field-by-field reference of every spec.yaml block — top-level
fields, credentials, network, environment, commands, static files,
agent context, and the sandbox block — see Kit spec reference.
Debugging
When a kit doesn't behave as expected, start with the network policy log and direct inspection inside the sandbox:
sbx policy logshows every outbound request the sandbox proxy saw, the rule it matched, extra context when available, and itsPROXYvalue, such asforward,forward-bypass,transparent, orbrowser-open. Use it to diagnose install-time download failures, blocked domains, and unexpected TLS interception. If downloads fail or arrive corrupted after you addserviceDomains, check whether the service mapping is too broad. Map only the hosts that need credential injection.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 ....