Worktrees
You are given a run that is about to write something, and you return where each write goes: a durable registry that is versioned, local progress that is disposable, or nothing at all because the run needs no isolation. This module decides where in-progress state is written. It is the twin of the workspace question and it fails the opposite way: a wrong workspace makes an agent read the wrong repository and answer confidently; a wrong worktree makes an agent write where writes were forbidden, so the damage is loud but it lands in someone else’s source.
Law
State is placed by what it is worth, not by what is convenient. Something that must survive and be reviewable is versioned on its own branch; something rebuildable is local and ignored; a target repository is neither and receives nothing from a run’s bookkeeping.
The project segment is mandatory. State that is not filed under a project is state that another project will read as its own.
.claude is a trust tree, never a runtime storage root. A tree that stores the work also stores the
mess, and a rule tree with session debris in it stops reading as authority.
Situation codes
| Code | Situation | Where it goes |
|---|---|---|
WORKTREE-1 | State must survive and be reviewable | <Source>/.worktrees/<project>/registries, locked linked worktree on its own branch |
WORKTREE-2 | Progress or a rebuildable pack | <Source>/.worktrees/<project>/sessions or cache, ignored |
WORKTREE-3 | A path without the project segment, or under .claude | rejected; migrate behind <project> |
WORKTREE-4 | A registry worktree owned by another Git common directory | rejected; it is not this Source’s state |
WORKTREE-5 | Parallel agents about to write | isolate only when two of them mutate one file |
WORKTREE-6 | A worktree is stale, prunable or in the way | pruned deliberately; never force-removed as a directory |
Reading a run
- Name what the run produces, then ask of each output: must it survive review, or can it be
rebuilt? That single question separates
WORKTREE-1fromWORKTREE-2. - Never place state without the project segment. A path is checked for
<project>before it is written —WORKTREE-3. - Check ownership before trusting a registry. Locked, clean, on the project branch, owned by this
Source’s Git common directory —
WORKTREE-4. - Decide isolation by collision, not by parallelism. Many agents writing many different files need
no worktree at all —
WORKTREE-5. - Leave the target repository alone. A run’s bookkeeping never lands in the repository being worked on; durable product records belong to that repository through its own review, not through this state.
WORKTREE-1 — state that must survive
Situation. The run produces something a person will read later and may disagree with: a design registry, an accepted candidate, a decision record.
Recognition signs
- Losing it would lose a decision, not just time.
- Someone may need to see how it changed.
- It is not derivable from anything else on disk.
Ask yourself. If this were deleted, would a decision have to be made again?
Boundary
WORKTREE-2: anything rebuildable from source or from a run belongs there instead, however expensive it was to produce.
How it fails. Durable state is written into an ignored folder, so the history that justified a decision is gone the first time the folder is cleaned.
WORKTREE-2 — progress and rebuildable packs
Situation. The run produces its own footprints: partial progress, an index, a preview build, a memory pack.
Recognition signs
- It can be produced again by running the same thing.
- Nobody will review it.
- It grows without bound if nothing removes it.
Ask yourself. Can this be rebuilt by re-running the work?
Boundary
WORKTREE-1: if a reviewer would ever cite it, it is not disposable.
How it fails. A cache is committed, and from then on the repository carries a snapshot that contradicts the source it was derived from.
WORKTREE-3 — a path that skips the project, or hides under .claude
Situation. State is about to be written to <Source>/.worktrees/registries, or anywhere under
<Source>/.claude/.
Recognition signs
- No project segment in the path.
- The path lies inside the trust tree.
- Two projects on this machine would collide in that location.
Ask yourself. Would a second project write to this exact path?
Boundary
WORKTREE-4: this is about the path; ownership is about which Git directory the worktree belongs to.
How it fails. It works perfectly for the first project and silently mixes state for the second, and the trust tree accumulates run debris that makes its own rules look provisional.
WORKTREE-4 — the registry belongs to another Git
Situation. A registry worktree exists at the right path but is administered by a different Git common directory, or it is unlocked, dirty, or on the wrong branch.
Recognition signs
git worktree listfrom this Source does not account for it.- The branch is not the project’s registry branch.
- It has uncommitted changes nobody in this run made.
Ask yourself. Does this Source’s Git actually own this worktree?
Boundary
WORKTREE-6: a worktree this Source owns but no longer needs is pruned. One it never owned is refused.
How it fails. The run commits into a branch another checkout is standing on, and two histories start disagreeing about the same registry.
WORKTREE-5 — parallel agents about to write
Situation. Several agents run at once and each will write files.
Recognition signs
- Each agent’s output path is known before it starts.
- Either those paths are disjoint, or two agents will touch one file.
Ask yourself. Will two agents write the same file, or merely write at the same time?
Boundary
WORKTREE-1: isolation is about collision during the run; durability is a separate question answered separately.
How it fails. Isolation is bought for every agent by reflex — it costs setup time and disk each — or, worse, agents share one worktree and run in parallel, and the last writer erases the others. Agents that must share a worktree run one at a time.
WORKTREE-6 — a worktree is stale
Situation. A worktree is prunable, abandoned, or standing where new state must go.
Recognition signs
- Git reports it as prunable.
- Its branch is merged, gone, or was never pushed.
- Its directory is missing while the administrative record remains.
Ask yourself. Is the record stale, or is the work in it unfinished?
Boundary
WORKTREE-4: refuse what this Source does not own; prune only what it does.
How it fails. The directory is deleted by hand, so Git keeps an administrative record of a worktree that is not there, and the next run inherits an error nobody caused. Destructive Git is never run from a background agent, where nobody is watching the branch it stands on.
Inputs
| Input | Evidence required |
|---|---|
| project | A declared project name, never inferred from a folder |
| source | The repository holding the trust tree and workflow root |
| outputs | Each thing the run will write, and whether it is rebuildable |
| worktree list | Git’s own account of worktrees, with lock and prunable status |
| ignore proof | That sessions and cache are ignored by Source |
Rules
- Durable state is versioned on its own branch; rebuildable state is ignored. Nothing durable lives in an ignored folder.
- The project segment is mandatory in every state path.
.claudeis never a runtime storage root.- A registry worktree must be locked, clean, on the project branch, and owned by this Source’s Git.
- Isolation is decided by file collision, not by the number of agents.
- Agents sharing one worktree run sequentially.
- A run’s bookkeeping never writes into the target repository.
- Stale worktrees are pruned through Git, never by deleting a directory, and never from a background agent.
Exceptions
- Reuse over creation. An existing project root that already satisfies ownership is reused; a second root for the same project is a collision, not a convenience.
- Legacy migration. State already sitting at a rejected path is migrated behind
<project>once it is verified clean. A dirty legacy registry stops the migration instead of being copied over. - A branch that is only local. A registry branch that was never pushed is still valid state. It is reported as local-only rather than treated as missing.
Output
One block per thing the run writes:
output: <what is being written>
durability: <durable | rebuildable>
path: <.worktrees/<project>/registries | sessions | cache>
isolation: <required | not required>
ownership: <locked, clean, branch, owning git dir>
situation: <WORKTREE-1 | WORKTREE-2 | WORKTREE-3 | WORKTREE-4 | WORKTREE-5 | WORKTREE-6>
reason: <the fact that decided the placement>Worked example
Run. “Fourteen agents each write one new module directory under the trust tree, and the run records which candidate was accepted.”
output: the fourteen module directories
durability: durable, but they belong to the trust tree itself, not to run state
path: none — written in place
isolation: not required
ownership: n/a
situation: WORKTREE-5
reason: every agent's output path is known in advance and no two agents touch one file, so a worktree per agent would buy setup time and disk for a collision that cannot happenoutput: the accepted-candidate record
durability: durable
path: .worktrees/starci-academy/registries
isolation: required if a second run writes it at the same time
ownership: locked, clean, on the project registry branch, owned by this Source's git
situation: WORKTREE-1
reason: losing it would lose a decision rather than time, and a reviewer may need to see how it changedThe same run, audited against the machine, also reports a violation it did not create:
output: pre-existing worktree state
durability: n/a
path: .claude/worktrees/ — 10 worktrees, 9 of them prunable
isolation: n/a
ownership: owned by this Source's git
situation: WORKTREE-3
reason: the trust tree is holding runtime state, which the project-scoped root exists to replace; the nine prunable records are pruned through git, and the live one is migrated behind the project segmentNote what the third block does not do: it does not delete a directory. Nine stale records are a git
matter, and doing it by hand is how the tenth becomes an error nobody caused.
Scope
This module decides where in-progress state is written. It does not decide which repository is read — that is the workspace question — and it does not decide what the state means or who may review it.