Worktree Isolation: The Hard Lesson
Before this, read:
- Git discipline for agents — branch-first conventions the incidents violated
- Spawning sub-agents — the context for parallel build agents
The rule is simple: every background agent that may write files or run git gets isolation: "worktree". The rule exists because two separate incidents proved that honor-system instructions are not enough, and each recovery cost 15+ minutes of reflog archaeology.
This article tells the story of those incidents, explains what git worktrees actually do, and documents the three-layer machine enforcement that replaced the behavioral rule.
What went wrong (CHANGELOG 2026-05-22)
Section titled “What went wrong (CHANGELOG 2026-05-22)”In May 2026, two parallel sub-agents were running build work at the same time. Both were spawned without worktree isolation. Here is what happened:
Sub-agent A was editing page.tsx in the org-chart-v2 branch. Sub-agent B, running a separate task, ran git checkout chat-resume-fix — which moved the shared working tree to a different branch. Sub-agent A’s page.tsx edits, mid-flight, were now on chat-resume-fix instead of org-chart-v2. The wrong changes landed on the wrong branch.
Then a third sub-agent did the same thing with agent/remove-synthetic-from-nav, dropping a Phase 4 commit until the parent session found it via git reflog and cherry-picked it back.
Neither agent knew it had broken anything. From each agent’s perspective, it ran git checkout <its-branch> as instructed. The problem was that they shared the same working tree — one checkout, two agents, no fencing.
What a git worktree actually does
Section titled “What a git worktree actually does”git worktree add creates a second directory pointing at the same repository but checked out to a different branch. The two directories do not interfere: editing files in one does not move the HEAD of the other.
When you pass isolation: "worktree" to the Agent tool, it creates one of these worktrees for the sub-agent. The sub-agent’s working directory is its own checkout. The parent session’s checkout doesn’t move regardless of what the sub-agent does.
The nested-repo problem
Section titled “The nested-repo problem”The Agent tool’s isolation: "worktree" covers the outer repo (agent-system). It does not cover nested repos.
projects/nerve-center-v5/ is a separate GitHub repo nested inside agent-system. Every concurrent agent that edits NC5 files touches the same .git/HEAD for that repo — the outer worktree doesn’t help. Agent A running git -C projects/nerve-center-v5 checkout other-branch rips the rug out from under agent B in the same shared NC5 checkout.
This happened again in June 2026.
The three-layer machine enforcement
Section titled “The three-layer machine enforcement”After the second incident, the system added three artifacts that enforce the rule without relying on any agent’s memory of a CLAUDE.md instruction:
Layer 1 — The per-agent worktree wrapper
Section titled “Layer 1 — The per-agent worktree wrapper”~/agent-system/scripts/safe-nc5-edit.sh <branch> [base]
Creates a git worktree under projects/nerve-center-v5/.claude/worktrees/safe-<branch>/ and prints its path. Idempotent — calling it twice with the same branch returns the same path.
Any agent working on NC5 uses this:
WT=$(bash ~/agent-system/scripts/safe-nc5-edit.sh feat/my-feature)cd "$WT"# edit, test, commit from here — never touch projects/nerve-center-v5/ directlyThe agent works in its own worktree. Other agents’ worktrees are unaffected.
Layer 2 — The pre-commit hook
Section titled “Layer 2 — The pre-commit hook”projects/nerve-center-v5/.git/hooks/pre-commit
The hook checks whether the commit is happening from the shared canonical checkout path. If yes, it refuses with an error pointing at safe-nc5-edit.sh. If the commit is from a worktree path, it passes.
This means: even if an agent forgets the instruction, even if it somehow ends up in the shared checkout, the commit fails. The hook is the last line of defense.
Reinstall the hook after a fresh clone:
bash ~/agent-system/scripts/install-nc5-pre-commit.shOverride only with NC5_ALLOW_SHARED_COMMIT=1 (JD’s use only, for emergency situations).
Layer 3 — The drift watchdog
Section titled “Layer 3 — The drift watchdog”~/agent-system/scripts/nc5-watchdog.sh, runs every 5 minutes via cron.
If the shared NC5 checkout has been on a non-main branch for 5+ minutes, the watchdog:
- Stashes any uncommitted work (saving it, not deleting it)
- Detaches HEAD onto
origin/main - Sends JD a Telegram message with the drift duration and the stash ref
State lives at ~/agent-system/state/nc5-watchdog.json. Log at ~/agent-system/logs/nc5-watchdog.log.
The watchdog doesn’t fix the root cause — it contains the blast radius. An agent that forgot the rule doesn’t permanently corrupt the main checkout; the watchdog catches it within 5 minutes and cleans up.
The broader lesson
Section titled “The broader lesson”These three layers are an instance of a rule that appears throughout this system: infrastructure beats instructions. A CLAUDE.md note saying “always use worktrees” is read once and forgotten when the context window fills. A pre-commit hook that refuses the commit is not forgotten. A drift watchdog that auto-corrects doesn’t rely on anyone’s memory.
The pattern: when a class of bug repeats despite written instructions, stop writing instructions and build the enforcement. The doc is still valuable as explanation; it cannot be the only protection.
Checklist for spawning parallel agents
Section titled “Checklist for spawning parallel agents”Before spawning multiple background agents on the same codebase:
isolation: "worktree"in every Agent tool call that may write files- Tell each sub-agent in its prompt: “You are in a worktree. Confirm with
pwd. Don’t touch other branches in the parent checkout.” - For work on NC5 specifically: use
safe-nc5-edit.shas the first step in the sub-agent’s prompt - Have each sub-agent commit in its own worktree; the parent merges via
git fetch && git merge --ff-only <branch>afterward, not by checking out the worktree itself
Next: How a hierarchy of agents routes and delegates work — CEO, domain agents, specialists, and the ask_agent messaging layer. Orchestration: CEO → domains → specialists.