fleet

$npx mdskill add SethGammon/Citadel/fleet

Coordinates parallel agent campaigns in isolated worktrees

  • Executes 2-3 independent work streams simultaneously per wave
  • Uses worktree isolation and shared context for coordination
  • Analyzes task decomposition to determine parallelizable streams
  • Delivers consolidated discoveries and progress across all waves

SKILL.md

.github/skills/fleetView on GitHub ↗
---
name: fleet
description: >-
  Parallel campaign orchestrator. Runs multiple campaigns in coordinated waves
  within a single session. Spawns 2-3 agents per wave in isolated worktrees,
  collects discoveries, shares context between waves. Use when work decomposes
  into 3+ independent streams that can run simultaneously.
user-invocable: true
auto-trigger: false
last-updated: 2026-03-21
---

# /fleet — Parallel Coordinator

Use for 3+ independent work streams that can run simultaneously in isolated worktrees. Do NOT use for single-file scope, linear work, or when a marshal or skill suffices.

## Orientation

**Use when:** Running 2+ independent work streams in parallel — tasks with non-overlapping file scopes that can execute simultaneously.

**Don't use when:** Work must execute sequentially or accumulate findings across phases (use `/archon`), a single orchestrated session is enough (use `/marshal`), or the task is simple enough for a bare skill.

## Commands

| Command | Behavior |
|---|---|
| `/fleet [direction]` | Decompose direction into parallel streams, execute in waves |
| `/fleet [path-to-spec]` | Read a spec file, decompose into streams |
| `/fleet continue` | Resume from the last fleet session file |
| `/fleet` (no args) | Health diagnostic → work queue → execute |
| `/fleet --quick [task1]; [task2]` | Lightweight parallel mode for solo devs — 2+ tasks, single wave, auto-merge, no session file |
| `/fleet --speculative N [direction]` | Try N different approaches to the same task in parallel — see Speculative Mode below |

## Protocol

### Step 1: WAKE UP

1. Read CLAUDE.md (project conventions)
2. Check `.planning/campaigns/` for active campaigns
3. Check `.planning/coordination/claims/` for external claims
4. Determine input mode: directed, spec-driven, continuing, or undirected
5. **Load prior session context**: If `.planning/momentum.json` exists, run
   ```bash
   node .citadel/scripts/momentum-read.cjs
   ```
   and read the output. Use the active scopes and recurring decisions to inform
   work queue prioritization. Skip silently if the file is absent or output is empty.

> **Wave context restoration:** Use the Claude Code Compaction API to restore fleet
> session context at the start of each session. Do NOT read `.claude/compact-state.json`
> — that pattern is deprecated in favour of server-side compaction (available on Opus 4.6+).
> Fleet session files (`.planning/fleet/session-{slug}.md`) remain the source of truth
> for inter-wave discovery relay; compaction handles agent memory, not campaign state.
> If the Compaction API is unavailable, fall back to reading the fleet session file's
> Continuation State directly.

### Step 1b: LOG SESSION START + START WATCHER

```bash
node .citadel/scripts/telemetry-log.cjs --event campaign-start --agent fleet --session {session-slug}
node .citadel/scripts/momentum-watch-start.cjs
```

The watcher runs in the background and re-synthesizes `momentum.json` within 500ms of any new discovery write. Safe to call if already running — only one watcher runs per project.

### Step 2: WORK QUEUE

Produce a ranked list of campaigns with:

| Column | Purpose |
|---|---|
| Campaign name | What this stream does |
| Scope | Which directories it touches |
| Dependencies | What must complete before this can start |
| Wave | Which wave to assign it to |
| Agent type | What kind of agent to spawn |

**Rules for work queue:**
- Independent items go in Wave 1
- Items that depend on Wave 1 results go in Wave 2
- Maximum 3 agents per wave (conservative default)
- Scope must NOT overlap between agents in the same wave

### Step 3: WAVE EXECUTION

For each wave:

1. **Prepare context** for each agent:
   - CLAUDE.md content
   - `.claude/agent-context/rules-summary.md`
   - **Map slice** (if `.planning/map/index.json` exists): run
     `node scripts/map-index.js --query "<agent's scope keywords>" --max-files 15`
     and inject the results as a `=== MAP SLICE ===` block. If the index does
     not exist, skip silently.
   - **Prior session context** (all waves): re-read `momentum.json` fresh at each
     wave boundary via `node .citadel/scripts/momentum-read.cjs` and inject as a
     `=== PRIOR SESSION CONTEXT ===` block. Re-reading (rather than reusing the
     Step 1 snapshot) picks up discoveries written by parallel Fleet sessions in
     other terminals. If the output is empty, skip silently.
   - Campaign-specific direction and scope
   - Discovery briefs from previous waves (if any)

2. **Log wave start**:
   ```bash
   node .citadel/scripts/telemetry-log.cjs --event wave-start --agent fleet --session {session-slug} --meta '{"wave":N,"agents":["name1","name2"]}'
   ```

3. **Spawn agents** with `isolation: "worktree"`:
   ```
   Agent(
     prompt: "{full context + direction}",
     isolation: "worktree",
     mode: "bypassPermissions"
   )
   ```

4. **Collect results** from all agents in the wave

4.5. **Validate wave results** — spawn one Phase Validator per agent in parallel
   (validators are Haiku, read-only, effort: low):
   ```
   Agent(
     subagent_type: "citadel:phase-validator",
     prompt: "Campaign: {session-slug}. Wave {N} agent: {agent-name}.
              Exit conditions: {agent's scope goal and any stated conditions}.
              HANDOFF: {agent's full handoff text}",
     effort: "low"
   )
   ```
   Collect all validator verdicts. For each agent:
   - **`verdict: "pass"`**: mark agent `validated` in session file. Proceed.
   - **`verdict: "fail"`**: check retry counter for this agent (max 2 retries in fleet;
     single-session so lower budget than Archon's 3):
     - **Retries remain**: re-spawn the failed agent in a new worktree with the
       validator's `conditions_failed` and `suggestions` appended to its prompt.
       Collect its result and re-validate. Decrement counter.
     - **Retries exhausted**: mark agent `partial` in session file. Log
       `validator_halt: {agent-name} wave {N} — {conditions_failed}`. Continue.
   - **Validator timeout or unparseable output**: treat as pass with warning. Log. Advance.

   Run all validators for the wave in a single parallel batch — do not validate
   sequentially. The cost is proportional to the wave size, not multiplicative.

5. **Log per-agent results**:
   ```bash
   node .citadel/scripts/telemetry-log.cjs --event agent-complete --agent {agent-name} --session {session-slug} --status {success|partial|failed}
   ```

6. **Compress discoveries** for each agent:
   - Extract HANDOFF blocks
   - Run `node .citadel/scripts/compress-discovery.cjs` on each output
   - Write compressed briefs to `.planning/fleet/briefs/`

6b. **Write persistent discovery records** for each agent (cross-session memory):
   ```bash
   node .citadel/scripts/discovery-write.cjs \
     --session {session-slug} \
     --agent {agent-name} \
     --wave {wave-number} \
     --status {success|partial|failed} \
     --scope "{comma-separated-scope-dirs}" \
     --handoff "{json-array-of-handoff-items}" \
     --decisions "{json-array-of-decisions}" \
     --files "{json-array-of-files-touched}" \
     --failures "{json-array-of-failures}"
   ```

7. **Log wave complete**:
   ```bash
   node .citadel/scripts/telemetry-log.cjs --event wave-complete --agent fleet --session {session-slug} --meta '{"wave":N,"status":"complete"}'
   ```

8. **Merge branches** from worktrees:
   - Review changes from each agent
   - If clean merge: merge the branch
   - If conflicts: record in session file, then decide:
     - **Resolve if:** the conflict is < 20 lines and affects only formatting or naming
     - **Skip if:** the conflict involves competing logic changes; keep the higher-delta worktree result and log the discarded changes in session file

9. **Update session file** with wave results and accumulated discoveries

### Step 5: COMPLETION

After all waves:

1. Run typecheck on the full project via `node scripts/run-with-timeout.js 300 <typecheck-cmd>`
2. Run tests if configured (also use the timeout wrapper). If tests fail after wave completion: apply the same error ladder as the main protocol — 1-2 failures: fix before merging; 3-4 failures: attempt fixes, continue if resolved; 5+ failures: halt the wave merge for that worktree and log `wave_test_fail: true` in the session file.
3. Update session file status to `completed`
4. Log session completion:
   ```bash
   node .citadel/scripts/telemetry-log.cjs --event campaign-complete --agent fleet --session {session-slug}
   ```
5. **Update momentum** (cross-session synthesis):
   ```bash
   node .citadel/scripts/momentum-synthesize.cjs
   ```
5.5. **Propagate knowledge** — for each campaign that completed this session, run:
   ```bash
   npm run propagate -- --campaign {slug}
   ```
   Run once per completed campaign slug (not per wave). If multiple campaigns
   completed, run for each slug. If `npm run propagate` is unavailable, note each
   slug in the fleet session file under `## Pending Propagation`.
6. Output final HANDOFF

## Fleet Session File Format

Create at `.planning/fleet/session-{slug}.md`:

```markdown
# Fleet Session: {name}

Status: active | needs-continue | completed
Started: {ISO timestamp}
Direction: {original direction}

## Work Queue
| # | Campaign | Scope | Deps | Status | Wave | Agent |

## Wave N Results
### Agent: {name}
**Status:** complete | partial | failed
**Built:** ...  **Decisions:** ...  **Files:** ...

## Shared Context (Discovery Relay)
- {cross-agent finding → what Wave N+1 should know}

## Continuation State
Next wave: N  Blocked items: ...  Auto-continue: true
```

## Scope Overlap Prevention

Before assigning agents to a wave:

1. List all scope directories for each agent
2. Check for parent/child overlaps:
   - `src/api/` and `src/api/auth/` OVERLAP (parent/child)
   - `src/api/` and `src/ui/` do NOT overlap (siblings)
3. `(read-only)` scopes never conflict
4. If overlap: move one agent to a later wave

Also check `.planning/coordination/claims/` for external claims.

## Budget Management

**Effort hints for wave agents** (use the `effort` parameter, not `budget_tokens`):

| Agent Type | Effort | ~Tokens |
|---|---|---|
| Fleet scouts (research, mapping, audit) | `medium` | ~100K each |
| Execution agents (build, refactor, implement) | `high` | ~250K each |
| Verify agents (typecheck, visual-verify, QA) | `low` | ~60K each |

The `effort` parameter is GA as of April 2026 and produces ~20–40% token reduction
compared to manually tuned `budget_tokens` values. Always prefer `effort` for new wave definitions.

## Quality Gates

- All agents must receive full context injection
- Scope must not overlap between same-wave agents
- Every wave must produce compressed discovery briefs
- Discovery relay must be injected into subsequent waves
- Merge conflicts must be resolved or explicitly recorded
- Final typecheck must pass after all waves

## Agent Timeouts

Sub-agents can hang indefinitely on tool calls. Fleet must enforce execution time limits
at the orchestrator level.

### Default Timeouts

| Agent Type | Default Timeout | Override Key |
|---|---|---|
| Skill-level agents | 10 minutes | `agentTimeouts.skill` |
| Research scouts | 15 minutes | `agentTimeouts.research` |
| Build agents | 30 minutes | `agentTimeouts.build` |

Timeouts are configurable in `harness.json`:
```json
{
  "agentTimeouts": {
    "skill": 600000,
    "research": 900000,
    "build": 1800000
  }
}
```

### Timeout Protocol

On timeout: log `agent-timeout` event, extract partial HANDOFF if present, retry once with simplified prompt (Wave 1 critical scope only), skip otherwise. Never block the wave. Record `Status: timed out` in session file.

Read timeout values from `harness.json` → `agentTimeouts.{skill|research|build}` (defaults: 600000/900000/1800000ms).

## Shared State Merge Strategies

Parallel agents writing to the same `.planning/` directory can silently overwrite
each other. Each shared resource has a declared merge strategy:

| Resource | Strategy | Rule |
|---|---|---|
| `.planning/discoveries/*.md` | append-only | Never overwrite an existing discovery file. Each agent writes its own uniquely-named file: `{agent-id}-{timestamp}.md`. |
| `.planning/fleet/briefs/*.md` | append-only | Each agent writes its own brief. Fleet coordinator reads all of them. |
| `.planning/fleet/session-{slug}.md` | lock-on-write | Only the Fleet coordinator updates the session file. Agents never write to it directly — they emit HANDOFFs that the coordinator reads and transcribes. |
| `.planning/campaigns/{slug}.md` | lock-on-write | Only the owning Archon instance updates this file. Fleet agents that produce campaign-adjacent work report it in their HANDOFF and let Archon update. |
| `.planning/telemetry/*.jsonl` | append-only | Append-only log. Multiple agents may append simultaneously — JSONL format guarantees each line is an atomic write. |
| `.planning/wiki/_staging/*.jsonl` | append-only | Each agent writes a uniquely-named staging file. Compile step resolves all of them in order. No concurrent write conflicts possible. |
| `.planning/coordination/claims/*.json` | lock-on-write | Each agent owns its own claim file (named by instance ID). No sharing; no conflicts. |

**Enforcement:** Before Step 3 (spawn agents), remind each agent in its context
injection which paths it may write to and what the strategy is for each. Agents
that attempt to modify lock-on-write resources they don't own must be blocked via
scope claim verification.

## Consistency Voting (High-Stakes Decisions)

For decisions that cannot easily be undone — campaign completion approval, campaign
merge to main, fleet abort — spawn 3 judgment agents in parallel and require 2/3
agreement before proceeding.

**When to vote:**
- Proposing to mark a multi-wave fleet `completed` when any wave is `partial`
- Merging an agent's branch when its phase validator returned a `fail` (even after retries)
- Deciding to abort and discard work from a wave with mixed results

**How to vote:**
```
Vote prompt: "Fleet session {slug}, Wave {N}. The proposed decision is: {decision}.
             Evidence: {handoff summaries, validator results}. 
             Should we proceed? Respond with JSON: {verdict: 'proceed'|'block', reason: '...'}"
```

Spawn 3 Phase Validators with the vote prompt. Collect results. Tally:
- 3/3 proceed → proceed
- 2/3 proceed → proceed, log the dissenting reason
- 2/3 block → block, escalate to user with the reasons
- 3/3 block → block

If voting agents time out: count the timeout as a `proceed` vote (conservative — don't let validator failure park the fleet).

Skip voting when the decision is clearly safe (all waves complete, all validators pass).

## Coordination Safety

### Instance ID Generation

Every agent spawned by Fleet must have a unique instance ID.

Format: `fleet-{session-slug}-{wave}-{agent-index}`
Example: `fleet-auth-refactor-w1-a3` (wave 1, agent 3)

The instance ID is:
- Written to the agent's worktree as `.fleet-instance-id`
- Included in all telemetry log entries for this agent
- Used in coordination claims to identify which agent owns which scope
- Used in dead instance recovery to identify orphaned claims

### Scope Overlap Detection

Before spawning: compare all agent scopes pairwise (directory scopes overlap any file inside them). On overlap: merge tasks, narrow scopes, or sequence. **NEVER proceed with overlapping scopes.**

### Dead Instance Recovery

After each wave: read `.planning/coordination/claims/`, verify each instance is still alive (worktree exists + HANDOFF present). Release orphaned claims, return uncompleted scope to next wave's queue.

## Fringe Cases

- **`.planning/fleet/` does not exist**: Create the directory before writing the session file.
- **All agents in a wave fail**: Escalate to the user rather than proceeding to the next wave. Output which agents failed and why before continuing.
- **Worktree checkout fails for an agent**: Skip that agent, log the failure in the session file, and continue. Record the skipped scope as a gap for the next wave.
- **`.planning/` does not exist**: Create `.planning/fleet/` before starting. If `.planning/coordination/` is absent, skip scope claim registration.
- **Discovery compression script missing**: Write raw HANDOFF excerpts to the briefs directory instead.
- **Phase validator times out or returns malformed output**: Treat as pass with warning. Log and advance. Never block a wave on validator failure.
- **All agents in a wave fail validation and exhaust retries**: Mark the entire wave `partial`. Log `wave_validator_halt`. Escalate to the user before proceeding to the next wave — partial wave results may invalidate downstream wave assumptions.

## Speculative Mode

`/fleet --speculative N [direction]`

Try N different approaches to the same task simultaneously. Each approach gets its own
worktree and branch. When all finish, the user picks the winner; losers are archived (not deleted).

### Step 1: Decompose into N strategies

Before spawning, enumerate N distinct approaches. Each approach must:
- Target the exact same files and end goal
- Use a meaningfully different strategy (not just style variations)
- Be feasible to complete in a single agent session

### Step 2: Spawn N agents in parallel

Each agent gets:
- The common direction (same for all)
- Its strategy description (different per agent)
- Its own branch name: `speculative/{session-slug}/{strategy-label}`
- Instruction to set `branch` and `worktree_status: active` in its campaign frontmatter

Spawn with `isolation: "worktree"`. Scope overlap rules do NOT apply between speculative
agents — they will all touch the same files intentionally.

### Step 3: Collect and compare

After all agents complete, for each:
1. Read the HANDOFF
2. Run typecheck on that worktree's branch via `node scripts/run-with-timeout.js 300 <typecheck-cmd>`
3. Record in the session file: what was built, typecheck result, key decisions

Present a comparison table to the user:

| Strategy | Branch | Typecheck | Key Decision | Notable Tradeoffs |
|----------|--------|-----------|--------------|-------------------|

If ALL N approaches fail typecheck: present the comparison table with all entries marked `FAIL typecheck`. Ask the user to pick the least-broken approach or abort. Do not proceed to Step 4 without a user decision.

### Step 4: Archive losers, merge winner

When the user picks a winner:
1. **Winner**: Update campaign frontmatter `worktree_status: merged`, proceed with normal merge
2. **Losers**: Update campaign frontmatter `worktree_status: archived`. Do NOT delete branches.

```bash
# Optional: tag losers for clarity
git tag archive/{loser-branch} {loser-branch}
```

Add `## Speculative Comparison` to session file: direction, N strategies, comparison table (strategy/branch/status/typecheck/notes), winner, merge timestamp.

## Quick Mode

`/fleet --quick [task1]; [task2]; [task3]`

### Differences from standard fleet

| Property | Standard Fleet | Quick Mode |
|---|---|---|
| Min streams | 3 | 2 |
| Min complexity | 4 | 3 |
| Waves | Multi-wave with discovery relay | Single wave only |
| Session file | Written to `.planning/fleet/` | Skipped — results reported inline |
| Discovery briefs | Compressed to `.planning/fleet/briefs/` | Skipped |
| Merge | Per-wave confirmation | Auto-merge if no conflicts |
| Scope claim | Written to coordination/ | Skipped |

### Protocol

1. Parse tasks from the `--quick` argument (semicolon-separated)
2. Validate scope overlap — if any two tasks touch the same files, merge them or sequence them
3. Spawn all agents simultaneously with `isolation: "worktree"`
4. Collect results; auto-merge worktrees if no conflicts detected
5. If merge conflict: surface to user, offer manual resolution
6. Report results inline — no session file written unless the user asks

### When /do routes here

`/do` routes to `--quick` mode (not standard fleet) when:
- Input contains "at the same time", "simultaneously", "in parallel", "both ... and"
- Two or more clearly independent tasks are detected
- Complexity is 3 (moderate), not 4+ (complex)
- User chose "1" (yes once) or "2" (always) on the Fleet confirmation prompt

Entry from `/do` confirmation prompt: user chose yes (1) or always (2). Preferences stored under `consent.fleetSpawn` in harness.json via `readConsent`/`writeConsent`.

## Contextual Gates

### Disclosure
- "Spawning {N} agents across {waves} waves in isolated worktrees. Estimated token budget: ~{tokens}K."
- For speculative mode: "Running {N} parallel approaches to the same task. All will touch the same files."

### Reversibility
- **Green:** Single-wave fleet with < 3 agents
- **Amber:** Multi-wave fleet (the default) -- each wave's merge is a separate commit
- **Red:** Speculative mode or fleets that modify shared infrastructure

Red actions require explicit confirmation regardless of trust level.

### Proportionality
- **Standard fleet:** work queue requires 3+ independent streams. Fewer → downgrade to Marshal or Archon.
- **Quick mode:** 2+ tasks with non-overlapping scopes. No minimum complexity gate.
- If all streams touch the same directory: downgrade to sequential Archon phases
- If estimated agents > 6: confirm with user (even trusted level)

### Trust Gating
Read trust level from `harness.json`:
- **Novice** (0-4 sessions): Always confirm before spawning. Show agent count, scopes, and estimated cost.
- **Familiar** (5-19 sessions): Confirm only for > 3 agents or speculative mode.
- **Trusted** (20+ sessions): Auto-proceed for standard fleet. Confirm only for speculative mode or > 6 agents.

## Exit Protocol

Update the session file, then output:

```
---HANDOFF---
- Fleet session: {name} — {waves completed} waves, {agents} agents total
- Built: {summary of all wave results}
- Discoveries: {key cross-agent findings}
- Merge conflicts: {count and resolution}
- Next: {remaining work if any}
- Reversibility: amber -- multi-wave merges, revert each wave's merge commit
---
```

More from SethGammon/Citadel