Picture this. You’ve just given an AI coding assistant a task, and a minute later it’s running commands, installing packages and rewriting files. You watch the terminal scroll and wonder whether you should have let it do this on your real laptop.
That worry is the reason Docker Sandboxes exist, and kits are what make them practical to live with. Here’s what kits are, what’s inside one, and how the whole thing works.

Start with the sandbox
A Docker Sandbox is a walled-off workspace where an AI agent can do its work without touching the rest of your machine. Docker launched the feature in March 2026, and you drive it with a command-line tool called sbx. It’s a standalone program, so you don’t need Docker Desktop to use it.
The usual comparison is an apartment with a locked door. The agent can rearrange the furniture all it likes, and when it’s done you can demolish the apartment and start fresh.
The catch is that a fresh apartment is empty, with no furniture, no tools and no Wi-Fi password. Docker’s own engineers say as much. One of them wrote that an empty sandbox is a good boundary, but that kits are what make sandboxes survivable as a development tool. Without them you’d redo the same setup every time.
So what is a kit?
A kit is a small, shareable bundle that describes what a sandbox needs. It can also include credentials and instructions for the agent. Docker’s docs list what a kit can carry:
Tools to install
Environment variables to set
Credentials to inject
Network rules that allow or block websites
Files to drop in
Startup commands to run
Instructions for the agent
All of it goes in one text file called spec.yaml, plus an optional files/ folder for anything you want copied in. You point the sbx command at it, and the sandbox applies it and enforces it at runtime. One writer put it nicely: kits are to agent environments what Dockerfiles are to app environments. If you know Dockerfiles, you already have the right instinct.
The community repo you shared, docker/sbx-kits-contrib, is a shared shelf of these kits. Each top-level folder is one kit.
Two kinds of kit
Mixins add something to an agent that already exists, like plugging a lamp into the wall. You can stack several on one sandbox.
Sandbox kits (in the repo’s older terminology, “agent” kits) define a whole agent from scratch, including its image and the command that launches it. You’d use one to package a custom agent so others can run it.
A third idea is worth knowing. A kit can use extends: to make a variant of a built-in agent, such as Claude Code with a different permission mode. The child inherits everything from its parent, and the parent’s setup steps run first.
One note on versions. Docker is moving fast here. The v0.45.0 release notes introduce “v3 kits,” which separate the main workload from reusable mixins, while v2 kits keep working. The README itself warns that the format is experimental and may change. Treat anything you build today as something you’ll revisit.
A kit, line by line
Here’s the shape of a simple kit in the current v2 style, based on Docker’s docs:
setup:
install:
- command: "apt-get update && apt-get install -y jq"
startup:
- command: ["my-daemon"]
background: true
environment:
variables:
MY_TOOL_WORKSPACE: /home/agent/my-tool
permissions:
network:
allow:
- api.example.com
deny:
- telemetry.example.com
agentInstructions:
content: |
jq is installed. Use it to inspect JSON before editing it.Reading it top to bottom:
Install commands run once, when the sandbox is created. This is where you put anything the agent needs on the machine.
Startup commands run every time the sandbox starts. They’re meant for background services, and they must be safe to run repeatedly.
Environment variables are simple settings the agent can see.
Network rules say which websites are reachable. If a domain matches both an allow and a deny rule, deny wins.
Agent instructions get appended to the agent’s memory file (
CLAUDE.mdorAGENTS.md, depending on the agent). It’s a way to tell the agent, “hey, this tool is here, here’s how to use it.”
Files in the files/home folder get copied into /home/agent/ inside the sandbox. This suits shared linter rules, editor settings and helper scripts.
The clever part: secrets stay out of the sandbox
Handing an API key to something running inside a sandbox is a bit nerve-wracking, and Docker’s design handles it well.
A kit declares which service it needs and how the credential should be attached to requests. The real key lives on your computer. Inside the sandbox, the agent only sees a placeholder. When the agent makes a request, a proxy on your machine swaps the placeholder for the real key before the request leaves. Docker’s tutorial for packaging Claude Code as a mixin shows this: ANTHROPIC_API_KEY inside the sandbox holds a placeholder, and the host proxy inserts the real key into the request header.
The real secret never enters the sandbox. One consequence is that you shouldn’t put secrets in environment.variables, because anything there is visible inside.
A second consequence is that credentials and network access are separate permissions. Declaring a credential doesn’t let the agent connect to that service, so you have to allow the domain too.
Using a kit
You pass kits with the --kit flag, and it accepts several kinds of source: a local folder, a ZIP file, a Git repository, or an OCI registry such as Docker Hub.
# From a local folder
sbx run claude --kit ./my-mixin/
# From a registry
sbx run claude --kit ghcr.io/myorg/my-kit:1.0
# From a Git repo, pinned to a tag
sbx run claude --kit "git+https://github.com/docker/sbx-kits-contrib.git#ref=v0.1.0&dir=code-server"Pinning matters. Without ref, you follow the repo’s default branch and the kit can change under you. A tag or an exact commit keeps things reproducible.
You can stack mixins by repeating the flag, so a Java kit, a cloud-CLI kit and a testing kit can all land in one sandbox. If a kit needs inputs, schema v2 kits can declare arguments and you supply them with --kit-arg name=value. Don’t use arguments for secrets, since values can linger in your shell history.
Two practical details trip people up:
A mixin passed with
--kitonly applies when the sandbox is created. To add a supported mixin to an existing sandbox, usesbx kit add, which restarts the sandbox but keeps installed packages and history. It only supports mixins limited to environment variables, install commands and allowed network domains.Kits can’t be removed from a running sandbox. To start clean, delete the sandbox and recreate it.
The safety rails around kits
Kit install commands run with root privileges inside the sandbox, so Docker is careful about where kits come from. By default, only kits hosted on Docker Hub (docker.io/) are allowed.
This matters for the repo in your link. Docker’s own docs show that loading a kit straight from a GitHub URL fails by default with an error saying the source isn’t in your allowlist. To allow it, you add the publisher to a setting:
sbx settings set kit.allowedSources '["docker.io/","github.com/docker/"]'Entries match on path-segment boundaries, so github.com/docker/ allows github.com/docker/sbx-kits-contrib but not github.com/docker-evil/kit. Setting the list to ["*"] allows anything, which Docker doesn’t recommend. Docker also says kits from the community repo are published automatically as OCI artifacts, so the registry route is often the easiest.
There’s also signing. Kits can be signed with cosign-compatible signatures, and you can require them with kit.requireSignature, so unsigned kits get rejected. The signature covers spec.yaml and the files/ folder, but not things a kit downloads at install time, so pin those by digest or checksum if they must stay fixed.
What’s on the community shelf
The sbx-kits-contrib repo has dozens of kits. From the folder names, you’ll find:
Editors and dev tools:
code-server,neovim,mise,playwrightSecurity and quality:
trivy,vale,packages-through-sfwGit helpers:
github-ssh,git-ssh-signAgents:
amp,crush,junie,openclaw,hermes-agent, and others
Docker has also been moving agents out of the core product and into kits. Its release notes say the built-in droid, copilot and kiro agents were removed and can now be run as community kits, for example sbx run docker.io/sbx/droid-kit:latest.
I’m going by folder names here, so open a kit’s own files before trusting it.
Testing: how a kit proves it works
The repo has a built-in quality check called the TCK (Technology Compatibility Kit). It’s an automated test suite that checks a kit’s spec, network policy, credential setup, commands, environment variables, injected files and security mounts.
There’s a stricter optional layer, the end-to-end test, which boots a real sandbox from your kit and checks that everything landed inside. It catches problems the quick tests can’t, like install commands that fail under the non-root agent user.
Contributors run a few commands before opening a pull request:
sbx kit validate ./my-kit/
cd my-kit && ../scripts/test-kit.sh
../scripts/test-kit-e2e.sh
sbx run --kit . <agent>The e2e step is the one to take seriously. CI skips it for pull requests from forks, because GitHub doesn’t expose secrets to those workflows. Your laptop is the only place those checks run before merge, and the green CI check doesn’t cover them.
The gotcha every newcomer hits
The e2e tests run under a “deny everything by default” network policy. If your kit reaches for a site you didn’t list, it’s blocked and your install fails.
The sneaky part is that package managers are nosy. When apt-get update runs, it refreshes every software source on the machine, not just the one you care about. If one gets blocked, the whole command fails. That’s why a kit on a Docker-based template may need download.docker.com allowed even if it only installs from Ubuntu’s archive. To work on both Intel and Apple Silicon machines, list archive.ubuntu.com, security.ubuntu.com and ports.ubuntu.com.
The fix is a loop: run the test, read the log of blocked requests with sbx policy log, add the missing host, repeat until nothing is blocked. It’s tedious, but it’s the safety system working.
Contributing a kit
If you want to share your own, the contribution rules are strict about commits. Every commit needs two unrelated things: a DCO sign-off (git commit -s, which adds a Signed-off-by: line) and a cryptographic signature (GPG or SSH) that produces GitHub’s green “Verified” badge. A signed commit without the sign-off fails the DCO check, and a signed-off commit without a signature won’t show as Verified.
For pull requests, new kits use a title like “Add my-kit kit”. Fixes use conventional commits such as fix(amp): bump install timeout. A good description covers what changed, any spec choices a reviewer should double-check, your test plan, and where the kit came from. Each kit should also ship a README showing the sbx run command, leading with the published docker.io/sbx/<kit>-kit:latest form.
Wrapping up
The idea behind kits is simple, and it solves a real problem. A sandbox gives you safety, but an empty one is a chore. A kit lets you describe what a workspace needs once, in a text file, and then share it, version it, sign it and reuse it, so you don’t rebuild your setup by hand every morning.
If you want to try it, install sbx, run one of the registry-published community kits against a throwaway project, and then open its spec.yaml. It’s usually short enough to read in a couple of minutes.

Join the conversation! Your thoughts help the community grow.