The first time you run two Claude Code sessions in the same checkout, it goes like this: session A is refactoring the parser while session B fixes a bug in the formatter, and twenty minutes in, A reads a file B just rewrote, builds on a function that no longer exists, and both sessions start "fixing" each other's work. You did not get two agents' worth of progress. You got a merge conflict with extra steps, authored in real time by two processes that each believed they owned the tree.
The isolation primitive
The failure above is not an agent problem, it is a filesystem problem: two writers, one working directory. Git already has the fix. A worktree is a separate working directory with its own files and its own branch, sharing the same repository history and remotes as your main checkout. Two sessions in two worktrees can both edit, build, and run tests, and neither can touch the other's files by construction.
Claude Code has this built in. As of July 2026:
claude --worktree feature-auth # or -w feature-authcreates a worktree under .claude/worktrees/feature-auth/ at your repo root, on a new branch named worktree-feature-auth, and starts the session inside it. Run the same command with a different name in a second terminal and you have two fully isolated sessions. Omit the name and Claude generates one. You can also just ask mid-session ("do this in a worktree") and Claude creates one itself with its EnterWorktree tool.
Two mechanics save real pain:
- Gitignored files do not follow you. A fresh worktree has no
.env, nonode_modules, none of your local config, because none of that is in git. A.worktreeincludefile at the repo root lists gitignored paths (like.envand.env.local) that should be copied into each new worktree. Set this up once or watch every parallel session fail its firstnpm run dev. - Branching starts from the default branch. New worktrees branch from your repo's default branch unless you set
worktree.baseRefto"head", so a worktree started while you sit on a feature branch does not silently inherit that branch's changes.
Worktrees compose with 2.5's subagents: add isolation: worktree to a custom subagent's frontmatter (or ask Claude to "use worktrees for your agents") and each subagent edits in its own temporary worktree instead of your live tree. Cleanup is asymmetric and worth knowing: worktrees Claude created for subagents and background work are swept automatically once they are older than your cleanupPeriodDays setting and fully clean (no uncommitted changes, no unpushed commits), but worktrees you created with --worktree are never auto-removed. Periodically run git worktree list and remove what you have abandoned.
Sessions vs worktrees, since the terms blur: a session isolates conversation (context, history); a worktree isolates files. Two sessions in one directory share a filesystem and will collide on writes. One session moving between worktrees shares its context across both. Parallel edits need both isolations at once, which is exactly what --worktree per terminal gives you.
The patterns that work
Implementer + reviewer. One instance builds the feature in a worktree. A second instance, in the main checkout or its own worktree, reviews the diff cold: no shared conversation, no knowledge of the implementer's reasoning, just the code. This split attacks the 0.1 problem directly, the agent grading its own homework. A reviewer that shares the implementer's context shares its misunderstandings; a reviewer that reads only the diff has to reconstruct intent from the code, which is precisely what your teammates will do, and it surfaces the same confusions they would hit. This is the lab below, and Part 3 turns it into standing infrastructure.
N approaches, pick one. For a genuinely uncertain design (two plausible schemas, three ways to structure a migration), dispatch the same spec to two or three worktrees, let each build its version, then diff the results and keep the winner. It feels decadent; it is often cheaper than one agent thrashing between approaches mid-context, because each instance commits to a lane, and you judge artifacts instead of arguments. Delete the losers without ceremony: worktrees make abandonment free, which is half their value.
Background long-runner. A big mechanical task (a rename across 300 files, a dependency migration) runs in its own worktree while you keep working interactively in the main checkout. The worktree contains the blast radius; you check in on it at your pace, not its pace.
Where it breaks
Parallelism's cost curve is the part nobody advertises. Every instance you add is another diff you must review, another context you must steer, another set of permission prompts arriving on their own schedule. Two instances, cleanly split between implementation and review, is a genuine multiplier. Three is workable when one is a low-attention long-runner. Past that, the math flips: you become a context-switching bottleneck rotating between agents that are each idle waiting for your judgment, and review quality, the thing this whole course optimizes, degrades exactly when volume rises. The position: more than three parallel instances usually returns negative for a single operator, and two well-split instances beat five chaotic ones every time. The constraint is not compute, it is your attention; scale within it. (What does scale further is removing yourself from the loop per-instance, which is what headless pipelines from 2.9 and the harness discipline of Part 3 are for.)
The other classic failure is parallelizing coupled work. Two worktrees editing the same module do not conflict on disk, but they still conflict at merge, and now the conflict is between two large agent-authored diffs nobody fully remembers. Isolation is not decoupling. Split work along module boundaries, not task-list boundaries, and when two tasks keep touching the same files, that is the codebase telling you they are one task.
Five sessions, one checkout. Sessions overwrite each other's edits; one runs the dev server while another switches branches under it. By evening there are 4,000 unreviewed lines across intertwined diffs, and you cannot say which session broke the build.
Two worktrees with a .worktreeinclude copying .env. Implementer builds in one; reviewer reads the diff cold in the other and files findings. You merge one reviewed branch, delete both worktrees, and can name every change that landed.
Lablab-2-10Implementer and reviewer, isolated
Goal: Run a two-instance implementer/reviewer split across worktrees and merge only what the cold review passes.
Prereqs: the agentic-practice repo with a test suite from earlier labs; two terminals.
- At the repo root, create
.worktreeincludelisting any gitignored files your build needs (at minimum.envif the repo has one). Commit it. - Terminal 1:
claude --worktree implementer. Dispatch a small real feature with scope and verification stated (for example: "Add an--only <unit>flag to the CLI that filters conversions. Scope: src/cli.ts and its tests. Done when the full test suite passes."). Let it work to a commit on itsworktree-implementerbranch. - Terminal 2, from the main checkout: start a plain
claudesession as the reviewer. Give it only the diff: "Rungit diff main...worktree-implementerand review the changes cold. You did not write this. Look for correctness bugs, weakened or missing tests, and scope creep. Verdict plus findings, with file and line references." - Make the reviewer's findings concrete: for each finding, decide accept or reject yourself, then send accepted items back to the implementer session as a fix-up dispatch. Re-review the delta.
- When the review passes, merge the branch from the main checkout, run the test suite one final time yourself, then clean up:
git worktree list, remove the implementer worktree, delete the branch.
Verify
git worktree listshowed at least two entries during the lab (main checkout plusimplementer), and shows only the main checkout after cleanup.- The reviewer session produced at least one concrete finding with a file reference, and you can point to the commit where an accepted finding was fixed.
- The merged branch passes the full test suite in the main checkout, run by you, after merge.
>Troubleshooting
- Implementer's build fails immediately on missing env or deps: gitignored files did not follow into the worktree. Add them to
.worktreeinclude(env files) and run the package install inside the worktree (dependency directories are not copied; installing per-worktree is normal). - Reviewer sees an empty diff: check the branch name with
git branch --list "worktree-*"and confirm the implementer actually committed; uncommitted changes in a worktree are invisible togit difffrom the main checkout. - Worktree creation fails with a trust prompt error: run
claudeonce in the repo root interactively and accept the workspace trust dialog, then retry--worktree.
Knowledge check
Knowledge check
Sources
- Run parallel sessions with worktrees (--worktree flag, default locations and branch names, .worktreeinclude, base branch, subagent isolation, cleanup rules): https://code.claude.com/docs/en/worktrees (fetched July 2026)
- Common workflows: run parallel sessions with worktrees: https://code.claude.com/docs/en/common-workflows (fetched July 2026)