CtrlK
BlogDocsLog inGet started
Tessl Logo

creating-sbx-templates

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

Quality

87%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Passed

No findings from the security scan

SKILL.md
Quality
Evals
Security

Creating sbx templates

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.

Pick a base

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.

Write the Dockerfile

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.
  • Set 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.
  • Pin versions as ARGs, so a rebuild is reproducible and a bump is one edit.
  • Leave 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.
  • Download, then run. 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.

Build a family with bake

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 --push

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

When the family multiplies

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 included

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

Publish and run

docker build -t you/my-template:v1 --push .
sbx run -t docker.io/you/my-template:v1 claude

sbx 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-stdin

Private templates work on Docker Hub only. Elsewhere, move the bytes:

docker image save you/my-template:v1 -o t.tar
sbx template load t.tar

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

Saving a running sandbox

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.

Last verified

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.

Repository
slurpyb/sbx-agent
Last updated
First committed

Is this your skill?

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.