Filesystem isolation: worktrees, reflinks, overlays and snapshots
Two different things need cloning: the sandbox's own root filesystem, and your project. They do not have to use the same mechanism, and getting this right is what makes fanning one task out to five agents cost almost nothing.
The rule that matters
The five ways to clone a workspace
| Strategy | Disk at N lanes | Setup time | Carries node_modules and caches? | Platform | Where it wins |
|---|---|---|---|---|---|
| Git worktree | ~N × working tree (objects shared) | 180–350 ms on SSD; minutes on a huge monorepo | No — every new worktree starts cold | Windows, Linux, macOS | The default whenever the folder is a Git repo. Least surprising, reviewable as a branch, no new tooling. |
| Reflink / CoW copy | ~1× (blocks shared until written) | Near-constant — a 2 GB tree in ~130 ms on APFS | Yes, including build output and caches | APFS, Btrfs, XFS, bcachefs. Not ext4 or NTFS. | Non-Git directories, and any tree whose value is in untracked artifacts. This is the single biggest practical win for monorepos. |
| OverlayFS (lower + per-lane upper) | Minimal upper per lane | Mount plus empty upper | Yes, via the lower layer | Linux (native kernel or fuse-overlayfs) |
Non-Git trees inside a Linux container or VM. Note the rename footgun: moving a file from lower into upper fails with EXDEV, which is known to break node_modules/.vite/deps. |
| qcow2 backing file | Delta only per VM | Instant (qemu-img create -b base.qcow2) |
Yes — it is the whole disk | Anywhere QEMU runs | VM and microVM disk images. This is how you get five near-instant VMs from one base without inventing a format. |
| Snapshot / clone (Incus, ZFS, Btrfs) | Near zero for snapshots | Sub-second on a CoW backend | Yes — it is the whole instance | Linux hosts | Persistent agent machines you fork per task. Storage driver decides whether it is free or expensive. |
| Plain recursive copy | N × size | O(size) | Yes | Everywhere | The reliable fallback. Fine for one lane, wasteful for ten. |
- A Git upstream patch for copy-on-write worktrees measured a Linux kernel fork (93k files, ~33 GB) needing ~0.9 GB of real disk per worktree on Btrfs, growing linearly, versus ~0 at any lane count with reflinks — and the reflink version also carries the untracked build tree.
- Eight isolated views of a 300 MiB tree: 2.4–2.6 GB with plain worktrees versus 301 MB with CoW views, at 2.1× the cold setup time.
- A Firefox-scale build cache: two worktrees summed to 47.2 GB naively, saved 27.4 GB via reflinks, measured 19.9 GB on disk — and restoring 13.5 GB of compiled artifacts into a second worktree wrote zero new bytes.
- Per-turn snapshots of 5,000 small files:
cp -r1,970 ms, a CoW clone 487 ms.
A worktree shares the object database, refs and config — not the working tree. Each one still
materialises every tracked file, so a repo with large generated assets or a heavyweight
node_modules gets expensive at ten lanes. The practical fixes, in order: reflink the ignored
directories after creating the worktree; use a warm pool of pre-provisioned worktrees so acquisition is
milliseconds instead of a two-minute install; use cone-mode sparse checkout plus partial clone for
enormous monorepos; and share compiled artifacts through a content-addressed cache rather than duplicating
them.
The strategy picker
Cloning the sandbox itself
The second half of the problem is the environment the agent runs in. Here the mechanisms are different and usually already built into your runtime.
Containers: image layers are already copy-on-write
Ten containers from one image share the immutable layers and each write only their own upper layer. You get cheap fan-out for free — right up until you bind-mount your project, at which point the bind mount deliberately exposes the host directory and all that layering stops applying to your source.
Implication: keep "the sandbox root filesystem" and "the project workspace" as separate concepts, because they use different mechanisms.
VMs and microVMs: qcow2 backing files and snapshots
qemu-img create -f qcow2 -b base.qcow2 -F qcow2 lane1.qcow2 gives you five lanes from one
base with delta-only writes. Incus snapshots do the same at the instance level. This is the
"instant five copies" mechanism people reinvent badly — it already exists, and it is not a format you
need to design.
Checkpoints are not memory
Filesystem checkpoints capture files. They do not rewind processes, pending network requests or open file handles, and they do not capture what a running agent had in RAM. If a lane has credentials written into it, the checkpoint contains those credentials — a detail at least one local sandbox tool documents plainly, and one that most do not mention at all.
The sharp edge to avoid
git clone --shared is described by Git's own documentation as a possibly dangerous
operation: it sets up object alternates referencing the source repository, and if those source objects
later become unreferenced and are pruned, the dependent clone can be corrupted. There is no reason to put
that in a product when git worktree exists.
The apply-back workflow
This is the part most tools get wrong, and it is mostly a user-interface problem rather than a plumbing one. A good workflow has four verbs, and they should be visible as verbs:
| Verb | What it does | What it must never do |
|---|---|---|
| Keep | Apply selected files or hunks from a lane onto the host working tree, as a commit, a cherry-pick or a patch. | Apply everything silently because the agent said it was done. |
| Export | Produce project-box2/ next to the original, so you can diff two results side by side without touching your tree. | Overwrite an existing directory of the same name. |
| Discard | Delete the lane and its workspace, freeing the copy-on-write blocks. | Discard the checkpoint you would need to recover something you later wanted. |
| Keep lane | Leave the sandbox and its workspace alive for another round of instructions. | Leave it running and billing, or leave it discoverable only if you remember its container ID. |
RW has done
more for safety than a dozen warnings in a settings file.