v1.4.0next
Guides

Build a worker Kit

Build a Docker Sandbox Kit for Kraft's Claude workers, push it to your registry, and run a repository's sandbox from it, pinned by digest.

A Kit is an image that carries its own sandbox policy: which hosts its workload may reach, which credentials it holds, and its limits. Kraft runs a Kit you build for it. Docker's published Kits require capabilities Kraft does not enforce, so Kraft refuses them.

This guide builds a Kit for Claude workers, pushes it to your registry, and points a repository at it. Kraft publishes no worker image of its own.

Before you start

  • Docker with BuildKit (docker buildx), logged in to a registry you can push to. Replace registry.example.com/acme below with yours.
  • The machine that runs Kraft logged in to the same registry: Kraft reads the Kit with that machine's docker manifest inspect and pulls it with its docker run.
  • An Anthropic API key in the Kraft daemon's environment.

1. Write the image

The image needs the platform floor and the agent CLI, and no agent Entrypoint: Kraft keeps the image's entrypoint and replaces its command with the one the harness file builds, so an entrypoint that is the agent itself runs the agent twice.

FROM docker.io/library/node:22-slim
RUN apt-get update \
 && apt-get install -y --no-install-recommends bash ca-certificates curl git \
 && rm -rf /var/lib/apt/lists/*
RUN npm install -g @anthropic-ai/claude-code

Save it as Dockerfile. Kraft bind-mounts each session's result file on its own, so the worker writes it in place; a tool that replaced it by renaming a new file over it would fail. The Claude CLI writes it in place.

2. Write the descriptor

Save this as kraft-worker-claude.yaml beside the Dockerfile:

# syntax=docker/sandbox-kit:3
schemaVersion: "3"
kind: workload
displayName: Kraft claude worker
dockerfile: Dockerfile
capabilities:
  - type: com.docker.sandbox/network-policy@1
    config:
      runtime:
        allow: [api.anthropic.com, statsig.anthropic.com]
  - type: com.docker.sandbox/credential@1
    config:
      service: anthropic
      phase: runtime
      apiKey:
        name: ANTHROPIC_API_KEY
        proxyManaged: true
        inject:
          - {domain: api.anthropic.com, header: x-api-key}
  - type: com.docker.sandbox/resources@1
    config: {cpu: 2, memory: 2gib}

What each capability becomes in Kraft:

  • network-policy@1: the sessions reach api.anthropic.com and statsig.anthropic.com and nothing else. There is no install phase, so the repository's setup_command reaches nothing: build what setup needs into the image, or add an install allow list. The Claude harness's own hosts are not added under a Kit, so a Kit for Claude lists them itself.
  • credential@1: the container holds ANTHROPIC_API_KEY only as a sentinel, and Kraft's egress proxy puts the real key in x-api-key on its way to api.anthropic.com. The value comes from the daemon variable you bind to the anthropic service in step 4.
  • resources@1: two CPUs and a 2 GiB memory limit on every session.

3. Build, push and pin it

docker buildx build -f kraft-worker-claude.yaml \
  -t registry.example.com/acme/kraft-worker-claude:1 --push .
docker buildx imagetools inspect registry.example.com/acme/kraft-worker-claude:1

The # syntax=docker/sandbox-kit:3 line makes BuildKit build it with the Kit frontend, which puts the descriptor on the image's manifest. The second command prints the digest (Digest: sha256:...). Pin the Kit by it: a tag could name a different Kit tomorrow, and Kraft refuses one.

4. Point a repository at it

In repos.yaml, under the repository's entry:

sandbox:
  kind: kit
  runtime: docker
  kit: registry.example.com/acme/kraft-worker-claude:1@sha256:<the digest>

In sandbox.yaml, bind the credential's service to the daemon variable holding the key:

credentials:
  anthropic: ANTHROPIC_API_KEY

The right-hand side is a variable in the Kraft daemon's environment; it can have any name.

5. Check it

kraft admin doctor

The repository's sandbox row reads and checks the Kit. A kit hosts row warning about Amp, Codex or Gemini hosts is expected: this Kit is for Claude, and sessions of other harnesses under it are refused their hosts.

File a work item on the repository. Its first task records a sandbox_kit_resolved event: kraft view events ID --type sandbox_kit_resolved. If the item stops instead, see A Kit is refused.

Changing the Kit

A rebuilt Kit has a new digest. Put the new digest in kit:. An item filed before the change keeps the sandbox it was filed with.

Copyright © 2026