docker-agent run --sandbox, one run end to end
One recorded docker-agent run --sandbox shows the kit, the sandbox, and the allowlist, and one sbx exec into the same VM shows the model call through the proxy.
You have an agent file with the filesystem and shell toolsets, and its model is ai/qwen3:4b on Docker Model Runner on your Mac. On the host, shell runs with your permissions. --sandbox moves the tools into a microVM and leaves the model on the host.
This section follows the recorded run, step by step, and figure 1.3 draws it. When you finish this section, you can read the launch summary of a sandboxed run and explain the two failures this run met.
The agent file
The agent file differs from the host version only in its provider. The 127.0.0.1 of your host cannot be reached from inside the sandbox, so the provider points at host.docker.internal:
version: "16"
providers:
host-runner:
provider: dmr
base_url: http://host.docker.internal:12434/engines/llama.cpp/v1
models:
local:
provider: host-runner
model: ai/qwen3:4b
temperature: 0
…Step 1: allow the model host
Persistent allowlist: the hosts that docker-agent sandbox allow stores, which docker-agent adds to the allow rules of the sandbox proxy on every later --sandbox run. The help names it the fix for a Blocked by network policy 403. The proxy translates host.docker.internal to localhost, so the capture allows localhost:12434 before the run:
$ docker-agent sandbox allow localhost:12434 (--config-dir, --data-dir, --cache-dir under fixtures/repo-sandbox/.m101, inside the workspace)
…
Added 1 host(s) to the persistent sandbox allowlist:
+ localhost:12434
[exit 0]
…Step 2: keep the state directories in the workspace
The capture kit keeps docker-agent out of ~/.cagent with --data-dir, --cache-dir, and --config-dir. With --sandbox, a data directory outside the workspace is refused, and the help gives only the default, ~/.cagent. The capture kit therefore puts all three under .m101/ in the workspace:
…
Error: --data-dir must be inside the sandbox's writable workspace $CAPTURE/fixtures/repo-sandbox
[exit 1]Step 3: the launch summary
…
Models gateway: none configured
Models catalog: allowlisting models.dev in the sandbox proxy
User sandbox allowlist: allowlisting 1 host(s) from `docker agent sandbox allow`:
- localhost:12434
sandbox docker-agent-<hash>
agent docker-agent
workspace $CAPTURE/fixtures/repo-sandbox (rw)
$CAPTURE/fixtures/agents (ro)
$CAPTURE/fixtures/repo-sandbox/.m101/cache/sandbox-kits/<hash> (ro)
$CAPTURE/fixtures/repo-sandbox/.m101/cfg (ro)
image docker/docker-agent-sbx-templates:latest
cpu 10
memory 32 GiB
…
✓ Created sandbox docker-agent-<hash>The run set no --models-gateway. It allows models.dev, because without that host the first catalog lookup fails with 403 Blocked by network policy. The next line repeats the host from step 1.
Auto-kit: a directory that docker-agent stages on the host and mounts read-only into the VM at the same path. Here it is .m101/cache/sandbox-kits/<hash>, and its manifest.json holds only agent_ref and built_at (the capture). The workspace is read-write, and the agent file's directory, the kit, and the config directory are read-only.
Step 4: an ordinary sandbox
During the run, sbx ls lists docker-agent-<hash> with the agent docker-agent, the status running, and the same four workspaces, three of them :ro (the capture). The sandbox is an ordinary one, and sbx lists and removes it like any other.
Step 5: the session store fails
Inside the VM, the run stopped before any model call:
…
Error: creating session store: migration failed even after database reset: failed to create migrations table: attempt to write a readonly database (1032)
Error:
[exit 1]The data directory sits on the virtiofs workspace mount, which mount lists as rw. A Python sqlite3 write on the same mount fails the same way (the capture), so on this host SQLite cannot write through that mount. The run printed no safety mode, so conflict C62 stays open. Docker Agent exits, but it does not stop or remove the sandbox VM, and the VM stayed running.
Step 6: the model call from inside
docker-agent version main
Commit: 154b78f2d517dae1397866dfb7586c4a302a3151
…
ANTHROPIC_API_KEY=proxy-managed
…
HTTP_PROXY=http://gateway.docker.internal:3128
…
NO_PROXY=localhost,127.0.0.1,::1,gateway.docker.internal
OPENAI_API_KEY=proxy-managed
…
Persistent sandbox allowlist is empty.The template runs docker-agent version main, not v1.149.0, although the docs say that :latest is built from the most recent v* release. The provider keys read proxy-managed. The in-VM allowlist is empty, because the allowed hosts arrive as proxy rules from the host.
The capture then starts the same agent file inside the VM by hand, with its state in /tmp/m101. This run shows the model path from the VM, not a working --sandbox launch:
$ sbx exec docker-agent-<hash> sh -c 'docker-agent --config-dir /tmp/m101 --data-dir /tmp/m101 --cache-dir /tmp/m101 run --exec --last …
…
The working directory contains README.md with 1 line.
[exit 0]The request to host.docker.internal:12434 leaves through HTTP_PROXY, because that host is not in NO_PROXY. The sandbox proxy changes host.docker.internal to localhost before it forwards the request, and the rule from step 1 admits it. The answer is correct: the capture kit copies the same README into every workspace, and it holds the one line hello (the capture).
Step 7: remove the sandbox
$ sbx rm --force docker-agent-<hash>
Deleting sandbox docker-agent-<hash>...
Sandbox 'docker-agent-<hash>' removed
[exit 0]A later run from the same workspace reuses the VM, and creates a new one only when the set of mounts has changed.
Docker Sandboxes (sbx) and Docker Agent (docker-agent) sbx 0.47.0, docker-agent 1.149.0 · bf4169c · 2026-10-07 · Edition 2026.10