You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
--clone is the reason teams with disposable-primary workflows can't leave sbx. On sbx, the primary workspace is an isolated in-container clone: the agent branches/commits/pushes without touching the host checkout, build/database state stays in the sandbox, and finished work comes back through an explicit git fetch sandbox-<name>. On msb, workspaces are direct host mounts (rw or :ro) — the agent edits the real checkout, which our ADR pinning sbx calls the load-bearing gap (the rest of our kit now runs on msb unchanged; we verified files, volumes:, and the toolchain end-to-end this week).
This proposes --clone as neutral acq vocabulary: passthrough on sbx (today's behavior), emulated by the msb adapter. Same trajectory as --image/ADR-0022 and volumes:/ADR-0023 — take a capability one backend has natively and make it a neutral knob the other backend implements its own way.
Prior art: disposable working copies are the industry default
Cloud agents all do clone-per-task into a fresh VM with an explicit git crossing back: OpenAI Codex cloud (repo cloned at a branch/commit into an isolated microVM), Cursor cloud agents (per-agent Firecracker VMs, repo cloned, snapshot-cached), Google Jules (clone into a GCP VM, PR back).
Sandbox platforms (E2B/Firecracker, Modal/gVisor, Daytona) bring code in by in-sandbox clone or upload — none mount a host checkout rw.
OpenHands offers a copy-on-write :overlay mount mode — clone semantics at the filesystem layer (agent edits a CoW layer; originals untouched).
Git worktrees (container-use, Agent Canvas) are the parallelism pattern but not an isolation boundary: the worktree's .git is a pointer into the main repo's .git, so a sandboxed agent would need rw access to the real object store, refs, hooks, and config — hooks/config being host-executed code paths.
sbx's distinctive contribution is the source: cloning from the local host checkout (uncommitted branches included, no forge round-trip) with a path-remote for fetch-back. That's the local-first variant of what every cloud agent does — worth making neutral rather than leaving as an sbx exclusive.
Proposed design (msb emulation)
At create, when --clone is passed on msb:
Clone the primary into a managed scratch dir, e.g. $XDG_STATE_HOME/acq/clones/<sandbox>/<repo>, and mount the scratch dir rw as the primary instead of the real path. Secondaries are unchanged (:ro as before).
git clone --no-hardlinks (or via file://) — this is load-bearing: a same-filesystem clone hardlinks object files by default, so an agent with write access to the scratch .git could modify inodes shared with the real repo's object store. The copy must be physical.
Register a sandbox-<sandbox> remote in the host checkout pointing at the scratch dir, mirroring sbx's recovery UX exactly: git fetch sandbox-<name> pulls agent branches back as hash-verified objects (hooks/config never transfer over fetch — the crossing is inert data).
acq rm deletes the scratch dir and the remote, warning about unfetched commits first (the same warning sbx prints today).
Deliberate divergence from sbx, proposed as the better default: a git clone carries no gitignored/untracked state. sbx's --clone copies gitignored files, which is how host-side build state (e.g. a macOS-initialized Postgres cluster in .devenv/state) poisons sandboxes — a documented trap in our kit's TROUBLESHOOTING. Workflows that need a specific ignored file (.env) already copy it in explicitly with acq cp; the doc story stays the same on both backends.
Tradeoff to state openly: the scratch clone lives on host disk (unlike sbx's in-guest clone), so agent writes land on the host — but confined to the managed dir, which is disposable by construction and never executed by the host's git.
CoW overlay mount (OpenHands-style): perfect state fidelity including ignored files, but merge-back is diff-shaped rather than git-native, and ignored-state fidelity is exactly the contamination the git clone avoids.
Clone-from-forge in-guest (the Codex/Jules pattern): works today over HTTPS, but loses uncommitted local work and adds a forge round-trip — not a substitute for local-first workflows.
Why acq-side
msb gaining a native clone feature would also close this, but the acq emulation is backend-neutral vocabulary (consistent with ADR-0022/0023), lands without an upstream msb dependency, and gives both backends identical UX (--clone, sandbox-<name> remote, rm warning). If msb later grows a native mechanism, the adapter can switch to it behind the same flag.
Problem
--cloneis the reason teams with disposable-primary workflows can't leave sbx. On sbx, the primary workspace is an isolated in-container clone: the agent branches/commits/pushes without touching the host checkout, build/database state stays in the sandbox, and finished work comes back through an explicitgit fetch sandbox-<name>. On msb, workspaces are direct host mounts (rw or:ro) — the agent edits the real checkout, which our ADR pinning sbx calls the load-bearing gap (the rest of our kit now runs on msb unchanged; we verified files,volumes:, and the toolchain end-to-end this week).This proposes
--cloneas neutral acq vocabulary: passthrough on sbx (today's behavior), emulated by the msb adapter. Same trajectory as--image/ADR-0022 andvolumes:/ADR-0023 — take a capability one backend has natively and make it a neutral knob the other backend implements its own way.Prior art: disposable working copies are the industry default
:overlaymount mode — clone semantics at the filesystem layer (agent edits a CoW layer; originals untouched)..gitis a pointer into the main repo's.git, so a sandboxed agent would need rw access to the real object store, refs, hooks, and config — hooks/config being host-executed code paths.sbx's distinctive contribution is the source: cloning from the local host checkout (uncommitted branches included, no forge round-trip) with a path-remote for fetch-back. That's the local-first variant of what every cloud agent does — worth making neutral rather than leaving as an sbx exclusive.
Proposed design (msb emulation)
At create, when
--cloneis passed on msb:$XDG_STATE_HOME/acq/clones/<sandbox>/<repo>, and mount the scratch dir rw as the primary instead of the real path. Secondaries are unchanged (:roas before).git clone --no-hardlinks(or viafile://) — this is load-bearing: a same-filesystem clone hardlinks object files by default, so an agent with write access to the scratch.gitcould modify inodes shared with the real repo's object store. The copy must be physical.sandbox-<sandbox>remote in the host checkout pointing at the scratch dir, mirroring sbx's recovery UX exactly:git fetch sandbox-<name>pulls agent branches back as hash-verified objects (hooks/config never transfer over fetch — the crossing is inert data).acq rmdeletes the scratch dir and the remote, warning about unfetched commits first (the same warning sbx prints today).Deliberate divergence from sbx, proposed as the better default: a git clone carries no gitignored/untracked state. sbx's
--clonecopies gitignored files, which is how host-side build state (e.g. a macOS-initialized Postgres cluster in.devenv/state) poisons sandboxes — a documented trap in our kit's TROUBLESHOOTING. Workflows that need a specific ignored file (.env) already copy it in explicitly withacq cp; the doc story stays the same on both backends.Tradeoff to state openly: the scratch clone lives on host disk (unlike sbx's in-guest clone), so agent writes land on the host — but confined to the managed dir, which is disposable by construction and never executed by the host's git.
Alternatives considered
:romount: closer to sbx's placement (working copy dies with the sandbox), but recovery is worse — the host can't fetch from guest storage, so commits leave via push (currently also blocked by the kit-hosts:22egress gap, msb: kitcaps.network.allowhosts get no port-22 egress — SSH push/clone to an allowed host times out despite the forwarded agent #402) or bundles copied out. Could be a later refinement; the host-side scratch dir gets the semantics right with the simplest lifecycle.Why acq-side
msb gaining a native clone feature would also close this, but the acq emulation is backend-neutral vocabulary (consistent with ADR-0022/0023), lands without an upstream msb dependency, and gives both backends identical UX (
--clone,sandbox-<name>remote, rm warning). If msb later grows a native mechanism, the adapter can switch to it behind the same flag.