Three parallel Claude Code sessions can ship three branches in an afternoon. They can also ship three branches that each pass their own tests, then break each other on merge. The difference is not the tooling. It is how you split the work.
We start with Claude Code git worktrees as native tooling: the --worktree flag, baseRef, .worktreeinclude, and cleanup semantics. Then we cover what the docs leave out: ownership boundaries, the work that serializes anyway, the merge runbook, and when to stay in one session.
What you’ll learn
- Drive the native worktree tooling:
--worktree,baseRef, PR worktrees, and.worktreeinclude - Split work by ownership boundary and freeze shared contracts before dispatching agents
- Identify hotspot files, dependent interfaces, and shared infrastructure that serialize work anyway
- Merge parallel branches in dependency order and validate the integrated result
- Apply a decision rule for when one focused session beats three parallel ones
Prerequisites
- A current Claude Code release; features such as
baseRefand PR worktrees landed well after the original--worktreeflag, so update first - Daily working fluency with Claude Code sessions, plan mode, and CLAUDE.md
- Comfort with git branching and merges, plus the
ghCLI for the merge workflow - A project whose tests can run per package or directory
What Claude Code git worktrees actually solve
A git worktree is a second checkout of the same repository in a separate directory, on its own branch. That one property is the entire value proposition. Two Claude Code sessions in two worktrees can never edit the same file on disk.
The official docs draw this line explicitly: worktrees give each session a separate checkout so parallel sessions never edit the same files. They are meant for sessions you run yourself. Coordination is a different job, handled by subagents, agent view, agent teams, or scripted workflows.
Everything else stays your job. Worktrees do not split the work, coordinate agents, isolate your dev database, or review the resulting branches. Treat them as file isolation and nothing more — the rest of this article is about the parts you still own.
The native tooling in 2026
You no longer need to hand-roll git worktree add. Start an isolated session directly:
claude --worktree feature-payments # terminal 1: feature work
claude --worktree bugfix-session-expiry # terminal 2: same repo
claude -w # no name: Claude generates one, e.g. bright-running-fox
Each command creates a worktree at .claude/worktrees/<name>/ on a new branch named worktree-<name>, and scopes the session to that directory. Mid-session, you can also ask Claude to “work in a worktree” — it calls the EnterWorktree tool — or have it switch into an existing worktree under .claude/worktrees/.
Two setup details matter before you run this in earnest. Add .claude/worktrees/ to .gitignore, or every worktree shows up as untracked noise in your main checkout. And interactive --worktree requires an accepted workspace trust dialog, so run plain claude in the repo once first (claude -p --worktree skips the trust check).
Choosing the base ref
Worktrees branch from origin/HEAD by default — a clean tree matching the remote. For parallel work that is usually correct: every agent starts from the same known-good base. When agents must build on unpushed local work, switch the base:
{
"worktree": {
"baseRef": "head"
}
}
Only "fresh" (the default) and "head" are accepted — you cannot point at arbitrary refs. You can also branch a worktree straight off a pull request: claude --worktree "#1234" fetches that PR’s head commit from origin (pull/1234/head on GitHub) into .claude/worktrees/pr-1234, which is useful for extending a teammate’s branch in isolation.
A fresh checkout is a bare checkout
A new worktree has none of your gitignored files: no .env, no .env.local, no local certs. The fix is a .worktreeinclude file at the project root, using .gitignore syntax:
.env
.env.local
config/local-secrets.json
Only files that match a pattern and are also gitignored get copied; tracked files never duplicate. On non-git VCS setups, WorktreeCreate/WorktreeRemove hooks replace the git logic entirely. .worktreeinclude is not processed when a WorktreeCreate hook runs, so the hook script must copy config files itself.
Dependencies are your problem too. Three worktrees means three npm installs and three dev servers on three ports. Each fresh session also re-explores the codebase from scratch, a repeated cost that context budgeting exists to make visible.
Cleanup is state-dependent. Exit an unnamed session with a clean worktree and Claude removes the worktree and branch automatically; a named session asks first. With uncommitted changes or new commits, it prompts you to keep or remove. Non-interactive runs (claude -p --worktree) are never auto-cleaned — git worktree remove is on you, which matters when you fan out headless sessions in CI.
Manual git worktree add ../repo-auth existing-branch still works and still matters for existing branches or custom locations. Nothing in the discipline below requires the native flag.
Split by ownership, not by feature
The failure pattern is always the same: work split by feature label. “Agent 1 does auth, Agent 2 does users” sounds parallel, but both features touch the session model, the API client, and the routes file. Ownership boundaries are directories, layers, or test surfaces — things you can point at in the filesystem.
Agent 1: build the authentication feature Agent 2: build the user management feature
Agent 1 owns src/api/auth/ — tests: npm test -- auth Agent 2 owns src/session/ — tests: npm test -- session Shared contract: src/types/api.ts, frozen before dispatch
The second rule: scaffold shared contracts sequentially, before dispatching anyone. API schemas, TypeScript interfaces, and migration designs get written first, in one session. Skip this and each agent invents its own assumptions.
The documented failure case is a fintech feature where both agents’ tests passed locally, yet the merged system shipped stale tokens. Nobody had validated the login response shape end to end. Freezing interfaces up front is spec-first prompting applied to multiple agents at once.
Run the plan as a gate. In your main session, in plan mode:
❯ Propose a parallelization plan for [feature]. Rules: each work package must map to an owned directory, layer, or test surface — not abstract ideas. Do not edit files. Output: module list, shared contracts, agent split, ownership mapping, test command per agent, merge order, risks.
You want back a module list, the contracts to scaffold first, two or three work packages mapped to owned paths, a test command per package, and a dependency-ordered merge sequence. This is a plan worth approving in the strictest sense: it is a go/no-go decision, not a to-do list.
If the plan cannot produce non-overlapping ownership, that is your answer: serialize. Do not negotiate with the boundaries. A split that needs caveats is a merge conflict with extra steps.
Start with two or three agents, not five. Practitioner consensus caps parallelism at your review capacity, and more agents multiply token usage, review burden, and integration risk.
One production team enforces the pattern as a CLAUDE.md rule: “All feature work MUST happen in git worktrees. Never make code changes directly in the repo root or on the main branch.” That is CLAUDE.md as a contract — a hard rule agents must obey, not documentation they might read.
What serializes anyway
Worktrees only isolate files. Three categories of work stay serial no matter how many checkouts you create.
Hotspot files. Routes files, dependency manifests (package.json, Cargo.toml), registries, and barrel exports get touched by every branch. Isolated checkouts just defer the collision to merge time. They also add a subtler cost: duplicated features and logic that compiles but disagrees at runtime.
Monorepos concentrate this problem, since shared manifests and generated files sit on every path. Scoping Claude Code in monorepos covers mapping ownership onto package boundaries.
Dependent interfaces. If the frontend agent needs endpoint signatures the backend agent is still writing, isolation does not help. Either freeze the contract first or sequence the tasks. “Agent B waits on Agent A” is serial work with parallel overhead.
Shared runtime infrastructure.
Worktrees do not isolate the dev database, ports, or caches. Two agents running migrations and seeding test data against one Postgres instance interfere constantly, and the failures look like model mistakes rather than environment collisions. Give each worktree its own database (or schema) and port range, or accept that integration-level testing is serial.
Add cross-cutting refactors to the serial list. When a change touches every layer, conflict-resolution time routinely exceeds the sequential cost. Keep worktrees short-lived either way: rebase onto main after each checkpoint so branches never drift into a week of divergence.
Merge in dependency order, then validate
Review and merge is the actual bottleneck. Every parallel branch is a diff someone has to read, and three rubber-stamped branches are worse than one properly reviewed one. The discipline in reviewing AI diffs without rubber-stamping applies three times, not once.
- 01
Run each branch's own tests before any merge
Each work package shipped with its own test command in the plan. Run it per worktree. These are the verification loops each agent iterated against, and they must be green before a branch becomes a merge candidate.
- 02
Merge in dependency order, not completion order
Contracts first, then backend, then frontend, then tests and docs. The branch that finished first is irrelevant. The branch others depend on goes first.
- 03
Run the full suite after every single merge
Not once at the end. Running the suite after each merge means a failure attributes to exactly one branch. A red suite after merge three implicates branch three, not the whole batch.
- 04
Run an integrated validation pass with fresh context
Per-branch tests cannot see contract drift or duplicated logic. Use a fresh session for this pass — the official docs note that a fresh context reviews better because Claude is not biased toward code it just wrote.
For the merge itself, hand coordination to a fresh session on the main checkout. This prompt comes from the same production engineering team running the pattern daily:
❯ Inspect both PRs using the gh cli and find the optimal order to merge them. Fix any merge conflicts that might appear.
Then run the integrated validation in the same session:
❯ Both PRs are merged to main. Run typecheck, lint, and the full test suite. Then check: are the shared contracts in src/types/api.ts used consistently by both the auth and session code? Flag any duplicated logic where the two branches solved the same sub-problem differently.
Conflicts do happen — the same team is blunt about it: “It does. Thankfully Claude is quite good at handling them.” The integrated pass is what catches the contract drift that per-branch tests miss. If your branches land as PRs rather than direct merges, babysit each one to green before starting the dependency-order sequence.
When one focused session wins
Parallelize only when all four conditions hold:
- Tasks are file-independent, with non-overlapping ownership
- Tasks are interface-independent, or the shared contract is frozen first
- Each task is verifiable with its own test command
- The branch count is within your review capacity
Serialize when any of these is true instead:
- The task is one deep problem — you cannot split a debugging session three ways
- Tasks share hotspot files or a dev database
- Downstream work needs upstream signatures as they evolve
- The change is a cross-cutting refactor
- You cannot give N diffs a real review
Parallelism is not free in tokens either. N sessions cost roughly N times the usage, and every fresh worktree re-pays the exploration cost your main session already paid. Every collision or drifted contract also comes back as correction tax, paid across N branches at once.
The better first use of a second session is often Writer/Reviewer: Session A writes the code, Session B reviews the diff with fresh context, A addresses the feedback. That is parallel sessions for quality, not throughput, and it carries none of the merge risk.
For the scripted end of the spectrum, give a subagent permanent worktree isolation:
---
name: migration-worker
description: Applies a scoped code migration in an isolated worktree
isolation: worktree
---
Each invocation gets a temporary worktree under the same baseRef rules, auto-removed if the subagent finishes without changes. Combined with subagents as context firewalls, you get file isolation and context isolation in one move. The bundled /batch skill packages the whole pattern: it splits one large change into 5-30 worktree-isolated subagents that each open a PR.
Treat all of this as a rung on the escalation ladder, not a default. One session, then Writer/Reviewer, then two or three owned worktrees, then scripted fan-out. Each step has to earn its overhead, or you step back down.
On a team, the ownership map is the part to standardize. Once every engineer can fan out three sessions, the bottleneck moves to shared hotspot files and to reviewers facing three branches at once. Agreeing on ownership boundaries, a shared .worktreeinclude, and a merge-order convention up front is the kind of team practice we set up in Enable.
Next steps
- Plan mode: get plans worth approving — the parallelization plan is a plan-mode artifact; make it a real gate.
- Reviewing AI diffs without rubber-stamping — review capacity is the true cap on how many agents you run.
- Verification loops for agentic code — per-worktree test commands are the loop each agent runs against.
External references: the official worktrees documentation for complete flag and cleanup semantics, and the parallel agents comparison for choosing between worktrees, subagents, and agent teams.