Skip to content

Git Worktree Isolation ​

Agents Fleet uses Git worktrees to give file-mutating workers isolated file system environments for safe parallel editing.

Overview ​

When the coordinator spawns a worker whose effective permission profile can run shell commands or write without scope restrictions, it automatically gets its own Git worktree:

  • Shell-capable or unrestricted-write workers → isolated worktree at .worktrees/{agentId}/ on branch worker/{agentId}
  • Read-only and scoped write-only workers → share the main working directory

The decision uses the effective profile after wildcard, type-specific, and spawn overrides. Shell is treated as write-capable even when canWrite is false, because commands can modify files directly. This includes tester workers and restricted workers explicitly elevated under SEC-4.

An explicit spawn cwd takes precedence and disables automatic worktree creation. That preserves compatibility for workflows that intentionally select a directory, but it also means shell commands operate in that shared directory. This is especially important on Windows, where an explicit shared path does not gain isolation merely because the effective profile was elevated.

Key Features ​

  • Automatic creation — worktrees are created on worker spawn, no user action needed
  • Fail-closed isolation — when an effective profile requires isolation and worktree creation fails, the worker fails before provider startup instead of falling back to the shared working tree
  • Auto-merge on completion — successful workers have their changes merged back
  • Conflict detection — merge conflicts are caught and handled gracefully
  • Worktree preservation on failure — failed workers' worktrees are kept for inspection
  • Max 2 merge resolution attempts — prevents infinite conflict loops (DoD-31/32)

How It Works ​

WorktreeManager ​

The WorktreeManager is responsible for the lifecycle of Git worktrees:

  1. Create — git worktree add .worktrees/{agentId} -b worker/{agentId}
  2. Remove — git worktree remove .worktrees/{agentId} + branch cleanup
  3. Merge — fast-forward or three-way merge back to the source branch
  4. List — enumerate all active worktrees

FleetManager Integration ​

The FleetManager hooks into worker lifecycle events:

Worker Spawn
  → WorktreeManager.create(agentId)
  → SDK session receives worktree path as workingDirectory
  → Worker operates in isolated directory

Worker Complete (success)
  → WorktreeManager.merge(agentId)
  → Worktree removed on successful merge
  → Branch cleaned up

Worker Complete (failure)
  → Worktree preserved for inspection
  → Warning logged for user

SDK Working Directory ​

The SDK's workingDirectory parameter passes the worktree path to the worker session. This means the worker's file operations (read, write, edit, bash) all operate within the isolated worktree.

Merge Conflict Flow ​

When a merge conflict is detected:

Merge Attempt
  → Conflict detected
  → Abort merge (git merge --abort)
  → Preserve worktree for manual resolution
  → Block the task (mark as blocked)
  → Notify coordinator of conflict

Coordinator may retry (up to 2 attempts)
  → If still conflicted after 2 attempts → permanent block

A maximum of 2 merge resolution attempts are allowed before the task is permanently blocked (DoD-31/32). This prevents infinite conflict resolution loops.

Commands ​

/worktree list ​

Show all active worktrees:

🌳 Active Worktrees
────────────────────
Type     Path                          Branch
worker   .worktrees/worker-1/          worker/worker-1
worker   .worktrees/worker-3/          worker/worker-3
compete  .worktrees/compete-pragmatic/ compete/pragmatic

/worktree cleanup ​

Remove all worker worktrees and their branches:

🧹 Cleaned up 3 worker worktrees

/worktree cleanup --all ​

Remove all worktrees including /compete worktrees:

🧹 Cleaned up 3 worker worktrees + 2 compete worktrees

/worktree status ​

Show worktree system status:

🌳 Worktree Status
──────────────────
Git Version:    2.43.0 ✅
Worker Trees:   2 active
Compete Trees:  1 active
Directory:      .worktrees/

Configuration ​

Worktree settings in your fleet config (~/.fleet/config.json or project .fleet/config.json):

typescript
worktrees?: {
  enabled?: boolean;           // default: true
  directory?: string;          // default: '.worktrees'
  symlinkNodeModules?: boolean; // default: false
}

Options ​

OptionDefaultDescription
enabledtrueEnable/disable worktree isolation for shell-capable and unrestricted-write workers
directory'.worktrees'Directory name for worktrees (relative to repo root)
symlinkNodeModulesfalseSymlink node_modules from main repo into worktrees to save disk space and install time

Disabling Worktrees ​

json
{
  "worktrees": {
    "enabled": false
  }
}

When disabled, all workers (including coders) share the main working directory. This is simpler but risks file conflicts during parallel editing.

/compete Integration ​

The /compete command uses the WorktreeManager with the prefix compete:

/compete "Implement caching layer"

This creates 3 parallel worktrees:

.worktrees/compete-pragmatic/    → branch: compete/pragmatic
.worktrees/compete-clean/        → branch: compete/clean
.worktrees/compete-alternative/  → branch: compete/alternative

Each implementation runs in full isolation. After judging, the winning implementation is merged:

/compete pick pragmatic
  → Merges compete/pragmatic into main branch
  → Cleans up all compete worktrees and branches

Compete Lifecycle ​

/compete <description>
  → Create 3 worktrees (pragmatic, clean, alternative)
  → Spawn 3 coder workers in parallel
  → Workers implement independently

/compete judge
  → Spawn reviewers to rate each implementation
  → Scores: correctness, quality, testing, performance, simplicity, integration

/compete pick <name>
  → Merge winning branch
  → Remove all compete worktrees

/compete cleanup
  → Force-remove all compete worktrees

Startup Checks ​

Git Version Requirement ​

Worktrees require Git ≥ 2.15. On startup, the CLI checks your Git version:

  • ≥ 2.15 → worktrees enabled normally
  • < 2.15 → warning displayed, worktrees disabled for the session
⚠️  Git 2.12.0 detected. Worktrees require Git ≥ 2.15.
    Worktree isolation disabled. Coders will share the main directory.

Orphan Worktree Detection ​

On startup, the CLI scans for leftover worktrees from previous sessions:

⚠️  Found 2 orphan worktrees from a previous session:
    .worktrees/worker-5/
    .worktrees/worker-8/
    Run /worktree cleanup to remove them.

This helps keep your repository clean after crashes or interrupted sessions.

Best Practices ​

  1. Run /worktree cleanup after sessions — especially after failures that may leave orphan worktrees
  2. Check /worktree status if things seem wrong — confirms Git version and active tree counts
  3. Use symlinkNodeModules: true for Node.js projects — avoids duplicate node_modules in each worktree
  4. Don't manually edit files in .worktrees/ — these directories are managed by the CLI
  5. Add .worktrees/ to .gitignore — worktrees should not be committed