2026-08-28 · Updated 2026-08-28 · 9 min read
Git worktrees for parallel coding agents
Isolate parallel coding agents with Git worktrees: the one-worktree-per-agent topology, ownership rules that prevent conflicts, recovery when boundaries fail, and how YYLO maps every task to its own worktree.
By Juno AI INC · worktrees · parallel-agents · yylo
The loudest way to parallelize coding agents is also the oldest mistake: point two agents at one checkout and wait. One agent regenerates a file the other is mid-edit on, a formatter run reverts a change that was fine, a half-finished refactor and a green feature land in the same dirty tree, and neither agent's report describes the bytes that actually exist. None of that is an agent problem. It is a working-tree problem, and Git solved it before any of these agents existed: a worktree is a second working tree attached to the same repository, so every lane gets its own files, index, and HEAD while the history underneath stays single and shared.
This guide owns the spatial half of parallel agent work: the worktree-per-agent topology, the ownership rules that keep concurrent lanes out of each other's files, recovery when a boundary fails anyway, and how YYLO turns the same shape into its unit of change. Two neighbors own the surrounding motion — the complete parallel workflow walks a batch from admission to closed evidence, and safe parallel execution owns readiness, quotas, and worker safety. None of those stages works for long if the agents underneath share one working tree.
How a Git worktree actually works
A worktree is a linked working tree, not a clone. One command attaches a new directory to the repository you are already in, creates a branch for it, and checks that branch out:
git worktree list answers with every working tree, its checked-out branch, and its path — the topology at a glance. Split the mechanics into what is shared and what is not, because both halves shape agent work:
- Shared: the object database, all refs, remotes, and repository configuration. Every worktree sees every branch and every commit. Nothing is duplicated, so creating a lane costs a checkout, not a copy of history.
- Per-worktree: the checked-out files, the index,
HEAD, untracked files, and build output. Dependencies and generated artifacts do not follow the worktree — a fresh lane needs its ownnpm installbefore its tests run.
One rule does most of the isolating: a branch may be checked out in only one worktree at a time, and Git refuses a second checkout, naming the path that already holds the branch. Treat that refusal as the mechanism it is. It is what stops two agents from committing to one branch from two directories, and it means lane identity comes from the branch, not the directory. Name both after the task — cart-total, search-index — never after a person or an agent product, because the lane outlives whoever or whatever worked in it.
Cleanup is part of the mechanics. git worktree remove ../cart-total deletes a lane whose work has landed; git worktree prune clears stale administrative entries after a lane directory was deleted by hand. Remove a worktree only after its commits are merged or deliberately abandoned — the directory is the only place an unmerged branch's uncommitted state ever existed.
One worktree per agent, one branch per worktree
The topology that survives parallel agents is boring on purpose. Keep the main checkout clean — it is where you read history, review diffs, and integrate; it is not a workspace. Give every concurrent task its own linked worktree with its own branch, and start exactly one agent session in each:
Whether the session is Claude Code, Codex, Pi, Cursor's agent, or OpenCode, an agent edits the working tree of the directory its session starts in. That is the whole wiring: cd into the lane, start the agent there, and its blast radius is that lane's files and that lane's branch. The main checkout is never at risk, and no agent ever sees another agent's half-finished state, because none exists in its tree.
The branch-per-worktree rule then encodes who may commit where. Two agents working one task from two directories on one branch is exactly the collision Git already refuses; two agents on two branches in two worktrees is the supported shape, and the only place their work meets is a merge. What a merge does with two branches is not decided by worktrees at all — that is the ownership question.
Draw ownership boundaries before launching
Worktrees prevent accidental co-editing. They do nothing about two lanes deliberately editing the same file on two branches — that collision simply moves to integration time. Boundaries are how you keep it from arriving there:
- One task owns a path set. When you split work into parallel tasks, name the files or directories each task may touch. Two tasks that must edit the same file are not parallel tasks; sequence them, and record the ordering where the work is tracked so the constraint survives your attention span.
- Generated files get one owner. A regeneration step rewrites whole files, so two lanes that both regenerate collide even when their hand-written edits never overlap. Regenerate in one lane, or after the other lanes land.
- State outside Git is not isolated at all. Worktrees isolate Git state, and only Git state — a database, a port, or a cloud account sits outside every worktree, so lanes pointed at the same one are coupled no matter how many directories exist. Bound those with the quota and admission discipline of the safe parallel execution guide.
The test for a boundary is cheap to run at planning time: read each task's path set aloud and check that no path appears twice. If one does, you have found either a sequencing mistake or a task that is really two tasks.
Recover when a boundary fails
Boundaries fail in two shapes, and they recover differently.
The first is a textual conflict: two branches edited the same lines, and integration reports it. Recover in the second lane, not in a third place — land the first lane, then rebuild the second lane on the new base and rerun the checks that cover its own surface:
Resolve only the paths the integration tool lists, keep both intents when both were wanted, and rerun the lane's focused tests before it re-enters integration — a resolved conflict is a claim that the two changes now compose, and the tests are the evidence.
The second shape is quieter: a semantic conflict. The branches touched different files and merge cleanly, but the changes break each other — one lane renames what the other calls, one changes a contract the other extends. No merge tool reports this class, because nothing overlaps textually. It is caught by the checks that run after integration, which is the honest reason to run focused validation on the integrated result rather than trusting green lanes. The recovery is the same loop one level up: fix forward in one place, on the integrated truth, and let the evidence — not the absence of conflict markers — say the work composes.
How YYLO maps every task to a worktree
Everything above is plain Git, and you can run it by hand. YYLO's contribution is that the topology is not a habit you maintain; it is the unit of change. Each task implements in a worktree the control plane created, against a base it recorded, and lands through one serialized queue:
yy task start creates one branch and one worktree for the task and freezes the exact target SHA the change is admitted against, so the base is recorded truth, not whatever the branch happened to point at when you looked. yy where task prints that worktree's resolved path and refuses ambiguous owners, so scripts and humans stop guessing directories. The work happens inside the boundary — implement, focused tests, a coherent commit — and the README names the principle: "The worktree is the safety boundary." yy task preflight inspects the tip read-only and reports closure defects before the expensive final gates run; yy task finish queues that committed tip for integration.
Integration is where the ownership rules become machinery. Feature worktrees are independent — each task implements against the exact base recorded at its start — and a single fenced arbiter serializes every target advance, one expected-old-SHA compare-and-swap at a time, so a moved target is composed against, never overwritten. When two changes genuinely collide, the queue preserves the conflict and lists the paths; resolve exactly those, then:
The lane model holds all the way to cleanup: a task worktree is removed only when the delivered commit is reachable and the worktree is safe to remove — never to make a conflict disappear.
Two isolation layers, two units
Parallel agent work has two distinct isolation layers, and confusing them causes most of the trouble. A worker lane is a process: one agent invocation with its own prompt, its own log, its own result record — the shape a parallel batch fans out over. A worktree lane is a place: one branch, one directory, one set of files. Batches of investigation, drafting, and review run fine as process lanes in one checkout because they produce records, not overlapping edits. Concurrent changes to one product run as process lanes only while the ownership rules hold — the moment two tasks can touch the same files, they need place lanes, because the cost of two agents editing one tree is paid in bytes.
When a batch of tasks does need real file isolation, each task gets its own worktree and its own agent session inside it, exactly as the mapping above describes — the batch cycle (admit through ready, bound the fan-out, read the evidence) is walked end to end in the parallel workflow guide, and composing process lanes with ordered chains is the multi-agent workflow guide's job. The operational reference for the task and merge commands on this page is the YYLO documentation.
Start with one worktree, one task
The topology is worth practicing at size one before you trust it at size four. Install YYLO, put a single verifiable outcome on the board, and let it create the first lane:
One task, one worktree, one agent inside it, one clean commit at the end — then a second task in a second worktree is a repetition, not a new experiment. The parallel habits that make many lanes safe (admission through readiness, bounded fan-out, per-lane evidence) are the same at any width, and the serialized landing path never changes. Grow by adding tasks, never by adding agents to one checkout.