Skip to main content
A recipe’s sources: list places things into the box at a path. Exactly one of four kinds names each source’s origin — and the kind decides whether the box’s writes ever reach your disk.
Screens verified by walkthroughs/test_sources.py.
Add ro: true to any mount to make it read-only inside the box.

Copy vs mount, demonstrated

This recipe hands the box a snapshot of the project and a read-only reference directory:
The box writes a file into its copy:
Your directory never sees it:
And the read-only mount refuses writes outright:

What a copy leaves behind

A copy: . source snapshots your cwd into a workdir node (its bytes live in that node’s held space), and the boot says so:
The snapshot survives the box on purpose — it may hold work the agent produced. Review it at the printed path, then reap it like anything else: dabs rm <workdir-id> -y.
Repeated copy:/scratchbox boots mint a new workdir node each time. They accumulate; sweep them periodically or dabs ls fills with stale snapshots. See Caveats.

mkmount: provisioning on first boot

mkmount: is mount: that creates its host origin if missing — say it where you mean “provision this”. The canonical use: a login/config dir a harness fills on first run, shared by every later box that names it:
The first box boots with an empty dir, you log in once inside, and every later box mounting that path is already logged in. A plain mount: whose origin is missing is treated as a typo and refused:

A per-box destination: $NODE_ID

A source’s path: (and the recipe’s workdir:) may name $NODE_ID — the id of the box being provisioned. It is the one variable a box path may name; the space variables name host origins only. It earns its keep when a tool keys state off its own working directory. A recipe that mounts . → /work gives every box the identical cwd, so every agent session inside derives the same transcript slug and they collide across boxes. Namespacing the destination gives each box its own:
The id is validated as a slug before it is substituted, so it can carry no / and no ..: $NODE_ID cannot move a mount out of the path that names it.

Where a snapshot lands: at:

For worktree: and copy: sources, at: says where the bytes land in the new node’s own spaces — e.g. at: $NODE_HELD/worktree (the default), so rm asks before reaping the checkout. See Spaces.