All labsLab 07
Level 330 min+150 XP

Two Agents, Two Worktrees, One Merge

Build two features at the same time, in two folders, with two agents — then put them back together.

After this module you can

run two agents in two worktrees at once, merge both branches, and resolve the conflict that follows

You need
  • Your project in git with a clean status and everything pushed (Lab 06)
  • Claude Code run at least once in that folder, so the workspace is trusted (Lab 01)
  • A CLAUDE.md in the repo (Lab 03)
  • Three terminal windows — two to work, one to watch
  • A paid Claude plan. Two sessions burn roughly double.

A git worktree is a second folder of the same repository, checked out on its own branch. Two folders means two agents can edit at the same time and never see each other’s files. The merge afterwards is where you find out whether that was a good idea.

Two features in parallel, one deliberate conflict, and an answer to the only question that matters here: was it faster, or just twice as expensive?

Before you open a second terminal, look at the bill

Parallelism is not a speed setting. Anthropic’s January 2026 guidance puts a multi-agent setup at three to ten times the tokens of one agent for the same task, and says to exhaust single-agent options first. The earlier research-system post measured its own stack at about fifteen times the tokens of chat, and noted that most coding work has fewer genuinely parallel parts than research does.

3–10xtokens of one agent, same taskAnthropic, 23 Jan 2026 ↗
16parallel Claudes that built a C compilerAnthropic, 5 Feb 2026 ↗
~$20,000API cost of that two-week runAnthropic, 5 Feb 2026 ↗

That C compiler is the ceiling: sixteen instances in containers, roughly 2,000 sessions, about 100,000 lines of Rust. It worked because the test suite was near-perfect. Parallel agents without an automated check only multiply code nobody verified.

Anything sequential. Anything where both halves depend on one design decision. Anything a better prompt or a /clear would have fixed. Anything you cannot test automatically.

Two features that touch different files. A build plus a separate review with fresh eyes. Work you can test half at a time, in a browser, before the halves ever meet.

Six things that must be true first

Pre-flight0/6 done

Run both agents, then merge them

  1. Pick two features that do not share a decision

    For QAIRU Event Sign-up: a dark mode toggle, and a seats-left counter that disables the form when the event is full. One is presentation, one is logic. Neither needs to know what the other decided.

    Write both down as one sentence each first. If you cannot, they are not two tasks — they are one, and you should stay in a single session.

  2. Clear the deck

    In the main folder:

    bash
    git status
    git log --oneline

    Status must be clean. You are about to have three copies of this repo on disk; do not leave yourself guessing which one holds uncommitted work.

  3. Terminal A — start the first agent in its own worktree

    bash
    claude --worktree dark-mode

    That one flag does the whole setup: a new folder at .claude/worktrees/dark-mode/ on a new branch, worktree-dark-mode. You never run git worktree add yourself. Then give it a scoped prompt:

    Agent AClaude Code · worktree dark-mode
    Add a dark mode toggle to the sign-up page.
    
    Scope — you may edit ONLY these files:
      index.html, styles.css
    Do not touch CLAUDE.md, README.md, or anything under .github/.
    
    Requirements:
    - A visible toggle in the header.
    - The choice is remembered in localStorage and applied before first paint.
    - Form labels and the submit button stay readable in both themes.
    
    Follow CLAUDE.md. When it works, commit on this branch with a one-line message.
    Then stop and tell me what you changed, file by file.
  4. Terminal B — start the second agent from the same main folder

    Open a second terminal window in the same project folder. Do not open it inside the first worktree.

    bash
    claude --worktree seats-left
    Agent BClaude Code · worktree seats-left
    Add a seats-left counter to the sign-up page.
    
    Scope — you may edit ONLY these files:
      index.html, seats.js
    Do not touch styles.css, CLAUDE.md, or README.md.
    
    Requirements:
    - Show "N seats left" next to the form, read from one capacity constant.
    - When N reaches 0, disable the submit button and show a short "full" message.
    - All logic lives in seats.js. index.html gets one script tag and one container div.
    
    Follow CLAUDE.md. When it works, commit on this branch with a one-line message.
    Then stop and tell me what you changed, file by file.

    Notice what both prompts share: an explicit file list. That is the most useful line in this lab.

  5. Terminal C — watch from outside while they work

    bash
    git worktree list

    Three entries: your main checkout and the two worktrees. Open each worktree’s index.html in a browser and test the features separately, now, while the agents still run. This is the part that pays for itself — each half is tested before it meets the other.

    If your project has dependencies, run your install command inside each worktree. A worktree is a fresh checkout; node_modules does not travel.

  6. Review each branch with a context that did not write it

    After agent A commits, in Terminal A:

    Fresh-eyes reviewClaude Code · either worktree, after the commit
    Use a subagent to review this branch's diff against the main branch.
    Report only correctness problems and violations of CLAUDE.md — not style, not naming.
    For each finding give me: the file, what breaks, and the smallest fix.
    If you find nothing real, say so and stop.

    A subagent gets its own context window, so it is not attached to code it just wrote; the best-practices page recommends exactly this split. Fix what is real, ignore the rest, repeat in Terminal B.

  7. Exit both sessions and keep the worktrees

    Leave each session. A worktree with no changes is removed automatically on exit; one with commits asks whether to keep or remove it. Choose keep — you still need those branches.

  8. Merge the first branch

    Back in the main folder:

    bash
    git merge worktree-dark-mode

    This one lands clean: nothing on main has moved since the branch started.

  9. Merge the second branch and meet the conflict

    bash
    git merge worktree-seats-left

    Both agents edited index.html. When their edits land in the same region, git stops and leaves conflict markers in the file — the expected outcome here, not a mistake. Hand it to an agent in the main folder:

    Conflict resolutionClaude Code · main folder, mid-merge
    git merge left conflict markers in index.html.
    Resolve them so BOTH features survive: the dark mode toggle and the seats-left counter.
    Do not delete either feature to make the conflict go away.
    When the file is clean, show me the resolved section, then give me the exact steps
    to test both features in the browser before I commit the merge.

    Read the resolved section yourself before committing. An agent resolving a conflict is guessing at intent, and the cheapest way to lose a feature is to accept a resolution that quietly dropped half of it.

    If git merges both edits without complaining, you got lucky with line numbers. Open the page anyway and check that both features are still there — a clean merge is not a working page.

  10. Verify on main, then clean up

    Open the page from the main folder. Both features must work together: toggle the theme, and watch the seats counter still update.

    bash
    git worktree remove .claude/worktrees/dark-mode
    git worktree remove .claude/worktrees/seats-left
    git branch -d worktree-dark-mode worktree-seats-left
    git worktree list

    Remove the worktrees before deleting the branches — git refuses to delete a branch that is still checked out somewhere. The last command should show only your main checkout.

    Optional finish, from a normal shell:

    bash
    claude -p "Summarize what changed in the last 3 commits in 5 bullets" \
      --allowedTools "Bash(git log *),Bash(git diff *)" --output-format json

    Find result, session_id and total_cost_usd in the JSON. That last field is what this lab is really about. The --allowedTools line is not decoration: -p starts in Manual mode, so a command you have not allowed is denied outright, and the summary gets written without ever reading the log.

The conflict was the lesson, not the accident

Worktrees isolate files. They do not isolate decisions. Both agents wrote good code for index.html and still collided, because neither knew the other was rearranging the same header. Claude Code enforces the file half: inside a worktree session it blocks edits, commands and git redirects aimed at the main checkout. Nothing enforces the decision half. You do.

So the real skill is not typing --worktree. It is splitting work along file lines before anything starts:

  • One owner per file. Name the files in each prompt, as you did above.
  • Give the second agent its own file where you can. seats.js exists so that only one line of index.html has to change.
  • Never let two agents edit CLAUDE.md, the README or the config in the same run.
  • Merge the same day. Stale branches turn a small conflict into an afternoon.

When two agents is an expensive way to get one result

Cognition’s June 2025 argument against multi-agent systems holds where it matters: actions carry implicit decisions, and conflicting decisions produce bad results. Their example is two subagents building a game — one makes a Mario-style background, the other a bird that does not match it, and the lead agent is left merging two incompatible assumptions. Your index.html conflict, scaled up.

So skip the second agent when the work is sequential, when both halves share a decision, when a sharper prompt or a /clear would have done it, or when you have no automated check. The default that survives real work is modest: one agent, subagents for research, a fresh context to review.

Go deeperWhere the branch actually starts from, and how to bring your .env along

By default worktrees use worktree.baseRef: "fresh" — they branch from the remote default branch (origin/HEAD), falling back to local HEAD when there is no remote. To include unpushed work instead, set {"worktree": {"baseRef": "head"}} in your Claude Code settings.

A fresh checkout also carries no ignored files and no dependencies. List the ignored files you need — .env, for example — in a .worktreeinclude file using gitignore syntax, and they are copied into each new worktree. Dependencies you reinstall. Source: the worktrees docs.

Go deeperThe manual route, which works in any tool

--worktree is Claude Code’s wrapper around plain git, so the same isolation works with Cursor, Codex, Gemini CLI or a bare editor:

bash
git worktree add ../qairu-dark-mode -b dark-mode
git worktree list
git worktree remove ../qairu-dark-mode

Then cd into that folder and start whichever agent you like.

Go deeperBigger than two: /batch, agent teams and workflows

/batch followed by one instruction splits a large change across 5–30 worktree-isolated subagents, each opening its own pull request. Agent teams — a lead plus teammates sharing a task list — are experimental and off by default, and the docs say plainly that teammates are not worktree-isolated, so you partition files by hand; the costs page puts them at roughly seven times a standard session’s tokens when teammates run in plan mode. Dynamic workflows run up to 16 concurrent agents by default. Read the agents overview first — all three multiply the bill you just measured.

Quick check

Your two worktree sessions finish. Both agents edited index.html. You merge the first branch cleanly, then the second one conflicts. What does that tell you?

Take it with you · checklistThe parallel-run card

Pre-flight, the file-ownership rules that prevent most conflicts, the merge and cleanup commands in order, and the questions that send you back to a single session instead.

You are done when

Both features work together on your main branch, `git worktree list` shows only the main checkout, and you can explain out loud why the two agents never overwrote each other's files.