3.2

--clone and /run/sandbox/source

Bind mode gives the agent your files, :ro and mountless modes give it less, and --clone gives it a private clone whose commits come back through a git remote.

You let an agent work on a repository overnight. In the morning git diff is clean, and a new file sits in .git/hooks/pre-commit, where no diff ever shows it. The three workspace modes decide how much of your tree the agent can write. With --clone it can write none of it.

When you finish this section, you can pick a workspace mode for a repository and fetch an agent's commits out of a clone-mode sandbox.

Three workspace modes

Direct mount: the workspace path mounted inside the VM at the same absolute path, read-write. In m101-demo the agent's pwd is $CAPTURE/fixtures/repo, the same string as on the host. git log lists the host commits c7dfd56 second and 086df68 first (the capture).

The mount is virtiofs, as the microVM boundary showed, and the file synchronization of the legacy plugin is gone (conflict C5). Extra paths follow the first one, and :ro makes one read-only. A read-only argument can name a single file. That keeps one path out of reach in a workspace that the sandbox can otherwise write.

Mountless: no path on sbx create, so the VM has no host bind mount. The agent works in the template's working directory, /home/agent/workspace for Docker's templates. m101-policy was created that way, and sbx create printed workspace none · no workspace bind mount (the capture). sbx run without a path mounts the current directory instead, which sbx run, create, stop, and rm warns about.

Direct mode needs a review step. The docs list what the agent can edit, such as Git hooks, CI configuration, package.json scripts, and .claude/settings.json. They warn that hooks do not show up in git diff. A Docker Captain described this covert channel on 2026-05-26, and it is the reason clone mode exists.

Clone mode

--clone: a flag at creation that runs the agent on a private clone of the host Git repository inside the container. The host repository is mounted read-only. It replaced --branch in v0.31.0, and --branch now fails with --branch is no longer supported; use --clone instead (conflict C6). The flag is a no-op when you re-attach to an existing clone-mode sandbox. The capture created m101-clone with it:

creating a clone-mode sandboxtextFull log
$ sbx create --clone shell $CAPTURE/fixtures/repo-clone --name m101-clone
✓ Git repository detected: $CAPTURE/fixtures/repo-clone
…
  Git daemon: git://127.0.0.1:<port>/repo-clone
  Remote: sandbox-m101-clone
✓ Created sandbox m101-clone
  mount  $CAPTURE/fixtures/repo-clone → /run/sandbox/source (ro, source)
…
SANDBOX      AGENT   STATUS    PORTS                        WORKSPACE
m101-clone   shell   running   127.0.0.1:<port>->9418/tcp4   $CAPTURE/fixtures/repo-clone
The image pull and the second sbx ls row are cut.

Inside, three facts stand out (the capture). The clone sits at the same path, $CAPTURE/fixtures/repo-clone, on /dev/vde, an ext4 volume, and its origin is /run/sandbox/source. The source mount is host on /run/sandbox/source type virtiofs (ro,nosuid,nodev,relatime), and touch /run/sandbox/source/x fails with Read-only file system. A commit made inside, 81e11df from sandbox, cannot be pushed to origin either: git push ends with remote unpack failed: unable to create temporary object directory (the capture). The docs name the limit: clone mode keeps the agent from changing your host repository. Reading it is still possible, so an untracked .env under the repository is readable inside.

Getting commits back

The git-daemon in the VM listens on 9418, and sbx publishes it on a loopback port. The CLI then writes a remote into the host repository's .git/config:

the sandbox remote on the host, before and after a fetchtextFull log
$ git -C $CAPTURE/fixtures/repo-clone remote -v
sandbox-m101-clone	git://127.0.0.1:<port>/repo-clone (fetch)
sandbox-m101-clone	git://127.0.0.1:<port>/repo-clone (push)
…
file:.git/config	remote.sandbox-m101-clone.fetch=+refs/heads/*:refs/remotes/sandbox-m101-clone/*
file:.git/config	remote.sandbox-m101-clone.fetch=+refs/heads/*:refs/sandboxes/m101-clone/*
…
$ git -C $CAPTURE/fixtures/repo-clone fetch sandbox-m101-clone
…
   c7dfd56..81e11df  main       -> sandbox-m101-clone/main
   c7dfd56..81e11df  main       -> refs/sandboxes/m101-clone/main
…
81e11df from sandbox
c7dfd56 second
086df68 first
The core.* config lines, the ls-remote output, and the fetch warning are cut.

Two fetch refspecs mean one fetch updates two places: refs/remotes/sandbox-m101-clone/main and refs/sandboxes/m101-clone/main. sbx rm removes the remote and the daemon and prints the recovery command git branch <local-name> refs/sandboxes/m101-clone/<branch>. In the capture, refs/sandboxes/m101-clone/main survived the removal (the capture). sbx stop stops the daemon, and a restart assigns a new port and rewrites the remote URL. The /root/.config/git/attributes warning in the fetch output comes from the daemon's user inside the VM and changes nothing. sbx kit add keeps the clone on a named workspace volume, which is the ext4 device above, and sbx rm cleans up the Git worktrees.

Figure 3.2 follows one commit from the clone to the host refs.

Fig. 3.2one commit from the clone to the hostflow
One commit from the clone to the host On the left, the host repository at $CAPTURE/fixtures/repo-clone with main at c7dfd56. A read-only virtiofs mount carries it into the sandbox m101-clone at /run/sandbox/source. The agent works in a private clone on an ext4 volume whose origin is that mount, and commits 81e11df. A git push to origin is refused by the read-only mount. git-daemon serves the clone on port 9418, published on a loopback port, and the host remote sandbox-m101-clone fetches it into refs/remotes/sandbox-m101-clone/main and refs/sandboxes/m101-clone/main. After sbx rm, the remote is gone and the refs/sandboxes entry survives. HOST · $CAPTURE/FIXTURES/REPO-CLONE SANDBOX M101-CLONE .git and working tree main at c7dfd56 second /run/sandbox/source virtiofs ro · Read-only file system bind mount, ro private clone, same path /dev/vde ext4 rw · origin = the mount 81e11df from sandbox git clone git push: unpacker error git-daemon :9418 published as 127.0.0.1:<port>->9418/tcp4 serves the clone remote sandbox-m101-clone git://127.0.0.1:<port>/repo-clone two fetch refspecs in .git/config git fetch sandbox-m101-clone after the fetch sandbox-m101-clone/main 81e11df refs/sandboxes/m101-clone/main 81e11df sbx rm: remote and daemon removed, refs/sandboxes/m101-clone/main survives
The host repository enters the VM read-only at /run/sandbox/source, the agent commits to a private clone, and git-daemon serves that clone back as a host remote. Read from the host repository across to the clone and back down to the host refs. Solid teal arrows are the fetch that writes two refs. The dashed rose arrow is the push that the read-only mount refuses.

Docker Sandboxes (sbx) and Docker Agent (docker-agent) sbx 0.47.0, docker-agent 1.149.0 · bf4169c · 2026-10-07 · Edition 2026.10