On Wednesday at 11:40am, four Claude Code sessions were running in four terminal tabs, each in its own git worktree, and all four of them were fighting over port 3000.
Agent 2 would start the Next.js dev server. Agent 4 would see "port in use", decide the old process was stale, and kill it. Agent 2 would then report that its Playwright check "failed due to a connection refused error, likely a flaky environment" and try again. They did this to each other for about 20 minutes before I noticed.
That was day 3 of a one-week experiment: run Claude Code in parallel git worktrees on a real side project and see if four agents really means four times the output. It doesn't. Here's what it actually means, with the numbers.
TL;DR
- Running Claude Code in 4 git worktrees for 5 working days, I queued 23 tasks. 17 shipped, 4 needed heavy rework, 2 got thrown away.
- 9 of the 23 branches collided with another agent's work: 5 textual merge conflicts, 4 clean merges that broke
mainor staging anyway. - My throughput went from 11 shipped tasks the week before (one agent, sequential) to 17. That's 1.5x, not 4x.
- The bottleneck moved from the agent to me. I spent 6.5 hours reviewing diffs, more than any single agent spent working.
- What fixed most of it: per-worktree ports, one "migrations lane", file-ownership rules per task, and capping at 3 agents.
What was the setup?
The setup was one monorepo, four worktrees, four independent Claude Code sessions, and me as the merge queue. The project is a small SaaS I run on the side: a Next.js frontend, a FastAPI backend, Postgres with Alembic migrations, and Redis for caching.
Creating the worktrees is the easy part:
git worktree add ../app-wt1 -b feat/billing-export
git worktree add ../app-wt2 -b feat/team-invites
git worktree add ../app-wt3 -b fix/search-pagination
git worktree add ../app-wt4 -b feat/audit-log
Then cd into each one, run claude, and hand it a task from a list. Each worktree shares the same .git object store, so there's no re-cloning, but each has its own checked-out files, its own branch, and (as I learned) its own need for node_modules.
My rule for the week: every task gets a branch, every branch goes through CI, and I merge to main myself. No agent touches main.
How many tasks actually shipped?
Out of 23 tasks, 17 shipped with light edits, 4 needed heavy rework, and 2 were deleted. For comparison, the previous week I used a single Claude Code session sequentially and shipped 11 tasks.
| Outcome | Count |
|---|---|
| Merged clean, shipped | 12 |
| Merge conflict, resolved quickly, shipped | 5 |
| Heavy rework (I rewrote 30%+ of the diff) | 4 |
| Thrown away | 2 |
The 2 throwaways were both cases where the agent solved the task in a way that made another in-flight branch pointless. Agent 3 refactored the search query builder "while it was in there", which invalidated the approach Agent 1 was halfway through for billing export filters. Neither agent knew the other existed. Why would they?
Why do parallel Claude Code agents collide?
Parallel Claude Code agents collide because git worktrees isolate files, not shared resources or intent. Each agent sees a clean, consistent repo and makes locally correct decisions. The collisions happen at everything the worktrees don't isolate: ports, databases, lockfiles, shared utilities, and naming conventions.
Here are the 9 collisions, grouped by what caused them.
1. Lockfile conflicts (4 of 9)
Three agents added npm dependencies and one bumped a Python package. package-lock.json conflicts are textually huge and semantically boring. I resolved all four by taking main's lockfile and re-running npm install on the branch. Annoying, about 10 minutes each, never dangerous.
2. Duplicate Alembic migrations (2 of 9)
This one is nasty. Agent 2 (team invites) and Agent 4 (audit log) both needed a schema change. Both ran alembic revision --autogenerate from the same parent revision. Both branches merged without a single git conflict, because the migration files had different random revision IDs and different filenames.
Then CI on main ran alembic upgrade head and got this:
Multiple head revisions are present for given argument 'head'
Two heads. Fixable with alembic merge heads, but the first time it happened, it happened on main, and my deploy was blocked until I fixed it. The second time I caught it on the branch because I'd added alembic heads to CI with a check that the output is exactly one line.
3. Route index conflict (1 of 9)
Two agents registered new API routers by appending a line to the same routers/__init__.py. Classic adjacent-line conflict. Two minutes to fix.
4. The two that git couldn't see (2 of 9)
These are the ones that scared me, because both merged clean and both passed CI.
The rename. Agent 1 renamed formatPrice() to formatCurrency() across the frontend and updated all 14 call sites that existed on its branch. Meanwhile Agent 4 added 3 new call sites to formatPrice(). Git merged it happily. TypeScript caught it on main. Fine, that's what a typechecker is for, but main was red for 25 minutes.
The cache key. This one reached staging. Agent 2 cached team membership under user:{id}. Agent 4 cached audit-log summaries under user:{id}. Different modules, different files, zero textual overlap, unit tests all green because each test suite mocked Redis on its own. On staging, the invite page tried to parse an audit summary as a membership list and threw a 500.
No merge tool would have caught this. The only defense is a convention (I now namespace keys by module: teams:user:{id}) written somewhere every agent reads.
What about the environment problems?
Environment problems cost more wall-clock time than merge conflicts did. Git worktrees give you a fresh checkout, and a fresh checkout is missing everything your .gitignore hides.
- Ports. All four dev servers defaulted to 3000 and the API to 8000. Agents killed each other's processes and blamed "flakiness". The fix was a tiny script I run when creating a worktree:
# wt-init.sh <n>
n=$1
echo "PORT=$((3000 + n))" >> .env.local
echo "API_PORT=$((8000 + n))" >> .env.local
echo "DATABASE_URL=postgresql://localhost/app_wt$n" >> .env.local
createdb "app_wt$n" 2>/dev/null
npm install --silent
-
One database. Before I added per-worktree databases, Agent 3 ran a test fixture that truncated the
userstable while Agent 2 was manually testing invites. Agent 2 spent a while "debugging" why its freshly created user vanished. -
Disk. Each worktree's
node_modulescame out to about 1.1GB. Four of them plus build caches ate roughly 6GB. Not a crisis, but I didn't expect it.
What did it cost?
I'm on a flat subscription plan, so the dollar cost was fixed, but the usage limit was not. Four concurrent sessions hit my usage limit on day 3 at 2:40pm, and I lost the rest of that afternoon. On days 4 and 5, with three agents instead of four, I didn't hit it.
The bigger cost was my attention. I logged my review time: 6.5 hours across the week, over 23 diffs with a median size of 214 changed lines. The week before, with one agent, review took about 3 hours for 11 tasks. Per task it's similar. The problem is the arrival pattern: four branches landing within the same hour means context switching across four unrelated features, and that's where I made mistakes. The cache key bug went past me in review. I read that diff.
Is running multiple Claude Code agents in parallel worth it?
Yes, but at 3 agents with strict lanes, not 4 agents on a shared codebase free-for-all. The speedup is real (1.5x in shipped tasks for me) but it's capped by human review and by how independent your tasks really are.
Here's what I changed for week two:
- Cap at 3 agents. Four exceeded both my usage limit and my review capacity.
- One migrations lane. Only one worktree at a time is allowed to create an Alembic revision. Every other task prompt says: "Do not create migrations. If you need a schema change, stop and tell me."
-
File ownership in the prompt. Each task lists directories the agent may edit. "You may modify
app/billing/andweb/app/billing/. Anything else, ask first." Claude Code mostly respects this, and when it doesn't, the diff makes it obvious. -
No opportunistic refactors. A line in
CLAUDE.md: "Do not rename or refactor shared utilities unless the task says to." This alone would have prevented both the rename break and one of the throwaways. -
Rebase before review. Each agent runs
git fetch && git rebase origin/mainand re-runs tests before telling me it's done. Conflicts get resolved by the agent that has the context, not by me. - Conventions file. Cache key namespacing, route registration, env var naming. Written down once, read by every session.
Week two isn't over, but after three days: 11 tasks shipped, 1 collision (a lockfile), zero red main builds.
The short answer
Running Claude Code in parallel git worktrees does not multiply your output by the number of agents. In my week with 4 agents on a real monorepo, 23 tasks produced 17 shipped features (1.5x my single-agent week), 9 branches collided, and 4 of those collisions merged clean in git while breaking the build or behavior. Worktrees isolate files, not ports, databases, migrations, shared names, or intent, so the gains come from partitioning work so agents never touch the same resources, and from keeping the agent count at or below what one human can actually review.
Written by the developer behind Preterview, an interview prep platform.
Top comments (0)