Thomas Piacentini
← Workshop

Chapter

docker-agent run --sandbox, one run end to end

Original text · English

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

Fig. 1.3one docker-agent run --sandbox, step by stepsequence
docker-agent stages a kit, has sbx create the VM, and opens two hosts on the proxy, and the model call from inside then leaves through that proxy.
docker-agent stages a kit, has sbx create the VM, and opens two hosts on the proxy, and the model call from inside then leaves through that proxy. Read top to bottom, one numbered row per step, and row 8 is the failure that ends the run. Rows 1 to 8 come from the allow, run, and kit-cache captures. Rows 9 to 15 come from the inside run and the removal captures. The chunk name in row 12 is the stream format of the cassette.

Original SVG

Original source
id: fig-1-3
kind: sequence
title: one docker-agent run --sandbox, step by step
claim: docker-agent stages a kit, has sbx create the VM, and opens two hosts on the proxy, and the model call from inside then leaves through that proxy.
caption: Read top to bottom, one numbered row per step, and row 8 is the failure that ends the run. Rows 1 to 8 come from the allow, run, and kit-cache captures. Rows 9 to 15 come from the inside run and the removal captures. The chunk name in row 12 is the stream format of the cassette.

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 {{docs-sbx Accessing host services from a sandbox}}, so the provider points at host.docker.internal:

the provider block of the sandboxed agent fileyamlFull source
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
…
Cut to the version, the provider, and the model. The agent, its instruction, and its two toolsets are cut.
Original source
title: the provider block of the sandboxed agent file
source: capture/fixtures/agents/files-sandbox.yaml
lang: yaml
note: Cut to the version, the provider, and the model. The agent, its instruction, and its two toolsets are cut.
---
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 {{help-agent docker-agent sandbox allow}}. 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:

one host added to the persistent allowlisttextFull source
$ 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]
…
The welcome banner and the telemetry notice of the first run are cut, and so is the second command.
Original source
title: one host added to the persistent allowlist
source: capture/out/27-sandbox-allow.txt
lang: text
note: The welcome banner and the telemetry notice of the first run are cut, and so is the second command.
---
$ 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 {{help-agent docker-agent run}}. The capture kit therefore puts all three under .m101/ in the workspace:

a data directory outside the workspacetextFull source
…
Error: --data-dir must be inside the sandbox's writable workspace $CAPTURE/fixtures/repo-sandbox
[exit 1]
The command line is cut.
Original source
title: a data directory outside the workspace
source: capture/out/27-data-dir-outside.txt
lang: text
note: The command line is cut.
---
…
Error: --data-dir must be inside the sandbox's writable workspace $CAPTURE/fixtures/repo-sandbox
[exit 1]

Step 3: the launch summary

the launch summary of docker-agent run --sandboxtextFull source
…
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 command line and the image pull progress are cut. The rest of the output follows in step 5.
Original source
title: the launch summary of docker-agent run --sandbox
source: capture/out/27-sandbox-run.txt
lang: text
note: The command line and the image pull progress are cut. The rest of the output follows in step 5.
---
…
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 {{docs-agent Auto-Kit}}. 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 {{docs-agent Auto-Kit}}. 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:

the end of the sandboxed runtextFull source
…
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 two self-update warnings before the error are cut.
Original source
title: the end of the sandboxed run
source: capture/out/27-sandbox-run.txt
lang: text
note: The two self-update warnings before the error are cut.
---
…
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 {{docs-agent Sandbox Mode}}, and the VM stayed running.

Step 6: the model call from inside

the agent binary and the proxy settings inside the VMtextFull source
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.
Cut to the version, four environment lines, and the in-VM allowlist. The other variables and the self-update warnings are cut.
Original source
title: the agent binary and the proxy settings inside the VM
source: capture/out/27-inside.txt
lang: text
note: Cut to the version, four environment lines, and the in-VM allowlist. The other variables and the self-update warnings are cut.
---
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 {{docs-agent Sandbox Mode}}. 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:

the model call from inside the VMtextFull source
$ 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 command line is cut after the state flags, and the two self-update warnings are cut.
Original source
title: the model call from inside the VM
source: capture/out/27-inside-run.txt
lang: text
note: The command line is cut after the state flags, and the two self-update warnings are cut.
---
$ 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 {{docs-sbx Accessing host services from a sandbox}}, 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

the removaltextFull source
$ sbx rm --force docker-agent-<hash>
Deleting sandbox docker-agent-<hash>...
Sandbox 'docker-agent-<hash>' removed
[exit 0]
Nothing is cut.
Original source
title: the removal
source: capture/out/27-sbx-rm.txt
lang: text
note: Nothing is cut.
---
$ 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 {{docs-agent Sandbox Mode}}.

Original source
- Allow each host service with `docker-agent sandbox allow localhost:PORT` before the first sandboxed run.
- Expect `--sandbox` to refuse a `--data-dir` outside the workspace, and test that SQLite can write inside it first.
- Read the launch summary for each mount mode, the image, and every allowed host.
- Remove the sandbox with `sbx rm` when you no longer need it, because docker-agent leaves it running.

Sources: help-agent docker-agent run, docker-agent sandbox allow (research/sources/help-docker-agent.md); docs-agent Sandbox Mode, Auto-Kit (research/sources/docs-docker-agent.md); docs-sbx Accessing host services from a sandbox (research/sources/docs-sandboxes.md); research/conflicts-register.md rows C61, C62; capture/README.md; capture/fixtures/agents/files-sandbox.yaml; capture/out/27-sandbox-allow.txt, 27-data-dir-outside.txt, 27-sandbox-run.txt, 27-kit-cache.txt, 27-sbx-ls.txt, 27-sqlite-probe.txt, 27-inside.txt, 27-inside-run.txt, 27-sbx-rm.txt, 04-workspace.txt; capture/cassettes/18-files.yaml.gz

Code and artifacts 1
What you take away

Saved in your notebook on this device.

Sources and limits

Reading checkpoints are self-reported. Test results are recorded separately and apply to the executed cases.

AI Engineering from Scratch · 3f9715c · MIT

Download this file ↓