Skip to content

ADR-001: Git Worktrees for Parallel Agent Isolation in Swarm Mode #213

@justrach

Description

@justrach

ADR-001: Git Worktrees for True Parallel Agent Isolation

Status: Proposed
Date: 2026-03-04
Deciders: @justrach
Area: swarm.zig, agent_sdk.zig, new worktree.zig


Context

run_swarm and review_fix_loop spawn multiple parallel agents, each operating on the same repository working tree. When writable: true, these agents can and do edit files concurrently — with no isolation.

The Problem Today

All parallel agents share a single working directory (cwd = repo_root):

Agent 1 ─── reads src/foo.zig ───► edits src/foo.zig ─── writes
Agent 2 ─── reads src/foo.zig ───► edits src/foo.zig ─── writes  ← OVERWRITES Agent 1
Agent 3 ─── reads src/lib.zig ───► edits src/lib.zig ─── writes  ← fine (different file)

Failure mode: last write wins. No conflict detection, no merge, no error — just silent data loss.

What Are Git Worktrees?

A git worktree is a second (or Nth) checkout of the same repository, each with:

  • ✅ Its own working directory — fully isolated filesystem state
  • ✅ Its own index (staging area) and HEAD pointer
  • Shared object database (.git/objects/) — no history duplication
.git/objects/                  ← shared: all history, objects
wt-agent-0/src/foo.zig         ← agent 0's working copy (isolated)
wt-agent-1/src/foo.zig         ← agent 1's working copy (isolated)
src/foo.zig                    ← main worktree (untouched)

Git worktrees have been stable since Git 2.15 (2017).


Decision

Give each parallel agent its own git worktree when writable: true.

Before spawning workers in run_swarm and review_fix_loop, create N temporary worktrees from HEAD (detached). Pass each worktree path as the agent's cwd. Remove all worktrees after synthesis.

Why This Over Alternatives

Alternative Why Rejected
File-level advisory locks Agents (claude/codex subprocesses) don't participate in our lock protocol
Pessimistic scheduling Eliminates parallelism
Post-hoc merge with git merge-file Impractical for LLM agents
Copy repo to temp dir Copies all history; 10–100× slower
Git worktrees Native git primitive, shared object DB, file isolation, ~50ms setup

Consequences

Positive

  • Parallel writes are safe by construction — no conflict possible between agents
  • Each agent's state inspectable in wt-agent-N/ after failure (great for debugging)
  • No changes to agent prompts or coordination logic needed

Negative

  • Each worktree duplicates working tree files (~50–200 MB per agent)
  • Stale worktrees accumulate on crash; need git worktree prune on startup

Implementation Plan

Sub-issues to create:

  1. worktree.zigcreateWorktree, removeWorktree, pruneWorktrees primitives + tests
  2. Modify swarm.zig — create/destroy per-agent worktrees around worker phase
  3. Modify review_fix_loop — worktree-per-iteration
  4. Startup prune — run git worktree prune on notifications/initialized
  5. Docs + AGENTS.md — document worktree model and agent constraints

Reference Architecture (After)

run_swarm(prompt, max_agents=3, writable=true)
  │
  ├─ Orchestrator → [task-0, task-1, task-2]
  ├─ git worktree add wt-agent-0 --detach HEAD   (~50ms each)
  ├─ git worktree add wt-agent-1 --detach HEAD
  ├─ git worktree add wt-agent-2 --detach HEAD
  │
  ├─ Agent 0 [cwd=wt-agent-0] ─── edits wt-agent-0/src/foo.zig
  ├─ Agent 1 [cwd=wt-agent-1] ─── edits wt-agent-1/src/bar.zig  ← fully parallel
  ├─ Agent 2 [cwd=wt-agent-2] ─── edits wt-agent-2/src/foo.zig  ← safe, isolated copy
  │
  ├─ Synthesizer → reads all three diffs, merges findings
  └─ git worktree remove wt-agent-{0,1,2}

Files to Change

File Change
src/worktree.zig New — worktree lifecycle primitives
src/swarm.zig Create/destroy worktrees around worker phase
src/tools.zig Wire prune into startup
src/main.zig Call worktree.pruneWorktrees on init
AGENTS.md Document worktree model and agent constraints

References

  • Git Worktree Docs
  • Stable since Git 2.15 (2017); used in GitHub Actions matrix builds

This is ADR-001 — the first Architectural Decision Record for this project. Future ADRs should follow this format.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions