worktree-fleet
Worktree Fleet
A skill for running N independent agents in parallel, each isolated in its own git worktree on its own branch. Independence is validated before anything spawns — if two workers declare overlapping target_files, the skill refuses with a clear conflict message.
Decision tree — which fleet?
You want to run multiple agents in parallel. Which fleet?
1. Are the tasks independent (no shared files, no shared state)?
YES → worktree-fleet ← YOU ARE HERE
NO → continue
2. Does the work need iteration with a reviewer making accept/iterate decisions?
YES → iterative-fleet
NO → continue
3. Is the work a one-shot DAG (each agent runs to completion, dependencies via depends_on)?
YES → dag-fleet
NO → continue
4. None of the above?
→ You're the orchestrator. Open multiple Claude Code sessions.
When to use THIS skill
- Tasks touch non-overlapping files (different modules, different docs, etc.)
- You want merge-safe isolation — each worker on its own branch, no mid-flight conflicts possible
- The merge decision is yours — after workers complete, you choose merge order / strategy
- You want independent branches in git that you can inspect, cherry-pick, or discard
When NOT to use this skill
- Workers need to coordinate or read each other's output →
dag-fleetwithdepends_on - Tasks overlap files (even partially) → fix the task split first, then come back
- You want headless workers + reviewer-in-loop →
iterative-fleet - Work fits in the current conversation → use Claude Code's built-in Agent tool directly
fleet.json schema
{
"fleet_name": "refactor-utils",
"type": "worktree",
"config": {
"max_concurrent": 4,
"model": "sonnet",
"fallback_model": "haiku"
},
"workers": [
{
"id": "rename-foo",
"task": "Rename foo() to baz() in src/utils/foo.ts and all callers",
"target_files": ["src/utils/foo.ts", "src/**/*.test.ts"],
"branch": "rename-foo-to-baz",
"type": "code-run",
"max_turns": 30,
"max_budget_usd": 2.0
}
]
}
New fields vs dag-fleet:
target_files(required per worker) — list of file globs this worker will touch. Overlap across workers = launch refuses with exit 2.branch(required per worker) — git branch name for this worker's worktree. Must not already exist.
Worker type override (Claude only): Worktree workers always need Bash for git commit. If you set type to read-only, write, or reviewer, launch.sh will automatically override to code-run with a warning. The worktree itself provides isolation — Bash restrictions are unnecessary here. This override does not apply to codex workers (codex uses sandbox modes).
Provider support: Set "provider": "codex" at config or per-worker level to use OpenAI Codex CLI instead of Claude. Codex workers use --sandbox workspace-write (needed for git commit). See dag-fleet SKILL.md for full codex provider documentation (model aliases, reasoning_effort, limitations).
Default max_turns is 100 (not 50 like dag-fleet). Worktree workers typically edit, test, and commit — they need headroom.
Available scripts
| Script | When to call | Args |
|---|---|---|
launch.sh |
Validate independence, create worktrees, spawn workers in tmux | <fleet-root> [--dry-run] |
status.sh |
Per-worktree progress, cost, completion state | <fleet-name-or-root> [--json] |
merge.sh |
Print merge plan (files changed, line counts) — no auto-merge | <fleet-name-or-root> |
cleanup.sh |
Remove git worktrees, requires --force | <fleet-name-or-root> --force |
Launch procedure
- Set
FLEET_ROOTto an absolute path. - Create
$FLEET_ROOT/fleet.jsonwith the schema above. - For each worker, create
$FLEET_ROOT/workers/{id}/prompt.md. Include:Save ALL output to $FLEET_ROOT/workers/{id}/output/ — use absolute paths. - Run:
bash ${CLAUDE_SKILL_DIR}/scripts/launch.sh $FLEET_ROOT --dry-runvalidates independence without creating worktrees or spawning workers.- ALWAYS tell the user the exact status command so they can monitor manually:
This is mandatory after every launch. The user must be able to check status without asking you.bash ${CLAUDE_SKILL_DIR}/scripts/status.sh <fleet-name-or-root>
IMPORTANT: Worker prompts MUST instruct the worker to commit its changes before exiting:
When you are done, commit your changes on the current branch with a descriptive message.
Without this, changes stay as unstaged modifications and cannot be merged via git merge.
After workers complete
- Run
merge.shto see what each branch changed. - Decide your merge strategy (in-order, cherry-pick, etc.).
- Merge manually — the skill does NOT auto-merge.
- Run
cleanup.sh --forceto remove worktrees.
Rationalizations to reject
| Agent says | Rebuttal |
|---|---|
| "The tasks overlap slightly but I can manage" | Overlapping target_files = reject. No exceptions. Fix the task split first. If you think you can manage it, you're wrong — merge conflicts in parallel worktrees are unrecoverable. |
"I'll skip --dry-run since I wrote the fleet.json carefully" |
Then dry-run will be fast. Run it. The independence validator catches things you didn't think of (glob overlap, bidirectional fnmatch). |
| "Two workers both need the config file, but in different sections" | Same file = overlap. The validator doesn't know about "sections." Split the config change into a separate sequential step, or have one worker own it. |
| "I'll auto-merge since the branches are clean" | Never auto-merge. Run merge.sh, read the output, decide strategy. The whole point of worktree-fleet is that the operator owns the merge decision. |
| "I can skip cleanup — the worktrees aren't hurting anything" | Worktrees hold branch locks. Stale worktrees block future branch creation and waste disk. Run cleanup.sh --force when done. |
STRICT RULES
- Never skip
--dry-runvalidation for new fleet configurations. - Never merge without reviewing
merge.shoutput first. cleanup.shrequires--force— no accidental removals.- Worktrees persist until you explicitly clean them up. They will not auto-remove.
$ARGUMENTS