I had three ideas and three terminal windows open. The math looked obvious: spin up three Claude Code sessions, one per worktree, point each at an independent branch, and pull roughly 3x my throughput for the afternoon. The official docs tell you to do exactly this. The desktop app auto-creates a worktree for every new session, and it is framed as the safe pattern.
Eight hours later I had two corrupted memory files, one Skills file with a paragraph I never wrote, and a bill for about $47 of token spend re-doing work that already existed in another worktree. The setup was safe. The shared state was not.
This is the 8-hour log: what I set up, when the two collisions hit, what was actually getting overwritten, and the three small patterns I run now to keep parallel sessions from eating each other.
The setup that looked safe
Three Claude Code sessions, each on its own worktree of the same repo. Three branches: feat/voice-buffer, fix/og-emit, feat/citation-tracker. None of the branches touched the same source files. I had checked that twice before I started.
# Terminal A
git worktree add ../wt-voice-buffer feat/voice-buffer
cd ../wt-voice-buffer && claude
# Terminal B
git worktree add ../wt-og-emit fix/og-emit
cd ../wt-og-emit && claude
# Terminal C
git worktree add ../wt-citations feat/citation-tracker
cd ../wt-citations && claude
Each session got the same system context: my repo CLAUDE.md, my user-level ~/.claude/CLAUDE.md, my ~/.claude/skills/, and my ~/.claude/projects/<repo>/memory/ directory. The worktrees were independent at the git level. Everything else was shared.
I caught the implication at hour eight, with a corrupted memory file open in front of me. Worktrees isolate your source code. They do not isolate Claude's brain. The Anthropic docs are explicit that worktrees share project-level memory while keeping the conversation and plan separate, so this is documented behavior, not a bug. I just had not read closely enough.
Collision 1: hour 3:42, the Skills file
The first thing that snapped was a Skills file I had not touched all day.
Session A was building a voice-buffer fix and asked itself "is there a Skill for streaming WebRTC buffers?" There was not, so it wrote one and kept working. Around the same eight-minute window, Session C was building the citation tracker and asked itself "is there a Skill for parsing source attributions?" There was not, so it wrote one too.
So far, no conflict. Different files, different topics. The collision came from a third file, the Skills index, which both sessions updated when registering their new Skill. Session A wrote first. Session C, reading the file thirty seconds later, saw the version before Session A's write, appended its own Skill, and saved. The voice-buffer registration disappeared from the index. Session A had no idea, because Session A had already moved on.
I noticed at hour five when I asked Session B "does our Skills index include voice-buffer yet?" It said no. I checked. It was right. The Skill file was on disk, but the index that pointed to it had been clobbered. Two writers, last-write-wins, no warning, no merge.
Collision 2: hour 6:18, the memory file
The second collision was uglier because it ate work I cared about.
I use ~/.claude/projects/<repo>/memory/ to store small persistent notes the agent should remember across sessions: an architecture.md with my component map, a feedback.md with stylistic preferences, a project.md with current priorities. Claude writes these itself, when I say "remember this" or when it decides something is worth keeping.
At hour 6:18, Session A finished its voice-buffer work and asked itself "should I save what I learned about the audio buffer invariants?" It read architecture.md, added a section, and saved. At hour 6:19, Session B finished the OG fix and asked itself "should I record the og:type double-emit bug as a known gotcha?" It read architecture.md (the pre-A version, still cached in its context), added its own section, and saved.
Session A's voice-buffer notes vanished. Eight minutes of careful invariants, gone, replaced by a paragraph about meta tag emission that was correct but unrelated.
I only caught this because I happened to grep for "buffer invariant" the next morning and found nothing. If I had not gone looking, the notes would simply not exist in any future session. There is no error log for "memory file silently overwritten by sibling process."
What was actually broken
Worktrees solve the file-system problem. Two sessions writing to src/voice/buffer.ts would have produced a git conflict, which is loud and recoverable. Two sessions writing to the same Skills index produce a silent overwrite, which is quiet and not.
Three classes of file are at risk, in roughly increasing order of how much they hurt:
-
Settings files (
~/.claude/settings.json). Rare, because the agent rarely writes here. But when it does, you get last-write-wins. -
Skills files (
~/.claude/skills/). Medium frequency. Indices and shared catalogues are the flashpoint, not the individual SKILL.md files. -
Memory files (
~/.claude/projects/<repo>/memory/). The most painful. The agent writes here exactly when it has just learned something worth keeping, which is exactly the work you do not want to lose.
This squares with what the 2026 worktree guides now say out loud: all worktrees of a project share the same auto-memory directory, so what Claude learns in one worktree carries into the others. Most write-ups frame that as a feature. Run three sessions at once and it is also the shared mutable state nobody is locking.
Anthropic's parallel-worktree pattern was designed for code. The harness was designed for one session at a time. Running both at once is the user's bug.
The $47 lesson
The cash cost was the rework. After the memory collision, Session A had no record of the voice-buffer invariants it had just figured out. The next morning I started a fresh session, asked it to extend the buffer, and it re-derived the same invariants from scratch in about 40 minutes of token spend. I checked the dashboard: roughly $47 of Sonnet tokens, plus a grumpier morning.
I had paid for the original derivation too, so it was double-billed, not lost. But the second payment was the avoidable one.
The 3 patterns I run now
After the collision day I changed three things. Each is small. None of them needed Anthropic to ship anything.
Pattern 1: per-session memory namespaces. Instead of one shared memory directory, each session writes into a per-branch subdirectory. I point the agent there with a per-worktree CLAUDE.md. At session end I merge the subdirectory back by hand or with a small script. Conflicts surface as duplicate filenames, which is loud and recoverable.
<!-- per-worktree CLAUDE.md -->
## Memory write location
Write all memory files under
`~/.claude/projects/repo/memory/feat-voice-buffer/`.
Do not write to `~/.claude/projects/repo/memory/` directly.
Pattern 2: a write lock on shared indices. For files I cannot namespace (the Skills index, settings.json), I run agent writes through a flock wrapper that takes an exclusive lock before touching the file. Last-write still wins, but the writes are serialized and the pre-write read sees consistent state. The wrapper is about twenty lines of shell.
#!/usr/bin/env bash
# ~/.claude/bin/locked-write.sh
target="$1"
lockfile="$HOME/.claude/locks/$(basename "$target").lock"
mkdir -p "$(dirname "$lockfile")"
exec 9>"$lockfile"
flock 9
cat > "$target"
Pattern 3: coordination via heartbeat files. Each session writes a heartbeat at ~/.claude/sessions/<pid>.json with its branch and the harness files it expects to touch. Before writing a shared index, a session greps that directory for sibling claims on the same path and waits or skips. This is the heaviest of the three, and the one I use least, because Patterns 1 and 2 catch most of the real collisions.
If you have used Claude Code sub-agents for parallel review, you will recognize the shape: the problem is not the model, it is the integration layer you did not realize was there. Sub-agents collide on opinions inside one session; parallel sessions collide on state across the harness. (I wrote up the sub-agent version of this in an earlier post on three sub-agents reviewing the same PR.)
What I believe now
Parallel Claude Code sessions are not free. The cost moves around, but it never hits zero, the same way letting one agent run autonomously for 24 hours is not free. With parallel sessions it shows up as silent overwrites in your harness directory, eight hours in, in a file you did not think about when you opened the second terminal.
The official framing is right at the source-code layer: edits in one session never touch files in another. It just stops one directory short. Edits inside ~/.claude/ are perfectly happy to touch each other, and they will, on the schedule of last-write-wins, with no error log to grep later.
One thing to take from this: when you open the second session in a second worktree, spend ten seconds deciding whether the two sessions share Skills, memory, or settings, and whether you mind if either silently eats the other's writes. If you do mind, add Pattern 1 today and Pattern 2 the first time you hit a collision. The current guides put 4 to 8 concurrent worktrees per developer as the reliable ceiling before you are bottlenecked on review anyway. Pattern 3 can wait until you are near that ceiling.
I am still running parallel sessions. I just stopped pretending the worktree boundary was the whole boundary.
Want the deeper version of this? I cover the harness layer, the modules of a Claude Code setup, and the failure modes of shared state in Claude Code Mastery, the field guide for engineers who want to run Claude Code seriously, not just open three terminals.


Top comments (0)