Skip to content
🎓 Find your path Subscribe

Worktree Isolation: The Hard Lesson

Tier 2 · Building 9 min read

Before this, read:


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.

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.

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 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.

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:

Terminal window
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/ directly

The agent works in its own worktree. Other agents’ worktrees are unaffected.

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:

Terminal window
bash ~/agent-system/scripts/install-nc5-pre-commit.sh

Override only with NC5_ALLOW_SHARED_COMMIT=1 (JD’s use only, for emergency situations).

~/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:

  1. Stashes any uncommitted work (saving it, not deleting it)
  2. Detaches HEAD onto origin/main
  3. 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.

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.

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.sh as 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.