2026-08-29 · Updated 2026-08-29 · 13 min read

A Git-worktree parallel-agent reference architecture, version 1

A citable reference architecture for parallel coding agents isolated in Git worktree lanes: six permanent components (records owner, protected trunk, lane, candidate root, fenced arbiter, mirror), a one-writer ownership rule, the lane state machine from frozen-base allocation to reachability-gated cleanup, serialized merge admission by expected-value compare-and-swap with readback, and the configuration surface that binds it — every product behavior verified against committed YYLO source.

By Juno AI INC · worktrees · parallel-agents · system-design

When scaling coding agents horizontally goes wrong, the damage concentrates in the same three joints: two workers mutating one checkout, a shared branch taking writes from several directions, and an integration step whose outcome nobody can reconstruct afterward. Git already contains the raw material for all three fixes — worktrees, refs, and an update primitive that refuses to overwrite — but raw material is not an architecture. What a team needs to lift is a small set of named components with fixed responsibilities, so that "who may write this, and who may delete it" has one answer per artifact at any width of parallelism.

This page is that lift, as version 1 of a citable reference. It names six components with permanent identifiers WPA-1 through WPA-6, states the ownership rule each one lives by, walks the lane from allocation to gated removal, specifies the serialized admission that moves the trunk, and binds the whole shape with a configuration surface. The architecture is tool-agnostic in its contracts and concrete in its grounding: every product behavior named below was traced to committed YYLO source, checked on 2026-08-29, this version's grounding date — the task-workspace state machine, the merge-queue script, and the worktree-lifecycle reference in the installed controller assets — not recalled from prose. The component set, the identifiers, and the diagrams are this page's own contribution. No demand estimate stands behind the route: the competitor exports of 2026-08-26 that feed this program record no searches for it, and its standing comes from reuse, not from a keyword.

The topology: six components

The whole shape fits in one picture. Product bytes are born in lanes, composed in a queue-owned root, and landed on a single trunk; records never mix with bytes; humans read a mirror that follows the trunk.

text
records owner (WPA-1)          product repository
  task truth, receipts          trunk (WPA-2) <──────── CAS ────────┐
  queue state, config                 ^                             |
        |  allocate lane              | landing                     |
        v                             |                             |
  lane (WPA-3) ── committed tip ──> candidate root (WPA-4) ──> arbiter (WPA-5)
  branch + directory + agent          detached, queue-built           sole trunk writer,
  one admitted path set               compose + validate             fenced, on demand
                                                                      |
                                              mirror (WPA-6) <─────────+
                                              read, debug, run servers

Each component earns its identifier by owning exactly one thing:

  • WPA-1 — Records owner. The metadata store: task truth, lifecycle receipts, queue state, and the configuration that binds the topology. It contains no product code, and its bytes never merge into product history. In this site's vocabulary it is the control-plane layer (CHT-5), present here only as the component that makes records survive every runtime beneath them.
  • WPA-2 — Protected trunk. One branch ref that all landed work composes onto. It is never anyone's workspace: while the trunk is being advanced it must not be checked out anywhere, and the refusal names the checkout that holds it.
  • WPA-3 — Lane. One branch, one directory, one admitted path set, one writer at a time. Lanes are siblings under one workspace root, born from a frozen base, and each carries its identity in its own worktree-local Git configuration.
  • WPA-4 — Candidate root. A detached checkout the queue builds per admission attempt, outside every lane. Composition onto the current trunk and validation of the landing attempt happen here, under a random ownership token, and implementation never happens inside one — candidate roots are the queue's surface, not an agent's workspace.
  • WPA-5 — Arbiter. The only component permitted to move the trunk. It is on-demand and fenced: it takes a per-repository, per-ref lock, performs the advance, and exits when idle or blocked — it is not a daemon, and nothing polls it.
  • WPA-6 — Mirror. A registered, detached checkout that follows the trunk for reading, debugging, and running servers. It is advanced mechanically after each landing, and an advancement that cannot complete is a recorded, recoverable event rather than silent drift — a stale mirror announces itself. It is never the place a change is written.

The one-way flow is the point: bytes move lane → candidate root → trunk → mirror, never sideways; records move only through the records owner. A second controller pointed at the same repository is not a second topology — the arbiter's lock file sits in the repository's shared Git administration, the directory every worktree of that repository shares, so distinct records owners over one trunk contend on the same inode.

Ownership: one writer per artifact

Parallelism is safe exactly where every artifact has one writer, and the topology assigns them without overlap.

  • Record writes belong to the records owner. Task state, receipts, and queue state are written by the lifecycle machinery, in transition order, so a record is a fact about a crossing that already happened rather than a diary entry.
  • Lane bytes belong to the lane's one session. The agent implementing the task edits its lane's directory and commits to its branch; the committed tip is the unit of progress, and nothing else writes either surface while the lane is live. Edits outside the admitted path set are the boundary-escape class CAF-3 of this site's failure taxonomy; the pre-launch form of the same discipline is RLS-7 and RLS-8 in the loop checklist, referenced here by identifier only.
  • The trunk belongs to the arbiter. No lane, no human, and no script outside the arbiter advances the protected ref; the mechanism below makes the advance itself refuse when the world moved.
  • Candidate roots belong to the queue. Created detached, owned by token, removed by the queue's own gate — a lane never observes another lane's admission attempt.
  • The mirror belongs to the landing machinery. It follows the trunk after each advance; commits do not originate there.

Identity is checkable rather than remembered. At allocation the lane's worktree-local configuration receives its role, its base commit, its task id, and content digests binding its manifest, its creation receipt, its admitted paths, and its materialized path list — so any process entering the directory can answer *which lane this is and from what base* by reading Git configuration, with no human in the loop. Re-entering a lane whose recorded identity no longer matches the record behind it is a refusal that preserves the directory for inspection: "task start identity drifted; preserve the worktree and inspect task status". The same closed posture meets orphans: a branch or a worktree path that already exists with no task record behind it is refused — "task branch already exists without a task record" — never adopted, because adopting it would graft unrecorded history into a governed lane.

One neighboring job is deliberately not restated here: how several agents claim, scope, and land *task records* without ambiguous shared state — claims with accounts, per-agent admission scopes, and sealed board merges — belongs whole to the coordination guide. This page's ownership rule stops at the topology's artifacts; the records inside WPA-1 have their own coordination contract.

The lane lifecycle

A lane is a state machine with one owner per transition, and every state has a defined failure path. The states, in order:

text
allocated ──> hydrating ──> working ──> queued ──> under admission ──> landed ──> retired
   |              |            |           |             |               |
 receipt      provision     commit,     closure       compose,        CAS +
 frozen:      failure ->    checkpoint   re-check,     validate on     readback,
 base SHA     preserved    preflight    persisted     the live        mirror
 path set     + recorded   (read-only)  validation    trunk           advance
              as failed                 on the tip

Allocation is the moment the base is frozen. The records owner resolves the trunk ref to one commit, computes the admitted path set, and only then creates the branch and directory — the worktree command names that exact commit, not a symbolic ref, so the lane's base is recorded bytes rather than a pointer that later moves. The creation receipt binds the base, the branch, the path set, and digests of the task manifest; provisioning then runs a named hydration workflow whose identity was frozen with the base, and a provisioning failure parks the lane in a failed-but-preserved state with its evidence recorded — recoverable through an explicit retry that re-verifies the frozen identity, never silently retried into a different tree.

Working is where agents live: implement, run focused checks on the changed surface, commit coherently, optionally checkpoint. The queue-facing transition repeats the closure read-only first — the tree is clean and the work sits on a committed tip — then persists that closure and runs the selected validation before the tip is recorded as queued. An interrupted admission is not a hole: the window between the recorded intent to merge and the trunk advance is durable, and recovery revalidates against the live trunk and rebuilds rather than trusting pre-crash evidence — a retry after the trunk moved composes on whatever the trunk actually is now.

Running whole batches of lanes — admitting through readiness, bounding the fan-out, reading what a drained pool wrote — is the execution cycle owned by the parallel workflow guide; this page contributes only the lane's own contract. The lane's practical mechanics, from the first worktree command to recovering a failed boundary, are walked in the Git-worktrees guide.

Merge admission: the only trunk writer

Landing is where parallel lanes stop being parallel, and the architecture spends its strictness there. Four properties do the work.

One writer at a time, per repository and ref. The arbiter takes an exclusive lock keyed by repository identity and target ref, placed among the repository's shared Git administration — so a second records owner, or a second queue, over the same repository contends on the same lock file and receives "another worker owns this repository/target-ref queue". Ownership is not reclaimed by patience: lease age alone never transfers it, a successor requires proof the producer died or an explicit handoff, and observers read status commands rather than polling the lock.

The advance refuses a moved world. The trunk update is a compare-and-swap: the ref update names both the new commit and the commit it expects to replace. If the trunk moved underneath the plan, the update fails with "target moved before compare-and-swap; no ref was changed" — no partial state, no second-guessing, just a re-plan against reality. When the trunk has moved, the queue composes the candidate onto the new tip; overwriting a moved trunk is not an operation the contract offers.

The result is read back before anyone trusts it. After the update, the arbiter re-reads the ref and requires the commit identity to match the candidate, then the tree identity to match, and only then advances the registered mirror. A landing that cannot prove what it wrote is a recorded failure, never a success.

Disagreement has a budget. A textual conflict is preserved, not resolved by machinery: the conflicted paths are listed, resolution touches exactly those paths, and the resolved candidate re-enters the same gate. A changed candidate invalidates the semantic evidence gathered against the old bytes; repair is allowed once, a delta review once more, and a candidate that still cannot converge is stopped in a recorded terminal state instead of looping at the gate. Review depth itself is risk-selected by policy before any reviewer runs.

Cleanup that refuses first

Removing a workspace is the most dangerous cheap-looking operation in the topology — it is the only step that can destroy the sole copy of unrecorded work — so the reference inverts the default: removal is gated, and every doubt preserves. The gate is strictest where the machinery owns both ends, and it applies to both removable surfaces.

The queue's own candidate root is removed only when all four hold: the ownership token verifies; the directory's head is exactly the recorded candidate commit; the tree is clean, untracked files included; and the delivered commit is an ancestor of the trunk — reachable, so history no longer needs the directory. Each failure preserves with a named reason (ownership_mismatch, candidate_head_mismatch, dirty, candidate_unreachable_from_target), and even the removal command failing preserves rather than half-removes.

A lane is held to the same posture with a coarser instrument: its removal refuses unless the delivered commit is reachable from the trunk and the lane is safe to remove. What the two tiers share is the consequence — a preserved workspace is always an evidence surface, and an operator returning to a dirty or unreachable one finds bytes to inspect, not a vanished directory. Deletion is never a conflict-resolution move and never a janitorial convenience — retiring a lane is a statement that the trunk now contains its work, and the gate exists to make that statement provable before it becomes irreversible.

The configuration surface

The topology is bound by one configuration document the records owner owns, validated at load rather than trusted at use — unknown keys are refused, and the required fields name their own shapes. Its topology-binding subset, as a generic example:

json
{
  "schema_version": "juno_task_workspace_config.v1",
  "repository": ".",
  "target_ref": "refs/heads/main",
  "workspace_root": "/srv/agent-lanes",
  "branch_prefix": "refs/heads/lane-",
  "hydration_workflow": ".juno_task/config/worktree-hydration.yaml"
}

The rules behind the keys: the trunk is named as a full local branch ref (a refs/heads/ spelling, checked at load); the branch prefix is a full local prefix that must end in a hyphen, so every lane branch is derivable as prefix plus task id and validated as a ref before creation; lanes are created as sibling directories named by task id under one root, which is what makes WPA-3 enumerable by listing. Three further lists ride the same document: the baseline admitted paths every lane receives, the selectable roots a start may additionally request (frozen into the creation receipt when a lane is allocated, so path admission is a recorded fact rather than a habit), and the controller-private paths excluded from every lane — records-side data that must never materialize inside product bytes. Focused validation profiles and their timeouts are named in the same place, so the queue's validation bill is configuration, not improvisation.

For teams porting the reference onto other tooling, the transferable contract is the pairing: one document binds trunk, lane naming, admission, and exclusion — and the document is validated, versioned, and read by the machinery that enforces it, so drift between the drawn architecture and the running one fails closed.

Sources, neighbors, and reuse

Two evidence classes stand behind this page, matching its declared sources. Product behaviors — the frozen-base allocation, the identity binding in worktree-local configuration, the orphan and drift refusals, the shared-state lock, the compare-and-swap with dual readback, the preserved-conflict resolution path, the bounded repair budget, and the five preservation reasons — were each located in committed YYLO source during the 2026-08-29 grounding pass, in the task-workspace and merge-queue scripts and the installed worktree-lifecycle reference, at the recorded depth. The six components, their identifiers, the diagrams, and the statements of the contracts as an architecture are original research on this page; YYLO is the worked implementation, not the claim's only possible instance. A whole-system treatment — where audit points, admission boundaries, and rollback seams sit across an entire development system rather than inside its parallelism — has its own page in this program and is deliberately not absorbed here.

Reuse is the primary goal. Lift the component set and the one-writer rule into your own tooling; cite the identifiers with the version and date below when you do, because that pairing is what lets a design doc six months from now name exactly which architecture it deployed.

Stability policy

Identifier permanence is absolute: for as long as this page resolves, WPA-1 through WPA-6 keep their numbers and the components they name. Retiring a component retires its identifier with it; the number is never handed to a successor meaning. Sharpening a sentence without relocating a component boundary is an in-place revision, journaled below with its date. Introducing a seventh component, deleting one, or reassigning which artifact a component owns opens a new version carrying its own grounding date, and prior versions stay reachable through the journal rather than being overwritten. The product contracts are re-traced to committed source on a quarterly cadence; a re-trace that alters nothing is itself journaled, and the current version number holds.

Changelog

  • First publication — version 1, grounding date 2026-08-29. Six components, the one-writer ownership rule, the lane state machine, the admission contract, the gated-removal contract, and the configuration surface. No earlier version exists; no identifier has been reassigned.

Citing the architecture

Cite the identifiers with their version number and grounding date; that pairing is what pins a design document to the exact architecture it deployed, even after later versions arrive. The recommended form:

text
Worktree parallel-agent reference architecture, version 1 (WPA-1 through WPA-6)
https://yylo.dev/guides/worktree-parallel-agent-reference-architecture
YYLO, product contracts read from committed source 2026-08-29

A design document that names WPA-3 and WPA-5 tells its next reader precisely which writer owned which artifact — and the version number and date tell them how to check that the architecture they inherited is the one this page still describes.