Build a Docker Sandbox template image by extending docker/sandbox-templates. Use when writing a Dockerfile for sbx, choosing a base variant, building a family of templates with bake, or publishing and loading one with sbx template.
72
87%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
A template is an image, and it decides what is installed. What a sandbox is
permitted to do belongs in a kit — reach for creating-sbx-kits instead when
the answer is a spec field.
Build a template when something must be baked in: a compiler toolchain, a large dependency tree, a config that has to exist before the agent starts.
docker/sandbox-templates:<variant>, all Ubuntu, all running as a non-root
agent user with sudo:
claude-code, claude-code-minimal (no Node, Python, Go or Java), codex,
copilot, cursor-agent, docker-agent, droid, gemini, kiro,
opencode, shell (no agent at all).
Each has a -docker twin bundling a full Docker Engine — privileged inside the
microVM, with a dedicated 50 GB sparse volume at /var/lib/docker, resizable
through DOCKER_SANDBOXES_DOCKER_SIZE. Naming a built-in agent without
--template selects the -docker twin.
Take shell or shell-docker when you supply the agent yourself. Going the
other way also works: start from your own golden image and layer the sandbox
contract on — a non-root agent at UID 1000 with passwordless sudo, owning
/home/agent/, with the proxy environment preserved across sudo.
FROM docker/sandbox-templates:claude-code-docker
ARG GO_VERSION=1.26.4
USER root
RUN apt-get update \
&& apt-get install -y --no-install-recommends build-essential unzip \
&& rm -rf /var/lib/apt/lists/*
USER agent
RUN mkdir -p /home/agent/.local/opt /home/agent/.local/bin
RUN curl -fsSL -o /tmp/go.tgz "https://go.dev/dl/go${GO_VERSION}.linux-amd64.tar.gz" \
&& tar -C /home/agent/.local/opt -xzf /tmp/go.tgz \
&& rm /tmp/go.tgz
ENV PATH=$PATH:/home/agent/.local/opt/go/bin
COPY --chown=agent:agent files/home/agent/ /home/agent/A fuller version is in assets/Dockerfile.
The moves that matter:
USER root for apt-get, USER agent for anything installing into a home
directory. rustup, nvm and pyenv run as root put their payload under
/root/, which the sandbox never reaches.PATH explicitly with ENV. Whether ~/.local/bin is already on
PATH varies between base images, and four authors in the wild disagreed
about it. One line ends the question.ARGs, so a rebuild is reproducible and a bump is one
edit.BASH_ENV alone. The base image uses it to carry the persistent
environment into non-interactive shells, and setting it yourself disables that
mechanism silently.curl | bash masks a blocked download, because bash
exits 0 on empty stdin — a policy block looks like a successful install. Pin
the installer's SHA256 where you can; its embedded per-platform hashes ride
along on that one pin.Build-time egress allows 443 and blocks 80, so fetch over HTTPS.
A template cannot define a new agent — except that
LABEL com.docker.sandboxes.flavor="<name>" registers one. That label appears
on no documentation page and in two unrelated public repos. Load-bearing and
unsupported; use it knowing that.
For several related templates, carry everything common in one base and keep the variants thin. One repository, variant in the tag.
docker-bake.hcl resolves FROM base to the locally built target, so variants
never pull a published base. Copy assets/docker-bake.hcl
and rename the targets.
docker buildx bake --load base # build base locally
VERSION=2026-08-08 docker buildx bake --pushEvery variant gets a moving -latest, plus an immutable -<VERSION> when
VERSION is set. Share pinned tool versions as bake variables passed through
args, so one file holds every version in the family.
A family that varies along more than one axis — agent × language × framework — is a cross product, not a list. Write one Dockerfile per layer and let bake expand the combinations, rather than one Dockerfile per combination.
Three mechanics carry it, and the matrix form is in assets/docker-bake.hcl:
ARG BASE with FROM ${BASE} makes a layer base-agnostic, so one
lang/Dockerfile serves every agent variant.matrix names the axes; name templates the target off them.contexts interpolated with the axis wires each leaf onto its own
parent, so app-codex-astro builds on lang-codex and never on a published
base. A missing contexts entry does not error — it silently resolves
FROM base against the registry instead.docker buildx bake --list=targets # the expansion, before building anything
docker buildx bake app-codex-astro # one leaf, parents includedOnly what is installed belongs on this tree. Per-layer network allows and
credentials stay in kits, which stack at run time and do not multiply: one
typescript mixin serves all four agents. See creating-sbx-kits.
docker build -t you/my-template:v1 --push .
sbx run -t docker.io/you/my-template:v1 claudesbx does not resolve docker.io the way plain Docker does, so write the
registry prefix in full for sbx run -t. Inside a Dockerfile's FROM, ordinary
Docker resolution applies and the bare form is fine.
Docker Hub pulls reuse sbx login. Any other registry needs credentials first,
or the pull goes anonymous and a private image fails:
gh auth token | sbx secret set --registry ghcr.io --password-stdinPrivate templates work on Docker Hub only. Elsewhere, move the bytes:
docker image save you/my-template:v1 -o t.tar
sbx template load t.tarsbx template ls and sbx template rm <name>:<tag> manage what has landed.
The image cache survives sandbox create and delete, clearing only on
sbx reset. Templates never auto-update — a moving tag still needs a manual
pull.
sbx template save <sandbox> <name>:<tag>, with --output file.tar to export.
It captures the whole filesystem, so any secret placed by hand ships with the
image — route credentials through sbx secret set and the proxy instead. And
user-level agent config such as /home/agent/.claude/settings.json is
regenerated at every creation, so it never survives into the saved image. Bake
config that must persist into the Dockerfile, or write it from a kit's
startup.
Verified against a research corpus and the sbx docs of 2026-08-07 (re-fetched unchanged on 2026-08-10). The bake
matrix expansion was run against buildx v0.36.0 on 2026-08-10, not just read:
docker buildx bake --list=targets produced the twelve targets described.
sbx --help
and sbx <cmd> --help are authoritative and current; prefer them to any command
list, including this one.
cd8f798
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.