Worktree Isolation
Use git worktree per task for complete code isolation with event streams.
What You’ll Learn
When two agents edit the same file at the same time, one of them loses. Their changes get overwritten, or both sets merge into an incoherent mess. Worktree isolation eliminates this by giving each agent its own complete working directory.
By the end, you’ll understand:
- Why shared working directories break multi-agent workflows
- How git worktree provides per-agent isolation
- The worktree lifecycle: create, work, merge or discard
- Event streams for monitoring worktree activity
- Automatic cleanup of unused worktrees
The Problem
Two agents working in parallel on the same repository:
AGENT A: Adding authentication AGENT B: Adding logging
Creates src/middleware/auth.ts Creates src/middleware/logger.ts
Modifies src/app.ts ←──── CONFLICT ────→ Modifies src/app.ts
Modifies src/routes/index.ts Modifies src/config.ts
Both modify src/app.ts. Without isolation, three outcomes are possible:
1. LAST WRITE WINS
Agent A writes app.ts with auth import
Agent B writes app.ts with logger import → auth import lost
2. READ-BEFORE-WRITE RACE
Both read the same version of app.ts
Both write based on that version → second write overwrites the first
3. MERGE CONFLICT
Both stage changes → git conflict markers → manual resolution needed
None are acceptable. The root cause: multiple agents sharing a single working directory.
How It Works
Git Worktree: One Repo, Multiple Directories
Git worktree creates additional working directories from the same repository. Each has its own branch and files, but they share git history.
MAIN REPOSITORY WORKTREE: AGENT A
/project/ /project/.worktrees/agent-a/
├── .git/ ◀── shared ──▶ (branch: feat/auth)
├── src/ ├── src/ ← independent copy
├── tests/ ├── tests/
└── package.json └── package.json
WORKTREE: AGENT B
/project/.worktrees/agent-b/
(branch: feat/logging)
├── src/ ← independent copy
├── tests/
└── package.json
Agent A and Agent B can both modify src/app.ts — they each have their own copy on their own branch.
Spawning Agents with Worktree Isolation
When the parent spawns a child with isolation, the sequence is:
Parent Agent
│
├──▶ 1. CREATE git worktree add .worktrees/task-42 -b task-42
│ → new directory + branch created (fast, uses hardlinks)
│
├──▶ 2. SET CWD Child agent works in .worktrees/task-42/
│ Agent sees a normal project — doesn't know it's a worktree
│
├──▶ 3. WORK Child reads, writes, tests — all local to worktree
│ No impact on main directory or other worktrees
│
├──▶ 4. COMPLETE Child commits to branch task-42
│ Returns: { worktree_path, branch, files_changed }
│
└──▶ 5. DECIDE Parent merges branch → or discards worktree
The child agent needs no special awareness. From its perspective, it works in a normal directory. Isolation is invisible to the worker.
The Full Lifecycle
┌─────────────────────────────────────────────────────┐
│ CREATE │
│ git worktree add <path> -b <branch> │
│ Fast: hardlinks, not full copy │
│ │ │
│ ▼ │
│ WORK │
│ Agent operates in worktree directory │
│ All reads/writes isolated. Can run tests locally. │
│ │ │
│ ▼ │
│ EVALUATE │
│ git diff --stat → changes exist? │
│ ┌──────┴──────┐ │
│ ▼ ▼ │
│ MERGE DISCARD │
│ Merge branch Remove worktree │
│ into main Delete branch │
│ └──────┬──────┘ │
│ ▼ │
│ CLEANUP │
│ git worktree prune │
│ Remove directory, clean git references │
└─────────────────────────────────────────────────────┘
Event Streams: Monitoring Activity
The parent monitors worktree activity through events, without breaking isolation:
Parent Agent (orchestrator)
│
├── AGENT A (worktree: feat/auth)
│ ├── event: file_created src/middleware/auth.ts
│ ├── event: file_modified src/app.ts
│ ├── event: test_run 3 passed, 0 failed
│ └── event: task_complete files_changed: 3
│
├── AGENT B (worktree: feat/logging)
│ ├── event: file_created src/middleware/logger.ts
│ ├── event: file_modified src/app.ts
│ └── event: task_complete files_changed: 3
│
└── MERGE DECISION
Both modified src/app.ts on different branches.
Git merge handles it if changes are on different lines.
If conflict: parent resolves with full context of both tasks.
Events flow child-to-parent only. The parent observes without interfering — modifying a worktree while the child works would break consistency.
Automatic Cleanup
Worktrees with no changes are cleaned up automatically:
1. Worktree created for exploration task
2. Agent reads 20 files, concludes "no changes needed"
3. git diff --stat → empty
4. Automatic: git worktree remove + git branch -d
5. No branch, no directory, no mess
This prevents worktree accumulation over long sessions with many parallel agents.
Key Insight
Worktree isolation is what makes true parallel development possible. It is the same concept as feature branches, but applied at the agent level.
The deeper insight: worktrees change the coordination model. Without isolation, agents must coordinate in real-time (“don’t touch app.ts, I’m editing it”). With isolation, agents work freely and conflicts resolve once at merge time. This is optimistic concurrency instead of pessimistic locking — it scales better because agents never block each other.
Hands-On Example
Two agents implementing features in parallel, then merging:
STEP 1: Create worktrees
──────────────────────────────────
git worktree add .worktrees/auth -b feat/auth
git worktree add .worktrees/logging -b feat/logging
STEP 2: Agents work in parallel
──────────────────────────────────
Agent A (in .worktrees/auth/):
Creates src/middleware/auth.ts
Modifies src/app.ts:
+ import { authMiddleware } from './middleware/auth'
+ app.use(authMiddleware)
Runs tests → pass
Commits: "feat: add authentication middleware"
Agent B (in .worktrees/logging/): ← simultaneous
Creates src/middleware/logger.ts
Modifies src/app.ts:
+ import { logger } from './middleware/logger'
+ app.use(logger)
Runs tests → pass
Commits: "feat: add request logging"
STEP 3: Merge results
──────────────────────────────────
git checkout main
git merge feat/auth → clean merge
git merge feat/logging → auto-merge (different lines of app.ts)
Final app.ts has BOTH imports. No manual conflict resolution.
STEP 4: Cleanup
──────────────────────────────────
git worktree remove .worktrees/auth
git worktree remove .worktrees/logging
Handling Merge Conflicts
When changes overlap, the parent agent resolves with context:
Agent A adds line 15: app.use(authMiddleware)
Agent B adds line 15: app.use(logger)
Parent reads conflict → understands both intents → resolves:
app.use(logger) ← logger first (every request)
app.use(authMiddleware) ← auth second (validates credentials)
Isolation Strategy Comparison
No Isolation: instant setup, zero safety → single agent only
Worktree: fast setup (hardlinks), full file isolation → parallel agents
Full Clone: slow (copies repo), full isolation → untrusted agents
Container: slowest (OS-level), maximum isolation → untrusted code
Worktree hits the sweet spot: strong isolation with minimal overhead.
What Changed
| Shared Working Directory | Worktree Isolation |
|---|---|
| Agents overwrite each other | Each agent has its own directory |
| Conflicts during work | Conflicts resolved at merge time |
| Must coordinate file access | Agents work independently |
| Sequential to avoid collisions | True parallel execution |
| Single branch | One branch per agent |
Next Session
This completes Module 2: Multi-Agent Systems. You now understand task graphs, background tasks, team communication, protocols, autonomous agents, and worktree isolation.
In Module 3, we shift to the systems that configure and extend Claude Code. Session 13 starts with Control Protocol — how external tools send structured commands to Claude Code and receive responses, enabling IDE integration and programmatic control.