
Swarm
- 1.4k installs
- 416 repo stars
- Updated August 5, 2026
- boshu2/agentops
swarm is an agent skill for dispatch parallel agents. triggers: "swarm", "dispatch parallel agents.", "swarm skill".
About
The swarm skill is designed for dispatch parallel agents. Triggers: "swarm", "dispatch parallel agents.", "swarm skill". Swarm Skill Spawn isolated agents to execute tasks in parallel. Before you swarm — pick the lightest path that fits > Confirm a swarm is even warranted. Invoke when the user asks about swarm or related SKILL.md workflows.
- microservices.
- team-topologies.
- mythical-man-month.
- .agents/swarm/results/*.json.
- kind: customer-of.
Swarm by the numbers
- 1,392 all-time installs (skills.sh)
- +28 installs in the week ending Aug 4, 2026 (Skillselion tracking)
- Ranked #496 of 2,153 Testing & QA skills by installs in the Skillselion catalog
- Security screen: HIGH risk (skills.sh audit)
- Data as of Aug 5, 2026 (Skillselion catalog sync)
swarm capabilities & compatibility
- Capabilities
- microservices · team topologies · mythical man month · .agents/swarm/results/*.json
- Use cases
- testing
What swarm says it does
Dispatch parallel agents. Triggers: "swarm", "dispatch parallel agents.", "swarm skill".
Dispatch parallel agents. Triggers: "swarm", "dispatch parallel agents.", "swarm skill".
npx skills add https://github.com/boshu2/agentops --skill swarmAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1.4k |
|---|---|
| repo stars | ★ 416 |
| Security audit | 3 / 3 scanners passed |
| Last updated | August 5, 2026 |
| Repository | boshu2/agentops ↗ |
How do I dispatch parallel agents. triggers: "swarm", "dispatch parallel agents.", "swarm skill"?
Dispatch parallel agents. Triggers: "swarm", "dispatch parallel agents.", "swarm skill".
Who is it for?
Developers using swarm workflows documented in SKILL.md.
Skip if: Skip when the task falls outside swarm scope or needs a different stack.
When should I use this skill?
User asks about swarm or related SKILL.md workflows.
What you get
Completed swarm workflow with documented commands, files, and expected deliverables.
- Coordination contract artifacts
- Collision-free parallel commits
By the numbers
- Defines eight required coordination contract fields per parallel agent stream
Files
Swarm Skill
Spawn isolated agents to execute tasks in parallel. Fresh context per agent (Ralph Wiggum pattern).
Before you swarm — pick the lightest path that fits
Confirm a swarm is even warranted. A swarm pays off only with **≥2
genuinely independent units of working-tree work** that benefit from
isolation. If it's one deliverable, pure analysis/investigation, or
no working-tree edits, do NOT swarm — use the lighter path below. Reaching
for the machinery on a small task costs more than the task (real failure
2026-06-15: an ATM-codex swarm pointed at a ~9-idea content task wedged on
codex boot; in-session Agent fan-out did it in one pass).
Three paths, lightest first — reach for the lightest that fits:
| Path | What it is | Use when |
|---|---|---|
| In-session Agent/Task fan-out (lightest) | Spawn 2–3 Agent subagents in this session. No persistence, no worktrees, no attach, dies with the session. Read-only-friendly. | One-shot parallel work: independent drafts, fan-out analysis, fresh-eyes review. Default for anything small. See `automation-shape-routing` shape 0. |
| `/swarm` (middle) | Wave-gated working-tree execution with disjoint file ownership + conflict checks (this skill). | ≥2 independent units that edit the working tree and need isolation + wave-validity gating. |
| ATM (`/using-atm`, heaviest) | Persistent tmux panes + human attach/steer + multi-vendor, running whole /rpi//evolve loops. | Long-lived epics needing persistence and live steering — not one-shot tasks. Boot cost (esp. codex) alone can exceed doing it inline. |
Loop position
Move 5 (wave execution) of the operating loop, specifically the parallel-fork primitive /crank invokes. Refuses to spawn parallel agents on a wave that has not cleared the wave-validity check in the slice validation plan: write scopes must be disjoint, no shared migration/contract/CLI surface, integration order declared when it matters, one owner per slice, discard path per slice. Parallelism is explicit ownership, not swarm chaos. Default to sequential when the wave-validity rows are not all green.
Coupled-chain rule (DERIVED-surface collision). Two slices that both regenerate a shared derived surface — cli-command-surface, registry.json, context-map, or the codex manifest — collide even if their source files are disjoint. Such a coupled chain (schema→write-model→export→gate→tests) MUST run sequential: each link branches off the freshly-MERGED prior link's SHA, never a pre-fan snapshot. Reserve parallel waves for provably-disjoint surfaces, cap 4–6.
Integration modes:
- Direct - Create TaskList tasks, invoke
/swarm - Via Crank -
/crankcreates tasks from beads, invokes/swarmfor each wave
Requires multi-agent runtime. Swarm needs a runtime that can spawn parallel subagents. If unavailable, work must be done sequentially in the current session.
Architecture (Mayor-First)
Mayor (this session)
|
+-> Plan: TaskCreate with dependencies
|
+-> Identify wave: tasks with no blockers
|
+-> Select spawn backend (gc if available; runtime-native: Claude teams in Claude runtime, Codex sub-agents in Codex runtime; fallback tasks if unavailable)
|
+-> Assign: TaskUpdate(taskId, owner="worker-<id>", status="in_progress")
|
+-> Spawn workers via selected backend
| Workers receive pre-assigned task, execute atomically
|
+-> Wait for completion (wait() | SendMessage | TaskOutput)
|
+-> Validate: Review changes when complete
|
+-> Cleanup backend resources (close_agent | TeamDelete | none)
|
+-> Repeat: New team + new plan if more work neededExecution
Read references/execution-steps.md when you need the full procedural detail (Steps 0–6): backend detection, gc dispatch, task typing + file manifests, context briefing, manifest auto-population, advisory bead clustering, wave identification, pre-spawn conflict check, test-file naming validation, multi-wave base-SHA refresh, and worker dispatch.
Every TaskCreate must include metadata.issue_type plus a metadata.files array. Do not spawn workers with overlapping file manifests into the same shared-worktree wave.
Example Flow
Mayor: "Let's build a user auth system"
1. /plan -> Creates tasks:
#1 [pending] Create User model
#2 [pending] Add password hashing (blockedBy: #1)
#3 [pending] Create login endpoint (blockedBy: #1)
#4 [pending] Add JWT tokens (blockedBy: #3)
#5 [pending] Write tests (blockedBy: #2, #3, #4)
2. /swarm -> Spawns agent for #1 (only unblocked task)
3. Agent #1 completes -> #1 now completed
-> #2 and #3 become unblocked
4. /swarm -> Spawns agents for #2 and #3 in parallel
5. Continue until #5 completes
6. /validate -> Validate everythingScope-Escape Protocol
When a worker discovers work outside their assigned scope, they MUST NOT modify files outside their file manifest. Instead, append to .agents/swarm/scope-escapes.jsonl:
{"worker": "<worker-id>", "finding": "<description>", "suggested_files": ["path/to/file"], "timestamp": "<ISO8601>"}For richer scope-escape narration (status classification, concrete next step, evidence), see references/scope-escape-template.md. Use the template when a single-line JSONL entry is insufficient for the operator to act on.
The lead reviews scope escapes after each wave and creates follow-up tasks as needed.
Key Points
- Runtime-native local mode - Auto-selects the native backend for the current runtime (gc pool, Claude teams, or Codex sub-agents)
- Universal orchestration contract - Same swarm behavior across Claude and Codex sessions
- Pre-assigned tasks - Mayor assigns tasks before spawning; workers never race-claim
- Fresh worker contexts - New sub-agents/teammates per wave preserve Ralph isolation
- Wave execution - Only unblocked tasks spawn
- Mayor orchestrates - You control the flow, workers write results to disk
- Thin results - Workers write
.agents/swarm/results/<id>.json, orchestrator reads files (NOT Task returns or SendMessage content) - Retry via message/input - Use
send_input(Codex) orSendMessage(Claude) for coordination only - Atomic execution - Each worker works until task done
- Graceful degradation - If multi-agent unavailable, work executes sequentially in current session
Worker report contract + lane authority (cp-hhd7, cards 4 + 16)
Worker FINAL REPORT — what the orchestrator requires
Workers write raw evidence; the orchestrator does not trust prose summaries. Each .agents/swarm/results/<id>.json or the worker's final message SHOULD include:
files_changed: [list of exact paths]
commit_sha: <git rev-parse HEAD> # or "no commit" + reason
test_tail: <verbatim last N lines of test output>
conflicts_surfaced: [list, or "none"]A result missing commit_sha or test_tail is treated as unverified until the orchestrator independently confirms persistence and test passage. The audit cost of trusting summaries exceeds the cost of requiring the fields.
Lane authority (POLICY, card 4 — applies when running a two-lane swarm)
In a multi-lane deployment (this is a contextual policy, not a universal swarm rule), a decision inside one lane's scope is decided by that lane with the other lane's view as input — not a vote, not an escalation. Escalate to the human operator only for:
- genuine out-of-both-lanes decision forks
- gate violations
- a loop that cannot self-heal
Escalating an in-lane sequencing call makes the operator a bottleneck. The lane authority rule is enforced by convention in the control-plane context; the mechanism (swarm) is general.
Workflow Integration
This ties into the full workflow:
/research -> Understand the problem
/plan -> Decompose into beads issues
/crank -> Autonomous epic loop
+-- /swarm -> Execute each wave in parallel
/validate -> Validate results
/post-mortem -> Extract learningsDirect use (no beads):
TaskCreate -> Define tasks
/swarm -> Execute in parallelThe knowledge flywheel captures learnings from each agent.
Task Management Commands
# List all tasks
TaskList()
# Mark task complete after notification
TaskUpdate(taskId="1", status="completed")
# Add dependency between tasks
TaskUpdate(taskId="2", addBlockedBy=["1"])Parameters
| Parameter | Description | Default |
|---|---|---|
--max-workers=N | Max concurrent workers | 5 |
--from-wave <json-file> | Load wave from OL hero hunt output (see OL Wave Integration) | - |
--per-task-commits | Commit per task instead of per wave (for attribution/audit) | Off (per-wave) |
When to Use Swarm
| Scenario | Use |
|---|---|
| Single one-shot deliverable / no working-tree edits / read-only investigation | do NOT swarm → do it inline, or fan out 2–3 in-session Agent subagents (see "Before you swarm" above + `automation-shape-routing` shape 0) |
| Multiple independent tasks | /swarm (parallel) |
| Sequential dependencies | /swarm with blockedBy |
| Mix of both | /swarm spawns waves, each wave parallel |
Why This Works: Ralph Wiggum Pattern
Follows the Ralph Wiggum Pattern: fresh context per execution unit.
- Wave-scoped worker set = spawn workers -> execute -> cleanup -> repeat (fresh context each wave)
- Mayor IS the loop - Orchestration layer, manages state across waves
- Workers are atomic - One task, one spawn, one result
- TaskList as memory - State persists in task status, not agent context
- Filesystem for EVERYTHING - Code artifacts AND result status written to disk, not passed through context
- Backend messaging for signals only - Short coordination signals (under 100 tokens), never work details
Ralph alignment source: ../shared/references/ralph-loop-contract.md.
Integration with Crank
When /crank invokes /swarm: Crank bridges beads to TaskList, swarm executes with fresh-context agents, crank syncs results back.
| You Want | Use | Why |
|---|---|---|
| Fresh-context parallel execution | /swarm | Each spawned agent is a clean slate |
| Autonomous epic loop | /crank | Loops waves via swarm until epic closes |
| Just swarm, no beads | /swarm directly | TaskList only, skip beads |
| RPI progress gates | /flywheel | Tracks progress; does not execute work |
---
Codex-Specific Coordination (folded from codex-team)
When the selected backend is Codex (Codex CLI on PATH or Codex sub-agents), swarm follows the same wave model, but Codex agents are headless — they cannot negotiate locks or wait turns. The orchestrator IS the lock manager: all conflict prevention happens before spawning, via file-target analysis.
Backend selection (Codex path), in order: 1. spawn_agent available → Codex experimental sub-agents (preferred) 2. Codex CLI available → Codex CLI via Bash (codex exec ...) 3. skill tool read-only (OpenCode) → OpenCode subagents (task(subagent_type="general", ...)) 4. None → fall back to the runtime-native swarm backend / sequential
Decision-time warning (codex boot-wedge). A Codex-backed swarm adds a boot-failure surface — codex can fail to boot at all (the actual 2026-06-15 failure: a codex swarm wedged before doing any work). For a small task the boot cost alone can exceed doing it inline, so first confirm the swarm is warranted (see "Before you swarm" at the top), then run the pre-flight below before committing to a Codex swarm.
Pre-flight (CLI backend only): verify which codex, then test the configured default model with codex exec --full-auto -C "$(pwd)" "echo ok". If either fails, fall back to another backend.
Canonical command + flag order:
codex exec --full-auto -C "$(pwd)" -o <output-file> "<prompt>"Flag order: --full-auto → -C → -o → prompt (insert -m "<model>" before -C only when intentionally pinning a model; otherwise the user's default is used). Valid flags: --full-auto, -m, -C, -o, --json, --output-schema, --add-dir, -s. Do NOT use -q / --quiet (don't exist).
- Cross-project tasks:
--add-dir /path/to/other/repo(repeatable) grants access beyond-C. - Progress monitoring: add
--jsonto stream JSONL events (turn.started/turn.completedwith tokenusage). No events for 60s → agent likely stuck. - Sandbox levels (`-s`):
read-onlyfor judges/reviewers,workspace-write(default with--full-auto),danger-full-accessonly in externally-sandboxed environments. Prefer-s read-onlyfor review/analysis tasks.
File-target strategy (apply before spawning Codex agents):
| File Overlap | Strategy | Action |
|---|---|---|
| All tasks touch same file | Merge | Combine into 1 agent with all fixes |
| Some tasks share files | Multi-wave | Shared-file tasks go sequential across waves |
| No overlap | Parallel | Spawn all agents at once |
For multi-wave Codex runs, the lead reads prior-wave results, then injects a summary of what changed (not raw diffs) into the next wave's prompts. Limits: ≤6 agents/wave, 120s default timeout, ≤3 waves (reconsider decomposition beyond that). Output dir: .agents/codex-team/ (or the standard .agents/swarm/results/). Concrete tool calls: references/backend-codex-subagents.md.
Codex troubleshooting: codex not found → npm i -g @openai/codex or fall back; default model unavailable → verify the echo ok pre-flight or pin with -m; empty/missing output → ensure the -o directory exists and is writable.
---
OL Wave Integration
Read references/ol-wave-integration.md when you invoke /swarm --from-wave <json-file> — covers pre-flight ol CLI check, input JSON format, task creation from wave entries, completion backflow via ol hero ratchet, and example flow.
---
References
- Executable acceptance: references/swarm.feature — wave-validity gate, fresh-context workers, conflict-free ownership, results+cleanup (soc-qk4b)
- Local Mode Details:
skills/swarm/references/local-mode.md - Validation Contract:
skills/swarm/references/validation-contract.md
---
Examples
Building a User Auth System
User says: /swarm
What happens: 1. Agent identifies unblocked tasks from TaskList (e.g., "Create User model") 2. Agent selects spawn backend using runtime-native priority (Claude session -> Claude teams; Codex session -> Codex sub-agents) 3. Agent spawns worker for task #1, assigns ownership via TaskUpdate 4. Worker completes, team lead validates changes 5. Agent identifies next wave (tasks #2 and #3 now unblocked) 6. Agent spawns two workers in parallel for Wave 2
Result: Multi-wave execution with fresh-context workers per wave, zero race conditions.
Direct Swarm Without Beads
User says: Create three tasks for API refactor, then /swarm
What happens: 1. User creates TaskList tasks with TaskCreate 2. Agent calls /swarm without beads integration 3. Agent identifies parallel tasks (no dependencies) 4. Agent spawns all three workers simultaneously 5. Workers execute atomically, report to team lead via SendMessage or task completion 6. Team lead validates all changes, commits once per wave
Result: Parallel execution of independent tasks using TaskList only.
---
Worktree Isolation (Multi-Epic Dispatch)
Read references/shared-checkout-discipline.md first when the target checkout (~/dev/<repo>) is shared with peer agents — it documents when worktrees are mandatory (vs. optional) and the three failure modes (branch-deletion data loss, swarm attribution confounded, destructive-recovery temptation) that motivate the discipline.
Read references/worktree-isolation.md when you need to dispatch workers across multiple epics or run waves with overlapping files — covers isolation semantics per backend, effort levels, post-spawn verification, manual worktree creation/routing/merge-back, the Merge Arbiter Protocol, cleanup, and the --worktrees / --no-worktrees parameters.
Worktree reaping (teardown). After a worker's PR is confirmed MERGED (gh pr view --json state = MERGED), reap its tree: git worktree remove <path> --force then git worktree prune. Leave unmerged-PR worktrees intact. Target zero orphaned worktrees — bound the live count to in-flight PRs. (The committed disposition gate scans the tracked file set, not live on-disk worktrees, so this teardown is the operational backstop.)
---
Troubleshooting
Read references/troubleshooting.md for full diagnostics.
| Problem | See |
|---|---|
| Worktree isolation did not engage | references/troubleshooting.md |
| Workers produce file conflicts | references/troubleshooting.md |
| Team creation fails | references/troubleshooting.md |
| Codex agents unavailable | references/troubleshooting.md |
| Workers timeout or hang | references/troubleshooting.md |
| gc backend detected but workers unresponsive | references/troubleshooting.md |
| Tasks assigned but workers never spawn | references/troubleshooting.md |
Related skills
- `/using-atm` — out-of-session ATM substrate when a swarm needs persistent panes and human attach/steer.
Reference Documents
- references/shared-checkout-discipline.md
- references/agent-genie-coordination-contract.md — Eight-field contract each parallel stream declares before claiming work- references/conflict-recovery.md
- references/cold-start-contexts.md
- references/backend-background-tasks.md
- references/backend-claude-teams.md
- references/backend-codex-subagents.md
- references/backend-inline.md
- references/claude-code-latest-features.md
- references/execution-steps.md
- references/local-mode.md
- references/ol-wave-integration.md
- references/ralph-loop-contract.md
- references/troubleshooting.md
- references/validation-contract.md
- references/worker-pitfalls.md
- references/worker-specs.md
- references/worktree-isolation.md
- ../shared/references/backend-background-tasks.md
- ../shared/references/backend-claude-teams.md
- ../shared/references/backend-codex-subagents.md
- ../shared/references/backend-inline.md
- ../shared/references/claude-code-latest-features.md
- references/pre-spawn-friction-gates.md
- references/scope-escape-template.md
- references/worker-pre-task-checks.md
- ../shared/references/ralph-loop-contract.md
Agent-Genie Coordination Contract
When two or more agent streams work in parallel against the same repo, each stream MUST state its coordination contract before landing any commit. The contract is not chat memory — it's an artifact each stream writes and checks. Without it, parallel streams collide on generated artifacts (registry.json, mkdocs nav, CLI docs, embedded copies) and one stream's "final regen" silently overwrites the other's work.
The Contract — Eight Required Fields
Each parallel agent stream declares, before claiming any work:
| Field | Example |
|---|---|
| Stream name | doctor, rpi, wireup |
| Branch name | feat/<type>/<bead>-<slug> |
| Base SHA | git rev-parse origin/main at stream start |
| Owned paths | cli/cmd/ao/doctor*.go, cli/internal/doctor/** |
| Forbidden paths | cli/cmd/ao/loop*.go (owned by sibling stream) |
| Shared generated files | registry.json, docs/contracts/context-map.md — declare which stream regenerates last |
| Handoff triggers | "ping <sibling> when tests/doctor/* green" |
| Closeout conditions | "PR merged + bead closed + <sibling> consumes my artifact" |
Write these to a coordination file the sibling stream can read — Agent Mail (mcp__mcp-agent-mail__send_message), a .agents/coordination/<topic>.md, or pinned in a shared NTM pane. Not in chat memory. Chat memory doesn't survive the handoff.
Why This Matters
Generated artifacts (registry.json, mkdocs nav, CLI docs, embedded hook copies) are produced by scripts that read the whole state of the repo. If two streams both run the regenerator at end-of-stream, the later run overwrites the earlier — silently, with a green diff. The "shared generated files" field is the load-bearing one: it names which stream is allowed to regen last, and the other stream must commit its work before the regen and skip the regen entirely.
Evidence (anchored)
"Parallel agent streams work reliably when each agent states branch
name, base SHA, owned paths, forbidden paths, shared generated files,
handoff triggers, and closeout conditions before landing. … This
prevents collisions on generated artifacts and lets one stream
unblock another without relying on ad hoc chat memory."
— .agents/learnings/2026-05-16-agent-genie-coordination-contract.md (post-mortem for soc-z3qo.1 / PR #285)
The empirical anchor: PR #285. The doctor stream owned doctor/canary drift; the RPI stream owned execution-packet files plus final registry.json regeneration. Each stream's contract was explicit about lanes. The streams committed in series; the registry regen happened exactly once at the end of the RPI stream. No collisions.
How To Apply
Before claiming work (each stream)
1. Read the bead for "owned files" / acceptance criteria. 2. Write your contract to one of:
- Agent Mail topic (
macro_prepare_threadthensend_message) .agents/coordination/<topic>.md(committed; visible to all streams
via the file system)
- NTM pane title or pinned message
3. Confirm receipt with sibling streams. Don't proceed until they have read and replied.
Sample contract block
## Stream: doctor (soc-z3qo.1)
- Branch: feat/doctor-soc-z3qo.1-rebuild
- Base SHA: abc1234
- Owned: cli/cmd/ao/doctor*.go, cli/internal/doctor/**, tests/doctor/**
- Forbidden: cli/cmd/ao/rpi*.go (rpi stream), .agents/rpi/** (rpi stream)
- Shared (I do NOT regen): registry.json, cli/docs/COMMANDS.md
- Handoff: ping #rpi-stream when tests/doctor/* green
- Closeout: PR merged + bead closed + rpi stream consumes my Healable traitDuring work
- Stay in your lane. If you discover scope outside your owned
paths, write a scope-escape note (see scope-escape-template.md). Do not edit.
- Don't run shared-file regenerators unless your contract names you
as the regen owner. Commit your non-generated edits, hand off, let the regen owner do the final pass.
- Re-read sibling contracts at each commit. If a sibling has moved
their boundary, your forbidden-paths list may have changed.
At closeout
- Confirm closeout conditions (PR merged, bead closed, artifact
consumed by sibling).
- Archive the contract file or mark the Agent Mail thread complete.
- If your stream produced a shared-file delta, name the SHA so the
sibling can rebase.
Failure Modes
- Implicit ownership. "I assumed they wouldn't touch registry.json"
— they did, and the regen overwrote your changes. The contract prevents this by making ownership explicit and writable.
- Chat memory only. "I told them in the NTM pane chat" — that
message scrolled off; the sibling claimed the path anyway. Contracts live in artifacts, not transient chat.
- Late contract. "I'll write the contract once I know what I'm
doing." By then you're already committing. Contracts go before claims.
- Closeout without confirmation. "I merged my PR; my work here is
done." If the sibling hasn't consumed your artifact, your closeout is premature; the bead may need to stay open until the consumer verifies.
Relation to Other Swarm Rules
This contract is separate from but composable with the other multi-agent swarm rules:
- Worktree isolation (
worktree-isolation.md) — physical
isolation of each stream's checkout
- Scope escape (
scope-escape-template.md) — what to do when you
discover work outside your lane
- Pre-spawn friction gates (
pre-spawn-friction-gates.md) — gates
that fire before a swarm even starts
The coordination contract is the operating protocol on top of those mechanics: even with worktree isolation, even with scope-escape templates, streams still collide on generated artifacts unless they declare ownership upfront.
See Also
worktree-isolation.md— physical isolation of each stream's checkoutscope-escape-template.md— what to do when scope creeps outside
the contract
pre-spawn-friction-gates.md— gates that fire before a swarm
even starts
agent-mailskill — primary medium for coordination contract delivery
Backend: Background Tasks (Fallback)
Concrete tool calls for spawning agents using Task(run_in_background=true). This is the last-resort fallback when neither Codex sub-agents nor Claude native teams are available.
When detected: Task tool is available but TeamCreate and spawn_agent are not.
Limitations:
- Fire-and-forget — no messaging, no redirect, no scope adjustment
- No inter-agent communication
- No debate mode (R2 requires messaging)
- No retry (must re-spawn from scratch)
- No graceful shutdown (only
TaskStop, which is lossy)
---
Spawn: Background Agents
Spawn agents with Task(run_in_background=true). Each call returns a task_id for later polling.
Council Judges
Task(
subagent_type="general-purpose",
run_in_background=true,
prompt="You are judge-1.\n\nYour perspective: Correctness & Completeness\n\n<PACKET>\n...\n</PACKET>\n\nWrite your verdict to .agents/council/2026-02-17-auth-judge-1.md\nThis is your ONLY output channel — there is no messaging.",
description="Council judge-1"
)
# Returns: task_id="abc-123"
Task(
subagent_type="general-purpose",
run_in_background=true,
prompt="You are judge-error-paths.\n\nYour perspective: Error Paths & Edge Cases\n\n<PACKET>...</PACKET>\n\nWrite your verdict to .agents/council/2026-02-17-auth-judge-error-paths.md",
description="Council judge-error-paths"
)
# Returns: task_id="def-456"Both Task calls go in the same message — they run in parallel.
Swarm Workers
Task(
subagent_type="general-purpose",
run_in_background=true,
prompt="You are worker-3.\n\nYour Assignment: Task #3: Add password hashing\n...\n\nWrite result to .agents/swarm/results/3.json\nDo NOT run git add/commit/push.",
description="Swarm worker-3"
)Research Explorers
Task(
subagent_type="Explore",
run_in_background=true,
prompt="Thoroughly investigate: authentication patterns...\n\nWrite findings to .agents/research/2026-02-17-auth.md",
description="Research explorer"
)---
Wait: Poll for Completion
Background tasks have no messaging. Poll with TaskOutput.
TaskOutput(task_id="abc-123", block=true, timeout=120000)
TaskOutput(task_id="def-456", block=true, timeout=120000)Or non-blocking check:
TaskOutput(task_id="abc-123", block=false, timeout=5000)After `TaskOutput` returns, verify the agent wrote its result file:
Read(".agents/council/2026-02-17-auth-judge-1.md")Timeout behavior: If timeout expires, TaskOutput returns with a timeout status — the agent may still be running. Recovery: 1. Check result file — agent may have written it but not finished cleanly 2. If result file exists → use it, TaskStop the agent 3. If no result file → agent failed silently. For council: proceed with N-1 verdicts, note in report. For swarm: add task back to retry queue, re-spawn a fresh agent. 4. Never assume TaskOutput completion means the result file was written — always verify
Fallback: If background tasks fail despite detection, fall back to inline mode. See backend-inline.md.
---
No Messaging
Background tasks cannot receive messages. This means:
- No debate R2 — judges get one round only
- No retry — if validation fails, re-spawn a new agent from scratch
- No scope adjustment — the prompt is final at spawn time
---
Cleanup
Background tasks self-terminate when done. For stuck tasks:
TaskStop(task_id="abc-123")This is lossy — partial work may be lost.
---
Key Rules
1. Filesystem is the only communication channel — agents write files, lead reads files 2. No messaging = no debate — --debate is unavailable with this backend 3. No retry = must re-spawn — failed agents get a fresh Task call, not a message 4. Always check result files — TaskOutput completion doesn't guarantee the agent wrote its file 5. Prefer native teams — this backend is strictly inferior; use it only as last resort
Backend: Claude Native Teams
Concrete tool calls for spawning agents using Claude Code native teams (TeamCreate + SendMessage + shared TaskList).
When detected: TeamCreate tool is available in your tool list.
---
Pre-Flight: Confirm Modern Claude Features
Before spawning teammates, verify feature readiness:
1. claude agents succeeds (custom agents discoverable) 2. Teammate profiles for write tasks declare isolation: worktree 3. Long-running teammates prefer background: true 4. Hooks include worktree lifecycle coverage (WorktreeCreate, WorktreeRemove) and config auditing (ConfigChange) where policy requires it
For canonical feature details, read: skills/shared/references/claude-code-latest-features.md.
---
Setup: Create Team
Every spawn session starts by creating a team. One team per wave (fresh context = Ralph Wiggum preserved; see skills/shared/references/ralph-loop-contract.md).
TeamCreate(team_name="council-20260217-auth", description="Council validation of auth module")TeamCreate(team_name="swarm-1739812345-w1", description="Wave 1: parallel implementation")Naming conventions:
- Council:
council-YYYYMMDD-<target> - Swarm:
swarm-<epoch>-w<wave> - Crank: delegates to swarm naming
Leader Contract (Native Teams)
Claude teams are leader-first orchestration:
1. One lead creates the team and assigns all work. 2. Teammates never self-assign from shared tasks. 3. Teammates report to lead via short SendMessage signals. 4. Lead reads result artifacts from disk, validates, and decides retries/escalation.
Recommended signal envelope (single-line JSON, under 100 tokens):
{"type":"completion|blocked|help_request","agent":"worker-3","task":"3","detail":"short status","artifact":".agents/swarm/results/3.json"}completion: task finished, artifact written. blocked: cannot proceed safely. help_request: teammate needs coordination or scope clarification.
Peer Messaging (Allowed, Lead-Controlled)
Native teams support direct teammate-to-teammate messaging. Use this only for coordination handoffs; keep messages thin and always copy the lead in follow-up summaries.
worker-2 -> worker-5: "Need auth schema constant name; please confirm from src/auth/schema.ts"
worker-5 -> lead: "Resolved peer question for worker-2; no scope change."---
Spawn: Create Workers/Judges
After TeamCreate, spawn each agent with Task(team_name=..., name=...). All agents in a wave spawn in parallel (single message, multiple tool calls).
Council Judges (parallel spawn)
Task(
subagent_type="general-purpose",
team_name="council-20260217-auth",
name="judge-1",
prompt="You are judge-1 on team council-20260217-auth.\n\nYour perspective: Correctness & Completeness\n\n<PACKET>\n...\n</PACKET>\n\nWrite your verdict to .agents/council/2026-02-17-auth-judge-1.md\nThen send a SHORT completion signal to the team lead (under 100 tokens).\nDo NOT include your full analysis in the message — the lead reads your file.",
description="Council judge-1"
)
Task(
subagent_type="general-purpose",
team_name="council-20260217-auth",
name="judge-error-paths",
prompt="You are judge-error-paths on team council-20260217-auth.\n\nYour perspective: Error Paths & Edge Cases\n\n<PACKET>\n...\n</PACKET>\n\nWrite your verdict to .agents/council/2026-02-17-auth-judge-error-paths.md\nThen send a SHORT completion signal to the team lead (under 100 tokens).",
description="Council judge-error-paths"
)Both Task calls go in the same message — they spawn in parallel.
Swarm Workers (parallel spawn)
Task(
subagent_type="general-purpose",
team_name="swarm-1739812345-w1",
name="worker-3",
prompt="You are worker-3 on team swarm-1739812345-w1.\n\nYour Assignment: Task #3: Add password hashing\n<description>...</description>\n\nInstructions:\n1. Execute your task — create/edit files as needed\n2. Write result to .agents/swarm/results/3.json\n3. Send a SHORT signal to team lead (under 100 tokens)\n4. Do NOT run git add/commit/push — the lead commits\n\nRESULT FORMAT:\n{\"type\":\"completion\",\"issue_id\":\"3\",\"status\":\"done\",\"detail\":\"one-line summary\",\"artifacts\":[\"path/to/file\"]}",
description="Swarm worker-3"
)
Task(
subagent_type="general-purpose",
team_name="swarm-1739812345-w1",
name="worker-5",
prompt="You are worker-5 on team swarm-1739812345-w1.\n\nYour Assignment: Task #5: Create login endpoint\n...",
description="Swarm worker-5"
)Research Explorers (read-only)
Task(
subagent_type="Explore",
team_name="research-20260217-auth",
name="explorer-1",
prompt="Thoroughly investigate: authentication patterns in this codebase\n\n...",
description="Research explorer"
)Use subagent_type="Explore" for read-only research agents. Use "general-purpose" for agents that need to write files.
---
Wait: Receive Completion Signals
Workers/judges send completion signals via SendMessage. These are automatically delivered to the team lead — no polling needed.
When a teammate finishes, their message appears as a new conversation turn. The lead reads result files from disk, NOT from message content.
# Teammate message arrives automatically:
# "judge-1: Done. Verdict: WARN, confidence: HIGH. File: .agents/council/2026-02-17-auth-judge-1.md"
# Lead reads the file for full details:
Read(".agents/council/2026-02-17-auth-judge-1.md")Timeout handling (default: 120s per round, 90s for debate R2):
If a teammate goes idle without sending a completion signal: 1. Check their result file — they may have written it but failed to message 2. If result file exists → read it and proceed (the message was the only thing missing) 3. If no result file → the agent failed silently. Recovery: proceed with N-1 judges/workers and note the failure in the report. For swarm workers, add the task back to the retry queue. 4. Never wait indefinitely — after the timeout, move on
See skills/council/references/cli-spawning.md for timeout configuration (COUNCIL_TIMEOUT, COUNCIL_R2_TIMEOUT).
Fallback: If native teams fail at runtime despite passing detection (e.g., TeamCreate succeeds but Task spawning fails), fall back to background tasks. See backend-background-tasks.md.
---
Message: Debate R2 / Retry
Send messages to specific teammates using SendMessage. Teammates wake from idle when messaged.
Council Debate R2
SendMessage(
type="message",
recipient="judge-1",
content="DEBATE ROUND 2\n\nOther judges' verdicts:\n- judge-error-paths: FAIL (HIGH confidence) — file: .agents/council/2026-02-17-auth-judge-error-paths.md\n\nRead the other judge's file. Revise your assessment considering their perspective.\nWrite your R2 verdict to .agents/council/2026-02-17-auth-judge-1-r2.md\nThen send a completion signal.",
summary="R2 debate instructions for judge-1"
)R2 timeout (default: 90s): If a judge doesn't respond to R2 within COUNCIL_R2_TIMEOUT, use their R1 verdict for consolidation. See skills/council/references/debate-protocol.md for full timeout handling.
Swarm Worker Retry
SendMessage(
type="message",
recipient="worker-3",
content="Validation failed: pytest tests/test_auth.py returned exit code 1.\nFix the failing tests and rewrite your result to .agents/swarm/results/3.json",
summary="Retry worker-3: test failure"
)---
Cleanup: Shutdown and Delete
After consolidation/validate, shut down all teammates then delete the team.
# Shutdown each teammate
SendMessage(type="shutdown_request", recipient="judge-1", content="Council complete")
SendMessage(type="shutdown_request", recipient="judge-error-paths", content="Council complete")
# After all teammates acknowledge shutdown:
TeamDelete()Reaper pattern: If a teammate doesn't respond to shutdown within 30s, proceed with TeamDelete() anyway.
If `TeamDelete` fails (e.g., stale members): clean up manually with rm -rf ~/.claude/teams/<team-name>/ then retry TeamDelete() to clear in-memory state.
---
Multi-Wave Pattern
For crank/swarm with multiple waves, create a new team per wave:
# Wave 1
TeamCreate(team_name="swarm-1739812345-w1", description="Wave 1")
# ... spawn workers, wait, validate, commit ...
# ... shutdown teammates ...
TeamDelete()
# If TeamDelete fails: rm -rf ~/.claude/teams/swarm-1739812345-w1/ then retry
# Wave 2 (fresh context)
TeamCreate(team_name="swarm-1739812345-w2", description="Wave 2")
# ... spawn workers for newly-unblocked tasks ...
TeamDelete()This ensures each wave's workers start with clean context (no leftover state from prior waves).
If `TeamDelete` fails between waves, the next TeamCreate may conflict. Always verify cleanup succeeded before creating the next wave team.
---
Key Rules
1. `TeamCreate` before `Task` — tasks created before the team are invisible to teammates — Enforcement: `safety.ValidateTeamLifecycle()` (T9) 2. Pre-assign tasks before spawning — workers do NOT race-claim from TaskList — Enforcement: documentation only 3. Lead-only commits — workers write files, lead runs git add + git commit — Enforcement: `hooks/git-worker-guard.sh` (T4) 4. Thin messages — workers send <100 token signals, full results go to disk — Enforcement: `safety.ValidateMessageSize()` (T9) 5. New team per wave — fresh context, Ralph Wiggum preserved — Enforcement: `safety.ValidateTeamLifecycle()` (T9) 6. Always cleanup — TeamDelete() after every wave, even on partial failure — Enforcement: `hooks/stop-team-guard.sh` + `safety.ValidateTeamLifecycle()` (T9)
Backend: Codex Sub-Agents
Concrete tool calls for spawning agents using Codex CLI (codex exec). Used for --mixed mode cross-vendor consensus and as the primary backend when running inside a Codex session with spawn_agent.
---
Variant A: Codex CLI (from any runtime)
Used when codex CLI is available on PATH. Agents run as background shell processes.
When detected: which codex succeeds.
Spawn: Background Shell Processes
# With structured output (preferred for council judges)
Bash(
command='codex exec -s read-only -m gpt-5.3-codex -C "$(pwd)" --output-schema skills/council/schemas/verdict.json -o .agents/council/codex-1.json "JUDGE PROMPT HERE"',
run_in_background=true
)
# Without structured output (fallback)
Bash(
command='codex exec --full-auto -m gpt-5.3-codex -C "$(pwd)" -o .agents/council/codex-1.md "JUDGE PROMPT HERE"',
run_in_background=true
)Flag order: -s/--full-auto → -m → -C → --output-schema → -o → prompt
Valid flags: --full-auto, -s, -m, -C, --output-schema, -o, --add-dir Invalid flags: -q (doesn't exist), --quiet (doesn't exist), -p as a prompt flag (in Codex CLI it means profile)
Wait: Poll Background Shell
TaskOutput(task_id="<shell-id>", block=true, timeout=120000)Then read the output file:
Read(".agents/council/codex-1.json")Limitations
- No messaging — Codex CLI processes are fire-and-forget
- No debate R2 with Codex judges — they produce one verdict only
--output-schemarequiresadditionalProperties: falseat all levels--output-schemarequires ALL properties inrequiredarray-s read-only+-oworks —-ois CLI-level post-processing, not sandbox I/O
---
Variant B: Codex Sub-Agents (inside Codex runtime)
Used when running inside a Codex session where spawn_agent is available.
When detected: spawn_agent tool is in your tool list.
Spawn
spawn_agent(message="You are judge-1.\n\nPerspective: Correctness & Completeness\n\n<PACKET>...</PACKET>\n\nWrite verdict to .agents/council/2026-02-17-auth-judge-1.md")
# Returns: agent_id
spawn_agent(message="You are worker-3.\n\nTask: Add password hashing\n...\n\nWrite result to .agents/swarm/results/3.json")
# Returns: agent_idWait
wait(ids=["agent-id-1", "agent-id-2"])Timeout: wait() blocks until completion. Set a timeout at the orchestration level (default: COUNCIL_TIMEOUT=120s). If an agent doesn't complete within the timeout, close_agent it and proceed with N-1 verdicts/workers.
Message (retry/follow-up)
send_input(id="agent-id-1", message="Validation failed: fix tests and retry")Cleanup
close_agent(id="agent-id-1")---
Mixed Mode (Council)
For --mixed council, spawn runtime-native judges AND Codex CLI judges in parallel:
# Claude native team judges (via TeamCreate — see backend-claude-teams.md)
Task(subagent_type="general-purpose", team_name="council-20260217-auth", name="judge-1", prompt="...", description="Judge 1")
Task(subagent_type="general-purpose", team_name="council-20260217-auth", name="judge-2", prompt="...", description="Judge 2")
# Codex CLI judges (parallel background shells)
Bash(command='codex exec -s read-only -m gpt-5.3-codex -C "$(pwd)" --output-schema skills/council/schemas/verdict.json -o .agents/council/codex-1.json "PACKET"', run_in_background=true)
Bash(command='codex exec -s read-only -m gpt-5.3-codex -C "$(pwd)" --output-schema skills/council/schemas/verdict.json -o .agents/council/codex-2.json "PACKET"', run_in_background=true)All four spawn in the same message — maximum parallelism.
Mixed mode quorum: At least 1 judge from each vendor should respond for cross-vendor consensus. If all judges from one vendor fail, proceed as single-vendor council and note the degradation in the report.
---
Key Rules
1. Pre-flight check: which codex before attempting Codex CLI spawning 2. Model availability: gpt-5.3-codex requires API account — fall back to gpt-4o if unavailable 3. Flag order matters — agents copy examples exactly 4. `codex review` is a different command with different flags — do not conflate with codex exec 5. No debate with Codex judges — they produce one verdict, Codex CLI has no messaging
Backend: Inline (No Spawn Available)
Degraded single-agent mode when no multi-agent primitives are detected. The current agent performs all work sequentially in its own context.
When detected: No spawn_agent, no TeamCreate, no Task tool available — or --quick flag was explicitly set.
---
Council: Single Inline Judge
Instead of spawning parallel judges, the lead evaluates from each perspective sequentially:
1. Build the context packet (same as multi-agent mode)
2. For each perspective:
a. Adopt the perspective mentally
b. Write findings to .agents/council/YYYY-MM-DD-<target>-<perspective>.md
3. Synthesize into final reportOutput format is identical — same file paths, same verdict schema. Downstream consumers (consolidation, report) don't know it was inline.
No debate available — debate requires messaging between agents.
---
Swarm: Sequential Execution
Instead of parallel workers, execute each task sequentially:
1. TaskList() — find unblocked tasks
2. For each unblocked task (in order):
a. Execute the task directly
b. Write result to .agents/swarm/results/<task-id>.json
c. TaskUpdate(taskId="<id>", status="completed")
3. Check for newly-unblocked tasks
4. Repeat until all tasks completeSame result files, same validation — just sequential.
Error handling: If a task fails mid-execution: 1. Write failure result to .agents/swarm/results/<task-id>.json with "status": "blocked" 2. Check if downstream tasks depend on it (blockedBy) 3. Skip blocked downstream tasks, mark as skipped 4. Continue with independent tasks that don't depend on the failed one
---
Research: Inline Exploration
Instead of spawning an Explore agent, perform the tiered search directly:
1. Read docs/code-map/ if present
2. Grep/Glob for relevant files
3. Read key files
4. Write findings to .agents/research/YYYY-MM-DD-<topic>.md---
Key Rules
1. Same output format — inline mode writes the same files as multi-agent mode 2. Same validation — all checks still apply 3. Slower but functional — no parallelism, but all skill capabilities preserved (except debate) 4. Inform the user — log "Running in inline mode (no multi-agent backend detected)"
Claude Code Latest Features Contract
This document is the shared source of truth for Claude Code feature usage across AgentOps skills.
Baseline
- Target Claude Code release family:
2.1.x - Last verified against upstream changelog:
2.1.75 - Changelog source:
https://raw.githubusercontent.com/anthropics/claude-code/main/CHANGELOG.md
Current Feature Set We Rely On
1. Core Slash Commands
Skills and docs should assume these commands exist and prefer them over legacy naming:
/agents/hooks/permissions/memory/mcp/output-style/effort— set model effort level (low/medium/high). Opus 4.6 defaults to medium./color— set prompt-bar color per session (useful for distinguishing parallel sessions)
Reference: https://code.claude.com/docs/en/slash-commands
2. Agent Definitions
For custom teammates in .claude/agents/*.md, use modern frontmatter fields where applicable:
modeldescriptiontoolsmemory(scope control)background: truefor long-running teammatesisolation: worktreefor safe parallel write isolation
Reference: https://code.claude.com/docs/en/sub-agents
3. Worktree Isolation
When parallel workers may touch overlapping files, prefer Claude-native isolation features first:
- Session-level isolation:
claude --worktree(-w) - Agent-level isolation:
isolation: worktree - Sparse checkout:
worktree.sparsePathssetting — limit worktree to relevant directories in large monorepos
If unavailable in a given runtime, fall back to manual git worktree orchestration.
Reference: changelog 2.1.49, 2.1.50, and 2.1.75.
4. Hooks and Governance Events
Hooks-based workflows should include modern event coverage:
WorktreeCreateWorktreeRemoveConfigChangeSubagentStopTaskCompletedTeammateIdlePostCompact— fires after session context compaction. Use for auto-recovery (e.g., re-inject context).InstructionsLoaded— fires when CLAUDE.md loads. Use for policy enforcement.
HTTP hooks: Hooks can POST JSON to a URL and receive JSON responses, in addition to shell script execution.
Use these for auditability, policy enforcement, and cleanup.
Reference: https://code.claude.com/docs/en/hooks
5. Settings Hierarchy
Skill guidance must respect settings precedence:
1. Enterprise managed policy 2. Command-line args 3. Local project settings 4. Shared project settings 5. User settings
Reference: https://code.claude.com/docs/en/settings
6. Agent Inventory Command
Use claude agents as the first CLI-level check to confirm configured teammate profiles before multi-agent runs.
Reference: changelog 2.1.50.
7. Session Management
--from-pr <url>— start or resume a session linked to a specific GitHub PR--worktree(-w) — start session in an isolated git worktree
Reference: https://code.claude.com/docs/en/cli-reference
8. Tool Enhancements
- Read tool:
pagesparameter for PDFs — read specific page ranges (e.g.,pages: "1-5"). Large PDFs (>10 pages) require this parameter. - Bash tool: Wildcard permission patterns —
Bash(npm *)orBash(* install)for flexible auto-approval.
9. Effort Levels
The /effort command controls model reasoning depth:
low— fast, shallow reasoning. Good for research/exploration agents.medium— balanced (Opus 4.6 default).high— deep reasoning. Good for implementation and complex debugging.
Skill recommendation: set effort per agent role — low for judges/explorers, high for implementors.
Skill Authoring Rules
1. Do not reference deprecated permission command names (/allowed-tools, /approved-tools). 2. Multi-agent skills (council, swarm, research, crank, codex-team) must explicitly point to this contract. 3. Prefer declarative agent isolation (isolation: worktree) over ad hoc branch/worktree shell choreography where runtime supports it. 4. Keep manual git worktree fallback documented for non-Claude runtimes. 5. For long-running explorers/judges/workers, document background: true as the default custom-agent policy. 6. Use /effort to right-size model reasoning per agent role when spawning multi-agent workflows.
Review Cadence
- Re-verify this contract when:
- Claude Code changelog introduces new
2.1.xor2.2.xentries - any skill adds or changes multi-agent orchestration
- hook event support changes
Cold-Start Execution Contexts
Every worker prompt must be self-contained. No prior session context assumed.
Problem
Workers spawned by /swarm (via Ralph Wiggum pattern) start with zero context. They don't know:
- What the project does or its conventions
- What other workers are doing in parallel
- What previous waves accomplished
- Which patterns or anti-patterns to follow
Workers that lack context produce code that doesn't match existing patterns, duplicates existing utilities, or violates conventions.
Solution: Self-Contained Worker Briefings
Every worker's TaskCreate description must include a cold-start context block that makes the worker fully autonomous.
Required Sections
## Context Brief (Read First)
### Project
<1-2 sentences: what the project does, primary language, key frameworks>
### Conventions
<3-5 bullet points: naming conventions, file organization, test patterns>
<Injected from standards skill for the detected language>
### This Task
<Issue description + acceptance criteria>
### File Scope
<Explicit list of files this worker owns — DO NOT touch files outside this list>
### Prior Wave Notes
<From SHARED_TASK_NOTES.md — discoveries from prior waves>
### Anti-Patterns (Do NOT)
- Do not create new utility functions without grepping for existing ones first
- Do not modify files outside your scope
- Do not add TODO comments — use bd for tracking
- <project-specific anti-patterns from learnings>How to Assemble
The orchestrator (crank/swarm lead) assembles the briefing. Workers never need to search for context.
# 1. Project context (cached, reuse across workers)
PROJECT_BRIEF="Go CLI tool (ao binary). Uses cobra for commands, viper for config."
# 2. Conventions (from standards skill, language-detected)
CONVENTIONS=$(cat skills/standards/references/go.md | head -30)
# 3. Task-specific (from issue/task description)
TASK_DESC=$(bd show "$TASK_ID" 2>/dev/null || echo "$TASK_DESCRIPTION")
# 4. File scope (from plan metadata)
FILE_SCOPE="cli/internal/goals/goals.go, cli/internal/goals/goals_test.go"
# 5. Prior wave notes
SHARED_NOTES=""
if [ -f .agents/crank/SHARED_TASK_NOTES.md ]; then
SHARED_NOTES=$(cat .agents/crank/SHARED_TASK_NOTES.md)
fi
# 6. Anti-patterns (from learnings with confidence >= 0.7)
ANTI_PATTERNS=$(grep -l "confidence: 0.[7-9]" .agents/learnings/*.md 2>/dev/null | \
xargs grep -A1 "title:" 2>/dev/null | grep "anti-pattern\|do not\|avoid" || echo "None")Size Budget
Target: 200-400 tokens for the context brief. Enough to orient; not enough to dominate the worker's context window.
| Section | Budget |
|---|---|
| Project | 20-30 tokens |
| Conventions | 50-80 tokens |
| Task | 50-100 tokens (varies) |
| File scope | 20-40 tokens |
| Prior wave notes | 30-50 tokens (summary) |
| Anti-patterns | 20-40 tokens |
If shared notes exceed budget, summarize to top 3 most relevant entries.
Integration Points
With /crank
Crank's Step 3b.1 (Build Context Briefing) should use this format. The ao lookup command produces a similar briefing — this reference standardizes the format for environments where ao is unavailable.
With /swarm
Swarm's worker dispatch should include the cold-start block in every TaskCreate. The swarm lead reads this reference and assembles the briefing before spawning.
With /implement
Individual /implement calls benefit from the same cold-start pattern when invoked by a fresh agent (e.g., from crank or via slash command in a new session).
Anti-Patterns
| Anti-Pattern | Why It Fails | Fix |
|---|---|---|
| "Read the codebase first" in worker prompt | Workers waste 50%+ of context on exploration | Provide the answers directly in the brief |
| Including full file contents | Token waste, workers read files anyway | Include paths only, let workers Read as needed |
| No file scope boundary | Workers modify unexpected files, causing conflicts | Always include explicit file ownership |
| Same brief for all workers | Irrelevant context wastes tokens | Customize conventions section per task type |
| Briefing > 500 tokens | Dominates worker context window | Summarize aggressively |
Merge Conflict Recovery Pattern
When parallel workers produce conflicting changes, capture context and retry intelligently.
Problem
Parallel workers in the same wave can produce merge conflicts when:
- File manifests were incomplete (worker touched unexpected files)
- Two workers independently refactored the same utility
- Import changes collide (both add imports to the same file)
- Test fixtures overlap
Current behavior: conflict = wave failure. No context preserved for retry.
Solution: Eviction + Context Capture
When a merge conflict occurs, capture the full context before evicting the conflicting change:
Step 1: Detect Conflict
# After worker completes, attempt merge
git merge --no-commit <worker-branch> 2>&1
if [ $? -ne 0 ]; then
CONFLICT_FILES=$(git diff --name-only --diff-filter=U)
echo "Merge conflict in: $CONFLICT_FILES"
fiStep 2: Capture Eviction Context
mkdir -p .agents/crank/conflicts
cat > ".agents/crank/conflicts/wave-${wave}-${TASK_ID}.json" <<EOF
{
"wave": ${wave},
"task_id": "${TASK_ID}",
"conflict_files": $(echo "$CONFLICT_FILES" | jq -R . | jq -s .),
"worker_branch": "${WORKER_BRANCH}",
"worker_diff_summary": "$(git diff --stat ${BASE_SHA}..${WORKER_BRANCH})",
"conflicting_with": "${MERGED_TASKS}",
"timestamp": "$(date -Iseconds)",
"resolution_strategy": null
}
EOF
# Abort the failed merge
git merge --abortStep 3: Classify Conflict
| Type | Signal | Resolution |
|---|---|---|
| Import collision | Only import blocks conflict | Auto-resolve: combine imports |
| Utility overlap | Both created similar helper function | Manual: pick one, delete other |
| Test fixture | testdata/ or _test.go conflicts | Auto-resolve: merge both fixtures |
| Logic conflict | Business logic in same function | Re-queue as serialized sub-wave |
| Formatting | Whitespace or formatting-only | Auto-resolve: run formatter after merge |
Step 4: Retry with Context
For the evicted task, re-queue with conflict context:
TaskCreate(
subject="RETRY: ${TASK_SUBJECT}",
description="${ORIGINAL_DESCRIPTION}\n\n---\n
CONFLICT CONTEXT (from wave ${wave}):
Your prior attempt conflicted with ${CONFLICTING_WITH} on files: ${CONFLICT_FILES}.
The other worker's changes have been merged. Your changes were evicted.
When re-implementing:
1. Read the current state of ${CONFLICT_FILES} (they now contain the other worker's changes)
2. Integrate your changes without overwriting theirs
3. If you need a utility they already created, use it instead of duplicating
Prior diff summary of your work:
${WORKER_DIFF_SUMMARY}"
)Integration with Swarm
Pre-Spawn Conflict Prevention
Before spawning workers, the conflict matrix from swarm/SKILL.md catches overlapping file manifests. This reference handles the cases that slip through (incomplete manifests, unexpected file touches).
Post-Wave Recovery Flow
Wave N workers complete
│
├── Merge worker 1 → SUCCESS
├── Merge worker 2 → CONFLICT with worker 1
│ ├── Capture eviction context
│ ├── Classify conflict type
│ ├── If auto-resolvable → resolve + merge
│ └── If not → evict + re-queue for next wave
│
└── Continue with remaining workersBudget
Each task gets max 1 conflict retry. If the retry also conflicts, classify as DECOMPOSE (needs manual split).
Metrics
Track in wave checkpoint:
{
"conflicts": {
"count": 1,
"auto_resolved": 0,
"evicted_requeued": 1,
"tasks_affected": ["ag-1234"]
}
}High conflict rates (>30% of wave tasks) signal poor file manifest quality. Log warning and suggest tighter pre-spawn conflict detection.
Swarm Execution Steps (Detailed)
This reference contains the detailed procedural steps for swarm execution (Steps 0 through 6). The SKILL.md billboard points here when you need concrete spawn/wait/message/cleanup procedures, file-manifest enforcement, conflict checks, and multi-wave base-SHA refresh logic.
Step 0: Detect Multi-Agent Capabilities (MANDATORY)
Use runtime capability detection, not hardcoded tool names. Swarm requires:
- Spawn parallel subagents — create workers that run concurrently
- Agent messaging (optional) — for coordination and retry
See skills/shared/SKILL.md for the capability contract.
After detecting your backend, read the matching reference for concrete spawn/wait/message/cleanup examples:
- Shared Claude feature contract →
skills/shared/references/claude-code-latest-features.md - Local mirrored contract for runtime-local reads →
claude-code-latest-features.md - Claude Native Teams →
backend-claude-teams.md - Codex Sub-Agents / CLI →
backend-codex-subagents.md - Background Tasks →
backend-background-tasks.md - Inline (no spawn) →
backend-inline.md
See also local-mode.md for swarm-specific execution details (worktrees, validation, git commit policy, wave repeat).
Step 0.5: Select Spawn Backend (Before Worker Dispatch)
Select the worker-dispatch backend by the ladder NTM > runtime-native > beads floor (see skills/shared/SKILL.md "Selection policy" for the canonical statement):
if [[ "${AGENTOPS_ORCHESTRATION:-}" == "off" ]]; then
SWARM_BACKEND="beads" # global opt-out — single-agent inline, work tracked via bd
elif command -v ntm &>/dev/null && ntm --robot-capabilities 2>/dev/null | jq -e '.spawn == true' >/dev/null 2>&1; then
SWARM_BACKEND="ntm" # top tier — capability-probed
else
SWARM_BACKEND="native" # runtime-native: Claude teams / Codex sub-agents; beads floor if neither
fiAGENTOPS_ORCHESTRATION=offis the global opt-out (mirrorsAGENTOPS_HOOKS_DISABLED=1): no spawn backend, degrade to the beads floor.SWARM_BACKEND="ntm": dispatch and monitor workers through NTM's robot API.SWARM_BACKEND="native": spawn via Claude Native Teams or Codex sub-agents per the runtime; if neither is available, fall to the beads floor (--quick).- Output-contract parity holds on every tier: workers write results to
.agents/swarm/results/, lead verifies-then-trusts. Workers already usebdfor issue tracking — no change needed.
`gc` is NOT a selectable backend (DEPRECATION). The Gas City (gc) CLI bridge was removed (soc-2rtm0);runtime=gcis rejected by the CLI (seeagentops/CLAUDE.md). TheSWARM_BACKEND="gc"dispatch block later in this file is retained for historical reference only — it is never selected. The top tier is NTM.
Step 1: Ensure Tasks Exist
Use TaskList to see current tasks. If none, create them:
TaskCreate(subject="Implement feature X", description="Full details...",
metadata={"issue_type": "feature", "files": ["src/feature_x.py", "tests/test_feature_x.py"], "validation": {...}})
TaskUpdate(taskId="2", addBlockedBy=["1"]) # Add dependencies after creationTask Typing + File Manifest
Every TaskCreate must include metadata.issue_type plus a metadata.files array. issue_type drives active constraint applicability and validation policy; files enable mechanical conflict detection before spawning a wave. This is how the prevention ratchet applies shift-left mechanically: active compiled findings use issue type plus changed files to decide whether a task should be blocked, warned, or left alone.
- Use canonical issue types:
feature,bug,task,docs,chore,ci. - Preserve the same
metadata.issue_typeon TaskUpdate / TaskCompleted payloads so task-validation can apply active constraints without guessing. - Pull file lists from the plan, issue description, or codebase exploration during planning.
- If you cannot enumerate files yet, add a planning step to identify them before spawning workers. An empty or missing manifest signals the need for more planning, not unconstrained workers.
- Workers receive the manifest in their prompt and are instructed to stay within it (see
local-mode.mdworker prompt template). - The worker prompt MUST include the
metadata.filesarray as the FILE MANIFEST section. Workers grep for existing function signatures before writing new code to avoid duplication. - Per-worker model/tool/prompt isolation specs: see `worker-specs.md` and `schemas/worker-spec.v1.schema.json`. When a wave's tasks declare a
metadata.worker_specreference, the spawned worker honors the named spec's model/tool/prompt allowlist instead of inheriting the lead agent's surface.
{
"issue_type": "feature",
"files": ["cli/cmd/ao/goals.go", "cli/cmd/ao/goals_test.go"],
"validation": {
"tests": "go test ./cli/cmd/ao/...",
"files_exist": ["cli/cmd/ao/goals.go"]
}
}Step 1a: Build Context Briefing (Before Worker Dispatch)
if command -v ao &>/dev/null; then
ao context assemble --task='<swarm objective or wave description>'
fiThis produces a 5-section briefing (GOALS, HISTORY, INTEL, TASK, PROTOCOL) at .agents/rpi/briefing-current.md with secrets redacted. Include the briefing path in each worker's TaskCreate description so workers start with full project context.
Output schema size guard: When 5+ workers in a wave share the same output schema (e.g., verdict.json), cache it to .agents/council/output-schema.json and reference by path instead of inlining ~500 tokens per worker. For ≤4 workers, inline is fine. See council skill's caching guidance reference for details.
Worker prompt signpost:
- Claude workers should include:
Knowledge artifacts are in .agents/. See .agents/AGENTS.md for navigation. Use \ao lookup --query "topic"\for learnings. - Codex workers cannot rely on
.agents/file access in sandbox. The lead should search.agents/learnings/for relevant material and inline the top 3 results directly in the worker prompt body.
Step 1.5: Auto-Populate File Manifests
Skip this step if all tasks already have populated `metadata.files` arrays.
If any task is missing its file manifest, auto-generate it before Step 2:
1. Spawn haiku Explore agents (one per task missing manifests) to identify files:
Agent(subagent_type="Explore", model="haiku",
prompt="Given this task: '<task subject + description>', identify all files
that will need to be created or modified. Return a JSON array of file paths.")2. Inject manifests back into tasks:
TaskUpdate(taskId=task.id, metadata={"files": [explored_files]})Once all tasks have manifests, proceed to Step 2 where the Pre-Spawn Conflict Check enforces file ownership.
Step 1.6: Advisory Bead Clustering
When tasks come from bd and scripts/bd-cluster.sh exists, run scripts/bd-cluster.sh --json 2>/dev/null || true before Step 2. Summarize any clusters as consolidation hints only; never run --apply here, and keep Step 2's file-manifest and dependency gates authoritative.
Step 2: Identify Wave
Pre-Spawn Friction Gates: Before spawning workers, execute all 6 friction gates (base sync, file manifest, dependency graph, misalignment breaker, wave cap, base-SHA ancestry). See pre-spawn-friction-gates.md.
Find tasks that are:
- Status:
pending - No blockedBy (or all blockers completed)
These can run in parallel.
Pre-Spawn Conflict Check
Before spawning a wave, scan all worker file manifests for overlapping files:
wave_tasks = [tasks with status=pending and no blockers]
all_files = {}
for task in wave_tasks:
for f in task.metadata.files:
if f in all_files:
CONFLICT: f is claimed by both all_files[f] and task.id
all_files[f] = task.idOn conflict detection:
- Serialize the conflicting workers into separate sub-waves (preferred -- simplest fix), OR
- Isolate them with worktree isolation (
--worktrees) so each operates on a separate branch.
Do not spawn workers with overlapping file manifests into the same shared-worktree wave. This is the primary cause of build breaks and merge conflicts in parallel execution.
Display ownership table before spawning:
File Ownership Map (Wave N):
┌─────────────────────────────┬──────────┬──────────┐
│ File │ Owner │ Conflict │
├─────────────────────────────┼──────────┼──────────┤
│ src/auth/middleware.go │ task-1 │ │
│ src/auth/middleware_test.go │ task-1 │ │
│ src/api/routes.go │ task-2 │ │
│ src/config/settings.go │ task-1,3 │ YES │
└─────────────────────────────┴──────────┴──────────┘
Conflicts: 1 (resolved: serialized task-3 into sub-wave 2)Test File Naming Validation
When workers create new test files, validate naming against loaded standards:
1. Detection: Same language detection as /crank (go.mod → Go, pyproject.toml → Python, etc.) 2. Validation: Load the Testing section of the relevant standard. For Go, this means:
- New test files must match
<source>_test.goor<source>_extra_test.go - Reject
cov*_test.goor arbitrary prefixes
3. Serial-first for monolith packages: If multiple workers target the same package AND that package has a shared testutil_test.go or >5 existing test files, force serial execution within that package.
Step 2.5: Pre-Spawn Base-SHA Refresh (Multi-Wave Only)
When executing wave 2+ (not the first wave), verify workers branch from the latest commit — not a stale SHA from before the prior wave's changes were committed.
# PSEUDO-CODE
# Capture current HEAD after prior wave's commit
CURRENT_SHA=$(git rev-parse HEAD)
# If using worktrees, verify they're up to date
if [[ -n "$WORKTREE_PATH" ]]; then
(cd "$WORKTREE_PATH" && git pull --rebase origin "$(git branch --show-current)" 2>/dev/null || true)
fiCross-reference prior wave diff against current wave file manifests:
# PSEUDO-CODE
# Files changed in prior wave
PRIOR_WAVE_FILES=$(git diff --name-only "${WAVE_START_SHA}..HEAD")
# Check for overlap with current wave manifests
for task in $WAVE_TASKS; do
TASK_FILES=$(echo "$task" | jq -r '.metadata.files[]')
OVERLAP=$(comm -12 <(echo "$PRIOR_WAVE_FILES" | sort) <(echo "$TASK_FILES" | sort))
if [[ -n "$OVERLAP" ]]; then
echo "WARNING: Task $task touches files modified in prior wave: $OVERLAP"
echo "Workers MUST read the latest version (post-prior-wave commit)"
fi
doneWhy: Without base-SHA refresh, wave 2+ workers may read stale file versions from before wave 1 changes were committed. This causes workers to overwrite prior wave edits or implement against outdated code. See crank Step 5.7 (wave checkpoint) for the SHA tracking pattern.
Steps 3-6: Spawn Workers, Validate, Finalize
For detailed local mode execution (team creation, worker spawning, race condition prevention, git commit policy, validation contract, cleanup, and repeat logic), read `local-mode.md`.
Platform pitfalls: Include relevant pitfalls from worker-pitfalls.md in worker prompts for the target language/platform. For example, inject the Bash section for shell script tasks, the Go section for Go tasks, etc. This prevents common worker failures from known platform gotchas.Pre-task checks: Inject the Quick-Reference Inject Block from worker-pre-task-checks.md into every worker dispatch prompt — grep-for-existing-impls, file-manifest existence, deletion-adjacent symbol verify. Prevents workers from duplicating existing utilities or operating on stale plan symbols.gc Worker Dispatch — DEPRECATED, historical reference only
gc tier removed (soc-2rtm0); retained for historical reference only — NOT selected. The Gas City (gc) CLI bridge was severed andruntime=gcis rejected by the CLI (seeagentops/CLAUDE.md). Step 0.5 never setsSWARM_BACKEND="gc". The top tier is NTM. The block below documents the old gc dispatch shape for archival purposes only — do not select or invoke it.
When gc was the selected backend (no longer reachable), dispatch and monitoring went through gc sessions instead of Claude teams or Codex sub-agents:
# Dispatch a task to a gc-managed worker
gc session nudge <worker-alias> "Implement task #<id>: <subject>. Files: <manifest>. Write results to .agents/swarm/results/<id>.json"
# Monitor worker progress
gc session peek <worker-alias> --lines 50
# Check all worker statuses
gc status --json | jq '.sessions[] | {alias, state, last_activity}'gc dispatch follows the same orchestration contract as native backends:
- Pre-assigned tasks (mayor assigns before nudge)
- File manifest enforcement (included in nudge prompt)
- Results written to
.agents/swarm/results/<id>.json - Lead-only commit policy (workers do not commit)
- Scope-escape protocol (workers append to
.agents/swarm/scope-escapes.jsonl)
gc-specific behaviors:
- Worker lifecycle managed by gc pool auto-scaling — no explicit cleanup needed
- Use
gc session peekfor progress checks instead ofSendMessage/send_input - If a worker is idle or unresponsive,
gc session nudgecan re-prompt it - gc sessions persist across waves — the same worker alias can be reused without respawning
Swarm Local Mode: Runtime-Aware Detailed Execution
Context Budget Rule
Workers write results to disk. The orchestrator reads only thin status files.
>
When N workers finish, their full output (file reads, tool calls, reasoning) must NOT flood back into the orchestrator context. This is the #1 cause of context explosion in multi-wave epics.
Result protocol: 1. Workers write .agents/swarm/results/<task-id>.json on completion 2. Orchestrator checks for result files (Glob/Read), NOT full Task/SendMessage output 3. SendMessage used only for coordination signals (blocked, need help) — kept under 100 tokens 4. Task tool return values are acknowledged but NOT parsed for work details
# Orchestrator creates result directory before spawning
mkdir -p .agents/swarm/resultsStep 2a: Pre-Wave Gate Snapshot (Lead Protocol)
Before spawning any wave whose validation ends at a repo-level CI gate, snapshot the pre-existing FAIL set so post-wave triage can mechanically distinguish swarm-introduced failures from stale breakage on main.
# Before spawn
scripts/pre-push-gate.sh --fast 2>&1 | sed 's/\x1b\[[0-9;]*m//g' | grep -E "^FAIL " | sort > /tmp/pre-wave-fails.txt
# After cleanup
scripts/pre-push-gate.sh --fast 2>&1 | sed 's/\x1b\[[0-9;]*m//g' | grep -E "^FAIL " | sort > /tmp/post-wave-fails.txt
# Swarm-introduced failures (only present post-wave)
comm -13 /tmp/pre-wave-fails.txt /tmp/post-wave-fails.txtThe output of the final comm is the authoritative diff. Failures in /tmp/pre-wave-fails.txt that remain in /tmp/post-wave-fails.txt are pre-existing and should be filed as a separate follow-up rather than fixed inline, which keeps the wave's scope honest.
Skip this step when main is mandated green before spawn (stricter protocol) or when the wave's validation does not run the gate.
Origin: internal learning note 2026-04-15-pre-wave-gate-snapshot captured during swarm validation.
Step 2b: Pre-Spawn Worktree Setup (Multi-Epic Waves)
Skip this step for single-epic waves or when --no-worktrees is set.Required for multi-epic dispatch or when --worktrees is set.Evidence: shared-worktree multi-epic dispatch produced build breaks and algorithm duplication (.agents/evolve/dispatch-comparison.md).
Claude-Native Isolation (preferred when available)
If running in Claude runtime with modern agent definitions, prefer declarative isolation first:
1. Confirm teammate profiles with claude agents 2. Use teammate definitions that set isolation: worktree 3. For long-running workers, set background: true
Only fall back to manual git worktree management when declarative isolation is unavailable.
Detection
# Multi-epic: check if tasks span more than one epic prefix
# If wave tasks have subjects like "[ol-527] ..." and "[ol-531] ...", use worktrees.
# Single-epic: tasks share one prefix (e.g., all ol-527.*) → shared worktree OK.Create Worktrees
# For each epic ID in the wave:
git worktree add /tmp/swarm-<epic-id> -b swarm/<epic-id>Track the mapping:
epic_worktrees = {
"<epic-id>": "/tmp/swarm-<epic-id>",
...
}Also record worker ownership for deterministic routing and conflict arbitration:
owner_worktrees = {
"worker-<task-id>": "/tmp/swarm-<epic-id>",
...
}Runtime worktreePath Contract (Ownership-Aware Isolation)
When using declarative isolation (isolation: worktree), the lead must verify each spawned worker reports a worktreePath and that it matches owner_worktrees.
1. At spawn time, record expected owner -> path mapping (owner_worktrees). 2. On worker completion, read runtime Task result and extract worktreePath. 3. Validate:
worktreePathexists on diskworktreePathequals the expected path for that worker- File ownership still maps to a single worker/worktree for that wave
4. If worktreePath is missing or mismatched, treat isolation as failed:
- abort overlapping-file parallel merge flow
- requeue conflicting tasks into a serialized fix-up order
- proceed only after ownership/worktree mapping is unambiguous
Example verification:
test -n "$worktreePath" && test -d "$worktreePath" && git -C "$worktreePath" rev-parse --is-inside-work-treeInject into Worker Prompts
Each worker prompt must include:
WORKING DIRECTORY: /tmp/swarm-<epic-id>
All file reads, writes, and edits MUST use absolute paths rooted at /tmp/swarm-<epic-id>.
Do NOT operate on the main repo directly.
Result file: write to <main-repo>/.agents/swarm/results/<task-id>.json (always main repo path).Merge-Back After Validation
After each worker's task passes validation:
# From main repo:
git merge --no-ff swarm/<epic-id> -m "chore: merge swarm/<epic-id>"
git worktree remove /tmp/swarm-<epic-id>
git branch -d swarm/<epic-id>Merge order must respect task blockedBy dependencies.
---
Step 3: Spawn Workers
Use whatever multi-agent primitives your runtime provides to spawn parallel workers. Each worker receives a pre-assigned task in its prompt.
Model Selection
Workers should use sonnet (not opus) to minimize cost. The orchestrator (lead) stays on opus for coordination and validation.
When spawning via the Task tool, pass model: "sonnet". When spawning via native teams, teammates inherit from the session model unless overridden — set COUNCIL_CLAUDE_MODEL=sonnet or use model: "sonnet" in the Task call. For longer tasks, prefer teammate profiles with background: true.
| Role | Model | Rationale |
|---|---|---|
| Lead/orchestrator | opus (session default) | Coordination, validation, state management |
| Workers | sonnet | Focused single-task execution, 3-5x cheaper |
| Explorers | sonnet | Read-only search tasks |
Spawn Protocol
For each ready task:
1. Pre-assign — Mark the task owned by worker-<task-id> before spawning (prevents race conditions) 2. Spawn — Create a parallel subagent with the worker prompt (see below) 3. Track — Map worker-<task-id> to agent handle for waits/retries/cleanup
All workers in a wave spawn in parallel. New team/agent-group per wave = fresh context (Ralph Wiggum preserved).
Worker Prompt Template
Every worker receives this prompt (adapt to your runtime's spawn mechanism):
You are worker-<task-id>.
Your Assignment: Task #<id>: <subject>
<description>
FILE MANIFEST (files you are permitted to modify):
<list of files from plan — one per line>
You MUST NOT modify files outside this manifest. If you need to read other files for context, that is fine.
If your task requires modifying a file not in this manifest, write a blocked result instead.
Instructions:
1. Execute your pre-assigned task independently — create/edit files as needed, verify your work
2. Write your result to .agents/swarm/results/<task-id>.json (see format below)
3. Send a SHORT completion signal to the lead (under 100 tokens)
4. If blocked, write blocked result to same path and signal the lead
RESULT FILE FORMAT (MANDATORY — write this BEFORE sending any signal):
On success:
{"type":"completion","issue_id":"<task-id>","status":"done","detail":"<one-line summary max 100 chars>","artifacts":["path/to/file1","path/to/file2"],"worktreePath":"<absolute-worktree-path-or-empty>"}
If blocked:
{"type":"blocked","issue_id":"<task-id>","status":"blocked","detail":"<reason max 200 chars>","worktreePath":"<absolute-worktree-path-or-empty>"}
CONTEXT BUDGET RULE:
Your message to the lead must be under 100 tokens.
Do NOT include file contents, diffs, or detailed explanations in messages.
The result JSON file IS your full report. The lead reads the file, not your message.
PRE-IMPLEMENTATION CHECKLIST:
Before writing new code, grep for existing function signatures in the codebase to avoid
duplicating functionality that already exists. For example:
grep -r "func.*FunctionName" . --include="*.go"
grep -r "def function_name" . --include="*.py"
This prevents duplicate implementations and ensures you extend rather than re-create.
CONDITIONAL PREFLIGHT CHECKS (keyed on task + manifest):
1) Flag-collision preflight — Task says "add --<name> flag" AND manifest touches a cobra file:
Before writing the registration, grep the target file and parent command for the name.
On collision, pick an alternative and note it in your result.detail.
Example: grep -nE '"(<name>)"' <target.go> <parent_cmd.go>
Source: .agents/learnings/2026-04-15-swarm-flag-collision-preflight.md
2) Codex parity audit — Manifest includes any file under `skills-codex/`:
After edits, run: bash scripts/audit-codex-parity.sh --skill <skill>
Resolve all CLAUDE_PRIMITIVE_LEAKAGE and residual-mixed-runtime-marker findings
(substitute runtime-agnostic terms) before reporting done.
Source: .agents/learnings/2026-04-15-codex-mirror-runtime-string-lint.md
3) Post-edit sync-script runs — Apply drift in your worktree so the lead's cherry-pick
lands it atomically. Workers still do NOT commit.
(a) Manifest has `cli/cmd/ao/*.go` AND task adds a cobra flag:
scripts/generate-cli-reference.sh && git diff --exit-code cli/docs/COMMANDS.md
(b) Manifest has any `skills-codex/` file:
bash scripts/regen-codex-hashes.sh && git diff --exit-code skills-codex/
If the diff is non-empty after the script runs, that IS the sync artifact — leave it
staged in the worktree and list the touched paths in result.artifacts.
Source: .agents/learnings/2026-04-15-post-wave-sync-scripts-are-in-scope.md
4) CI-policy parity preflight — Manifest includes any `.github/workflows/*.yml` file:
The lead's wave-acceptance step runs `bash scripts/validate-ci-policy-parity.sh`
when workflow YAML changes are detected. Before signaling done:
- If you added/renamed a job in validate.yml, also update `summary.needs:` AND
the `### CI Jobs and What They Check` table in `AGENTS.md` (mark `(non-blocking)`
if the job has `continue-on-error: true`).
- Sanity-run locally: `bash scripts/validate-ci-policy-parity.sh` should exit 0.
- If you cannot align all three surfaces (e.g., AGENTS.md is outside your manifest),
write a blocked result with `SCOPE-ESCAPE: AGENTS.md needed for CI parity`.
Motivation: commit c587b361 was a manual fix after soc-lmww1 drifted the three
surfaces. This preflight prevents recurrence at worker time, not just wave time.
See skills/crank/references/wave-patterns.md "CI-Policy Parity Gate".
Rules:
- Work only on YOUR pre-assigned task
- Do NOT claim other tasks
- Do NOT message other workers
- Do NOT run git add, git commit, or git push — the lead commitsScope-Escape Protocol: When a worker needs to modify files outside its manifest:
>
1. Write a blocked result: {"type":"blocked","issue_id":"<id>","status":"blocked","detail":"SCOPE-ESCAPE: <file> needed because <reason>"}2. Do NOT modify the out-of-scope file or work around the constraint
3. The lead evaluates scope-escape requests between waves and either adds the file to a future wave's manifest or rejects with guidance
Orchestrator note — populating the FILE MANIFEST: When building each worker prompt, replace
<list of files from plan — one per line> with the explicit file paths assigned to that task inyour plan. Pull these from the task's metadata.files field if present, or derive them from thetask description during planning. Example populated manifest:
>
```
FILE MANIFEST (files you are permitted to modify):
src/middleware/auth.py
tests/test_auth.py
```
>
If the plan does not yet enumerate files, add a planning step to identify them before spawning
workers. An empty or missing manifest is a signal to pause and plan further — not to let workers
operate unconstrained.
Race Condition Prevention
Workers do NOT race-claim tasks from TaskList. The team lead assigns each task to a specific worker BEFORE spawning. This prevents:
- Two workers claiming the same task
- Workers seeing stale TaskList state
- Non-deterministic assignment order
Workers only transition their assigned task: in_progress -> completed.
Git Commit Policy
Workers MUST NOT commit. The team lead is the sole committer.
| Actor | Git Permissions |
|---|---|
| Team lead (mayor) | git add, commit, push |
| Workers | Read-only git. Write files only. |
Rationale:
- Workers share a worktree (per native teams semantics research)
- Concurrent git add/commit from multiple workers corrupts the index
- Lead-only commits ensure atomic, reviewable changesets per wave
Worker instructions: Include in every worker prompt: "Do NOT run git add, git commit, or git push. Write your result to .agents/swarm/results/<task-id>.json, then send a short signal (under 100 tokens) via your runtime channel. The team lead reads result files, not messages."
Wave Commit Cadence
Best practice: one commit per completed wave (not one massive commit for the entire swarm run).
| Cadence | When to use | Commit message format |
|---|---|---|
| Per wave (default) | Standard swarm execution | chore(wave-N): close ag-xxxx, ag-yyyy |
Per task (--per-task-commits) | When per-task attribution is required (audits, blame tracking) | chore(ag-xxxx): <task subject> |
| End of swarm | Never recommended — loses wave attribution and makes rollback harder | - |
Why per-wave: Each wave is an atomic unit of parallel work. A single commit per wave provides:
- Clean rollback boundary (revert one wave without touching others)
- Clear attribution of which wave introduced a change
- Issue IDs in commit message for traceability
Commit message convention:
chore(wave-1): close ag-1234, ag-1235
- ag-1234: Add authentication middleware
- ag-1235: Create user model schemaThe lead commits after all tasks in a wave pass validation (Step 4a), before spawning the next wave.
Step 4: Wait for Completion
Wait for all workers to signal completion using your runtime's wait mechanism. Workers write result files to disk and send a minimal signal.
Result data — always read from disk, never from agent messages:
Check .agents/swarm/results/<task-id>.json for each worker. These are ~200 bytes each. Do NOT parse agent messages or return values for work details — they contain the worker's full conversation (5-20K tokens per worker) and will explode the lead's context.
CRITICAL: Do NOT mark complete yet — validation required first.
Step 4a: Validate Before Accepting (MANDATORY)
TRUST ISSUE: Agent completion claims are NOT trusted. Verify then trust.
The Validation Contract: Before marking any task complete, Mayor MUST run validation checks. See skills/shared/validation-contract.md for full specification.
Validation flow:
<task-notification> arrives
|
v
RUN VALIDATION
|
+---+---+
| |
PASS FAIL
| |
v v
complete retry/escalateFor each completed task notification:
1. Check task metadata for validation requirements:
TaskList() -> find task -> check metadata.validation2. Execute validation checks (in order):
| Check Type | Command | Pass Condition |
|---|---|---|
files_exist | ls -la <paths> | All files exist |
command | Run specified command | Exit code 0 |
content_check | grep <pattern> <file> | Pattern found |
tests | <test_command> | Tests pass |
lint | <lint_command> | No errors |
3. On validation PASS:
TaskUpdate(taskId="<id>", status="completed")4. On validation FAIL:
- Increment retry count for task
- If retries < MAX_RETRIES (default: 3): send a follow-up message to the worker via your runtime's messaging mechanism: "Validation failed: <specific failure>. Fix and retry."
- If retries >= MAX_RETRIES: mark task as blocked and escalate to user
Minimal validation (when no metadata):
If task has no explicit validation requirements, apply default checks:
# Check that worker wrote the expected files
git status --porcelain # Should show unstaged changes from worker
# Check for obvious failures in recent output
# (agent should not have ended with errors)Example task with validation metadata:
TaskCreate(
subject="Add authentication middleware",
description="...",
metadata={
"validation": {
"files_exist": ["src/middleware/auth.py", "tests/test_auth.py"],
"command": "pytest tests/test_auth.py -v",
"content_check": {"file": "src/middleware/auth.py", "pattern": "def authenticate"}
}
}
)Step 5: Review & Finalize
When workers complete AND pass validation: 1. Check git status for changes (workers wrote files but did not commit) 2. Review diffs 3. Run any additional tests/validation 4. Team lead commits all changes for the wave (sole committer)
Step 5a: Post-Merge Naming Cleanup
After merging worker output, scan for scaffolding-era naming conventions introduced by parallel workers (e.g., TestCov_ prefixes, cov*_test.go file names). Rename to follow project conventions. Run go vet ./... (or equivalent linter) to catch naming inconsistencies before committing.
Step 5b: Cleanup
After wave completes:
# Clean up result files from this wave (prevent stale reads in next wave)
rm -f .agents/swarm/results/*.jsonShut down all workers via your runtime's cleanup mechanism. Then clean up the agent group/team.
Reaper Cleanup Pattern
Cleanup MUST succeed even on partial failures:
1. Request graceful shutdown for each worker 2. Wait up to 30s for acknowledgment 3. If any worker doesn't respond, log warning, proceed anyway 4. Always run cleanup — lingering agents pollute future sessions
Timeout Configuration
| Timeout | Default | Description |
|---|---|---|
| Worker timeout | 180s | Max time for worker to complete its task |
| Shutdown grace period | 30s | Time to wait for shutdown acknowledgment |
| Wave timeout | 600s | Max time for entire wave before forced cleanup |
Step 6: Repeat if Needed
If more tasks remain: 1. Check TaskList for next wave 2. Spawn a NEW wave worker set (new sub-agents or new team) for fresh context 3. Execute the next wave 4. Continue until all done
Partial Completion
Worker timeout: 180s (3 minutes) default per worker.
Timeout behavior: 1. Log warning: "Worker {name} timed out on task {id}" 2. Mark task as failed with reason "timeout" 3. Add to retry queue for next wave 4. Continue with remaining workers
Quorum: Swarm does not require quorum -- each worker is independent. Each completed task is accepted individually.
OL Wave Integration
When /swarm --from-wave <json-file> is invoked, the swarm reads wave data from an OL hero hunt output file and executes it with completion backflow to OL.
Pre-flight
# --from-wave requires ol CLI on PATH
which ol >/dev/null 2>&1 || {
echo "Error: ol CLI required for --from-wave. Install ol or use swarm without wave integration."
exit 1
}If ol is not on PATH, exit immediately with the error above. Do not fall back to normal swarm mode.
Input Format
The --from-wave JSON file contains ol hero hunt output:
{
"wave": [
{"id": "ol-527.1", "title": "Add auth middleware", "spec_path": "quests/ol-527/specs/ol-527.1.md", "priority": 1},
{"id": "ol-527.2", "title": "Fix rate limiting", "spec_path": "quests/ol-527/specs/ol-527.2.md", "priority": 2}
],
"blocked": [
{"id": "ol-527.3", "title": "Integration tests", "blocked_by": ["ol-527.1", "ol-527.2"]}
],
"completed": [
{"id": "ol-527.0", "title": "Project setup"}
]
}Execution
1. Parse the JSON file and extract the wave array.
2. Create TaskList tasks from wave entries (one TaskCreate per entry):
for each entry in wave:
TaskCreate(
subject="[{entry.id}] {entry.title}",
description="OL bead {entry.id}\nSpec: {entry.spec_path}\nPriority: {entry.priority}\n\nRead the spec file at {entry.spec_path} for full requirements.",
metadata={
"issue_type": entry.issue_type,
"ol_bead_id": entry.id,
"ol_spec_path": entry.spec_path,
"ol_priority": entry.priority
}
)3. Execute swarm normally on those tasks (Step 2 onward from main execution flow). Tasks are ordered by priority (lower number = higher priority).
4. Completion backflow: After each worker completes a bead task AND passes validation, the team lead runs the OL ratchet command to report completion back to OL:
# Extract quest ID from bead ID (e.g., ol-527.1 -> ol-527)
QUEST_ID=$(echo "$BEAD_ID" | sed 's/\.[^.]*$//')
ol hero ratchet "$BEAD_ID" --quest "$QUEST_ID"Ratchet result handling:
| Exit Code | Meaning | Action |
|---|---|---|
| 0 | Bead complete in OL | Mark task completed, log success |
| 1 | Ratchet validation failed | Mark task as failed, log the validation error from stderr |
5. After all wave tasks complete, report a summary that includes both swarm results and OL ratchet status for each bead.
Example
/swarm --from-wave /tmp/wave-ol-527.json
# Reads wave JSON -> creates 2 tasks from wave entries
# Spawns workers for ol-527.1 and ol-527.2
# On completion of ol-527.1:
# ol hero ratchet ol-527.1 --quest ol-527 -> exit 0 -> bead complete
# On completion of ol-527.2:
# ol hero ratchet ol-527.2 --quest ol-527 -> exit 0 -> bead complete
# Wave done: 2/2 beads ratcheted in OLPre-Spawn Friction Gates
From swarm friction analysis of 14,753 sessions. Git sync conflicts rose from 71 to 82.6 per 1K sessions (Jan → Feb).
58% of friction is addressable with process gates, not model improvements.
Pre-Spawn Checklist (Mandatory)
Before spawning ANY worker (team agent, Codex sub-agent, or worktree agent):
Gate 1: Base Branch Sync
git fetch origin && git diff --stat HEAD origin/$(git branch --show-current)If there are upstream changes, rebase/merge BEFORE spawning. Stale base branches cause 82.6/1K merge conflicts.
Gate 2: File Ownership Manifest
Before spawning, generate an explicit file ownership manifest:
Worker A owns: cli/cmd/ao/goals.go, cli/cmd/ao/goals_test.go
Worker B owns: skills/plan/SKILL.md, skills/plan/references/
Worker C owns: hooks/session-start.shRule: No file may appear in two workers' manifests. If two tasks touch the same file, combine them into one worker.
Gate 3: Dependency Graph Verification
Verify no worker depends on another worker's output:
Worker A: independent (no deps)
Worker B: independent (no deps)
Worker C: depends on Worker A output → MOVE TO WAVE 2Workers with dependencies go in later waves. Never spawn dependent workers in the same wave.
Gate 4: 15-Minute Misalignment Circuit Breaker
Set a timer. If a worker hasn't produced its first meaningful output (commit, test result, or file change) within 15 minutes:
1. Check if the worker is stuck in research/planning loop 2. If stuck: kill and re-scope with smaller task 3. If making progress: extend timer by 15 minutes
Gate 5: Wave Size Cap
Maximum 4 workers per wave. Evidence: waves of 5+ have exponentially higher merge conflict rates. If you have 6 tasks, split into Wave 1 (4 workers) + Wave 2 (2 workers).
Gate 6: Worktree Base-SHA Ancestry
Before spawning worktree-isolated workers, verify the worktree branch base is a direct ancestor of main HEAD. A worktree branch rooted off a non-main commit pulls unintended branch ancestry during merge-back, causing extra files to land.
# PSEUDO-CODE
MAIN_HEAD=$(git rev-parse main)
for WORKTREE_BRANCH in $WORKTREE_BRANCHES; do
if ! git merge-base --is-ancestor "$MAIN_HEAD" "$WORKTREE_BRANCH" 2>/dev/null; then
echo "WARN: $WORKTREE_BRANCH is not based on main HEAD ($MAIN_HEAD)"
echo " Single-commit branch: prefer cherry-pick over merge for merge-back"
echo " Multi-commit branch: git rebase main $WORKTREE_BRANCH before merge"
fi
doneResolution guidance:
- Single-commit worktree branches: Use
git cherry-pick <sha>instead ofgit merge --no-ffduring merge-back. Cherry-pick applies only the commit's diff, avoiding unintended ancestry. - Multi-commit worktree branches: Run
git rebase main <branch>before merging back. This re-roots the branch onto current main HEAD and eliminates stale ancestry.
Post-Spawn Gates
After Each Worker Completes
1. Run the external gate command (not worker self-report) 2. Check for file conflicts with other workers' outputs 3. If conflicts: use merge arbiter (see references/conflict-recovery.md)
After Each Wave Completes
1. Merge all worker outputs to base branch 2. Run full test suite on merged result 3. Refresh base SHA before spawning next wave 4. Re-evaluate remaining tasks (some may be unnecessary after Wave N results)
Anti-Patterns
- ❌ Spawning workers without checking base branch freshness
- ❌ Two workers editing the same file "they'll figure it out"
- ❌ Spawning 8 workers at once for "maximum parallelism"
- ❌ Worker A depends on Worker B's output in the same wave
- ✅ Explicit file manifest per worker, verified for no overlap
- ✅ Wave cap of 4, dependency-ordered waves
- ✅ Base branch synced immediately before spawn
Ralph Loop Contract (Reverse-Engineered)
This contract captures the operational Ralph mechanics reverse-engineered from:
https://github.com/ghuntley/how-to-ralph-wiggum.tmp/how-to-ralph-wiggum/README.md.tmp/how-to-ralph-wiggum/files/loop.sh.tmp/how-to-ralph-wiggum/files/PROMPT_plan.md.tmp/how-to-ralph-wiggum/files/PROMPT_build.md
Use this as the source-of-truth for Ralph alignment in AgentOps orchestration skills.
Core Contract
1. Fresh context every iteration/wave.
- Each execution unit starts clean; no carryover worker memory.
2. Scheduler-heavy, worker-light.
- The lead/orchestrator schedules and reconciles.
- Workers perform one scoped unit of work.
3. Disk-backed shared state.
- Loop continuity comes from filesystem state, not accumulated chat context.
- In classic Ralph:
IMPLEMENTATION_PLAN.mdandAGENTS.md.
4. One-task atomicity.
- Select one important task, execute, validate, persist state, then restart fresh.
5. Backpressure before completion.
- Build/tests/lint/gates must reject bad output before task completion/commit.
6. Observe and tune outside the loop.
- Humans (or lead agents) monitor outcomes and adjust prompts/constraints/contracts.
AgentOps Mapping
| Ralph concept | AgentOps implementation |
|---|---|
| Fresh context per loop | New workers/teams per wave in /swarm; fresh operating-loop context per worker or NTM pane |
| Main context as scheduler | Mayor/lead orchestration in /swarm and /crank |
| Plan file as state | bd issue graph, TaskList state, plan artifacts in .agents/plans/ |
| One task per pass | One issue per worker assignment in swarm/crank waves |
| Backpressure | /validate, task validation hooks, tests/lint gates, push/pre-mortem gates |
| Outer loop restart | Wave loop in /crank; NTM/Agent Mail substrate for out-of-session loop restarts |
Implementation Notes
- Keep worker prompts concise and operational.
- Keep state in files/issue trackers, not long conversational memory.
- Prefer deterministic checks over subjective completion.
Scope-Escape Report Template (for spawned agents)
Use this template when, mid-task, a worker discovers the work cannot be completed within its declared scope without violating boundaries (immutable scope edits, foreign worktree access, cross-epic mutation, missing credentials, etc.). Emit one report per spawned worker. Workers must NOT silently widen scope.
Template
---
type: scope-escape
worker_id: <swarm-assigned worker id>
task_id: <bead id, task list id, or work-item id>
parent_run: <epic id, plan path, or wave id>
detected_at: <ISO-8601 UTC>
status: BLOCKED | NEEDS_OPERATOR | NEEDS_DECOMPOSE
---
# Scope Escape: <one-line summary>
## What I tried
<2-4 lines: which files I read, which edits I attempted, which commands I ran>
## Where I stopped
<1-2 lines: the boundary I refused to cross — name the file, scope rule, or contract that would have been violated>
## Why
<1-2 lines: the constraint (PROGRAM.md immutable scope, foreign worktree, missing credential, cross-epic dependency, deletion-adjacent stale plan, etc.)>
## Concrete next step
<exactly one suggestion the operator can act on:
- "decompose into a separate bead under <parent>" or
- "approve the immutable-scope edit explicitly" or
- "merge feat/<branch> first; this depends on <commit>" or
- "supply <credential>; current run cannot proceed">
## Evidence
<paths, command output snippets, or grep hits backing the claim>When to emit
- BLOCKED: the boundary is hard. No flag/permission unblocks it.
- NEEDS_OPERATOR: the operator can authorize wider scope, but the worker must not assume.
- NEEDS_DECOMPOSE: the task is real but should be split; recommend the split.
What NOT to do
- Silently widen scope into immutable paths.
- File a generic "I couldn't do this" comment without the structured fields.
- Continue partially — emit the report and stop the worker cleanly.
Source
agentops-zm8 post-mortem: workers used ad-hoc scope-escape language; the operator had to read the prose to figure out next steps. The template makes the next step machine-extractable.
Shared-Checkout Discipline
When ~/dev/<repo> is contended — peer Codex agent in the same directory, NTM swarm pane, out-of-session scheduled operating-loop or /evolve run on the substrate, or operator parallel session — never edit in the shared tree and never leave work uncommitted between turns. Use a git worktree. Commit-or-stash incrementally with explicit paths. Verify a clean baseline before spawning a swarm.
This is the prerequisite check that justifies worktree-isolation.md. worktree-isolation tells you how to isolate; this doc tells you when you must — and what fails if you don't.
When This Fires
| Signal | Action |
|---|---|
git status --short returns foreign files you did not create | Switch to a worktree before any edit |
| Handoff or memory mentions "another session was here" | Worktree, even if git status is clean now |
About to spawn a swarm (/swarm, /crank, NTM panes) | git worktree add first; point the session symlink at the worktree |
About to run a destructive git command (reset --hard, clean -fd, checkout -- .) on a dirty tree | Stop. The "dirt" may be a peer's work |
| Multi-hour session about to end with uncommitted edits | Commit explicit paths now; do not leave work hostage to the next agent |
Failure Modes (Why The Rule Exists)
1. Branch-deletion data loss. A full session's deliverables — README revision, a new skill, a Gherkin spec — left uncommitted on an ephemeral branch in the shared checkout. A concurrent session merged and deleted that branch, stashing the loose files to clean its own tree. The work survived only because the other session stashed rather than git clean-ed: luck, not discipline. Recovery required git checkout stash@{N}^3 -- <paths> across two stashes to reassemble.
"in a shared or agent-contended checkout, commit (or at least branch) work incrementally as each piece completes, never at session end. A session-long pile of uncommitted edits is hostage to every other agent's branch operations — checkout switches, merges,reset,clean, branch deletion."
— .agents/learnings/2026-05-17-quick-commit-early-in-contended-checkouts.md
2. Swarm attribution confounded. A 4-pane duel swarm spawned directly into the live shared checkout. A concurrent co-tenant agent was also working there. The co-tenant's untracked file bleed and ~6 off-scope commits got attributed — in the orchestrator's own retro — to swarm scope-drift. They were not. Root cause: every committer in the shared checkout shows as the same git author, so swarm-pane work and co-tenant work are indistinguishable after the fact.
"before spawning any swarm —git worktree adda dedicated directory and point thentmsession symlink at that, not at a live shared checkout. Also rungit status --untracked-files=allat spawn; a non-clean tree means either stash the unrelated state or pick a different worktree."
— .agents/learnings/2026-05-17-quick-swarm-isolated-worktree-or-attribution-confounds.md
3. Destructive recovery temptation. Throughout the 2026-05-17 cascade session, 33+ foreign files persisted in the shared checkout. Every git operation had to either dodge them (via worktrees, used 8+ times: /tmp/ao-rebase, /tmp/ao-int2, /tmp/ao-fix, /tmp/ao-full, /tmp/mo-sdlc, /tmp/ao-ci2, /tmp/ao-wiki-merge, /tmp/ao-fmt) or risk destroying another agent's work via git clean -fd or git checkout -- ..
"Worktrees were the only safe path. Used 8+ times … Each was cheap to create; the collisions they avoided were not."
— .agents/learnings/2026-05-17-shared-checkout-discipline.md
How To Apply
Pre-edit check (every turn)
git status --short
# If non-empty and you did not create those files → worktree required.Real work — use a worktree
# Project convention: bd worktree create handles the dance for you.
bd worktree create --branch <type>/<bead-id>-<slug>
# Or manually, off fresh main:
git fetch origin main
git worktree add -b <type>/<bead-id>-<slug> /tmp/<repo>-<slug> origin/main
cd /tmp/<repo>-<slug>
# do work, commit, push from herePre-swarm — verify clean baseline
# In the target worktree (NOT the shared checkout):
git status --untracked-files=all
# Empty → safe to spawn the swarm here.
# Non-empty → either stash with a labeled message, or pick a different worktree.Committing in a shared tree (when worktree is unavailable)
# Stage explicit paths only. Foreign WIP must not ride along.
git add path/a path/b path/c
git commit -m "..."
# NEVER:
git add -A # adds everything, including peer's WIP
git add . # sameCommit cadence
Commit as each piece completes, not at session end. A 3-hour session with zero commits is 3 hours of work hostage to the next destructive git command any peer agent runs.
What This Doc Does NOT Cover
- `mcp-agent-mail` file reservations. That is an orthogonal application-
level lock layer (Agent Mail's file_reservation_paths tool). It does not replace git-level discipline; it complements it. See the agent-mail skill.
- The proposed `check-worktree-disposition.sh` CI gate. Filed as a
follow-up; this doc documents the operator-level rule, not the gate.
- Worktree mechanics in detail. See worktree-isolation.md
for the per-backend isolation semantics, sparse-checkout config, and post-spawn verification.
See Also
- worktree-isolation.md — backend-specific worktree
mechanics; this doc is the prerequisite "when to use" rule.
- pre-spawn-friction-gates.md — broader
pre-spawn gate inventory; clean-baseline is one such gate.
- conflict-recovery.md — recovery once contention
has already produced a conflict.
# Executable spec for the /swarm skill — wave-execution parallel-fork (BC3 Loop, Move 5).
# /swarm is the primitive /crank invokes to run a wave. It spawns fresh-context workers
# in parallel ONLY when the wave is conflict-free (the wave-validity check is all-green);
# otherwise it runs sequential. Parallelism is explicit ownership, not chaos. Hexagon:
# supporting; consumes: implement, vibe; produces: .agents/swarm/results/*.json;
# customer-of crank. (soc-qk4b)
Feature: Swarm executes a wave in parallel only when ownership is conflict-free
As the loop's wave-execution fork
I want parallel workers spawned only on a verified-disjoint wave
So that parallelism is explicit ownership, never a colliding free-for-all
Background:
Given a wave of slices handed down by /crank
Scenario: the wave-validity check gates parallel spawn
When /swarm prepares to run the wave
Then it spawns parallel workers only if every wave-validity row is green
(disjoint write scopes, no shared migration/contract/CLI surface,
integration order declared, one owner per slice, a discard path per slice)
And it defaults to sequential when any row is not green
Scenario: each worker runs in fresh, isolated context
When workers are spawned
Then each receives one pre-assigned atomic task and executes it in fresh context (Ralph pattern)
And no two workers share a write scope
Scenario: results are captured and the backend is cleaned up
When the wave completes
Then per-worker results are written under .agents/swarm/results/*.json
And spawned backend resources are released
Scenario: swarm is the wave primitive crank invokes
Then /crank drives wave execution through /swarm rather than spawning agents directly
Swarm Troubleshooting
Worktree isolation did not engage
Cause: isolation: worktree was specified but the Task result has no worktreePath — worker changes land in the main tree. Solution: Verify agent definitions include isolation: worktree. If the runtime does not support declarative isolation, fall back to manual git worktree add (see Worktree Isolation section). For overlapping-file waves, abort and switch to serial execution.
Workers produce file conflicts
Cause: Multiple workers editing the same file in parallel. Solution: Use worktree isolation (--worktrees) for multi-epic dispatch. For single-epic waves, use wave decomposition to group workers by file scope. Homogeneous waves (all Go, all docs) prevent conflicts.
Team creation fails
Cause: Stale team from prior session not cleaned up. Solution: Run rm -rf ~/.claude/teams/<team-name> then retry.
Codex agents unavailable
Cause: codex CLI not installed or API key not configured. Solution: Run which codex to verify installation. Check ~/.codex/config.toml for API credentials.
Workers timeout or hang
Cause: Worker task too large or blocked on external dependency. Solution: Break tasks into smaller units. Add timeout metadata to worker tasks.
gc backend detected but workers unresponsive
Cause: gc controller is running but worker sessions are idle or not accepting nudges. Solution: Run gc status --json to check session states. Use gc session peek <alias> --lines 50 to inspect last activity. If a session is stuck, restart it via gc pool commands. Verify scale_check = "bd ready --count" returns pending work.
Tasks assigned but workers never spawn
Cause: Backend selection failed or spawning API unavailable. Solution: Check which spawn backend was selected (look for "Using: <backend>" message). Verify Codex CLI (which codex) or native team API availability.
Validation Contract (Moved)
Source of truth: skills/shared/validation-contract.md
This file is a compatibility shim for older links and references.
Worker Pitfalls: Platform-Specific Gotchas
Inject relevant sections into worker prompts based on the task's target language/platform.
---
Bash
Subshell variable scoping -- Variables set inside a pipe subshell do not propagate.
# BROKEN: count stays 0 (while runs in subshell)
count=0; cat file.txt | while read line; do count=$((count+1)); done
# FIX: redirect instead of pipe
while read line; do count=$((count+1)); done < file.txtmacOS vs GNU tools -- BSD sed/awk/head flags differ from GNU.
# BROKEN on macOS:
sed -i 's/old/new/' file.txt
# FIX (macOS): sed -i '' 's/old/new/' file.txtrm alias hangs workers -- Some systems alias rm to rm -i, blocking on confirmation.
# FIX: bypass aliases
/bin/rm -f somefileSilent pipe failures -- Pipeline exit code is the last command's. Earlier failures are hidden.
# FIX: enable pipefail at top of script
set -o pipefailUnquoted variables -- Word splitting breaks paths with spaces.
# BROKEN: cat "my" and "report.txt" separately
file="my report.txt"; cat $file
# FIX: always double-quote: cat "$file"---
Go
Build tag placement -- //go:build must be first line, blank line before package.
// BROKEN:
package main
//go:build linux
// FIX:
//go:build linux
package mainModule path vs imports -- Import paths must match the module path in go.mod exactly.
go.mod: module github.com/user/repo
BROKEN: import "github.com/user/repo/v2/pkg" (module is not v2)
FIX: import "github.com/user/repo/pkg"Test naming -- Files must end _test.go. Functions must be TestXxx (capital after Test).
BROKEN: auth_tests.go, func testAuth(t *testing.T)
FIX: auth_test.go, func TestAuth(t *testing.T)Unused imports fail build -- Go refuses to compile with unused imports.
// FIX: remove unused imports, or blank-import for side effects:
import _ "github.com/lib/pq"Unused variables fail build -- Declared-but-unused locals are a compile error.
// BROKEN: result declared, only err used
result, err := doSomething()
// FIX: blank identifier
_, err := doSomething()Cobra command global state -- cobra.Command instances retain flag/arg state across calls. Re-using the same command object in tests bleeds state between test cases.
// BROKEN: cmd is package-level; each test sees prior test's args
var cmd = &cobra.Command{...}
func TestA(t *testing.T) { cmd.Execute() }
func TestB(t *testing.T) { cmd.Execute() } // sees TestA's flag values
// FIX: construct a fresh command per test, or call cmd.ResetFlags() between
func newCmd() *cobra.Command { return &cobra.Command{...} }os.Chdir is process-global -- os.Chdir mutates the process working directory, breaking t.Parallel() and any concurrent goroutine relying on relative paths.
// BROKEN: blocks t.Parallel; siblings see whatever dir this test left behind
func TestX(t *testing.T) {
os.Chdir(tmp); defer os.Chdir(prev)
runThing() // uses relative paths
}
// FIX: pass dir as a parameter; never mutate cwd in tests
func TestX(t *testing.T) {
t.Parallel()
runThing(tmp)
}---
Git
Worktree isolation -- Changes in a worktree are invisible to main tree until merged. Workers in /tmp/swarm-epic-1/ do not affect /repo/.
Detached HEAD -- Worktrees created without -b start detached; commits may be lost.
# BROKEN: git worktree add /tmp/task1 HEAD
# FIX: git worktree add /tmp/task1 -b swarm/task1Never commit from a worker -- Concurrent git add/git commit corrupts the index. Workers write files only. The team lead is the sole committer.
---
Skills / Docs
Source of truth -- Edit skills in skills/ in this repo, NOT ~/.claude/skills/ (installed copies are overwritten on update).
Reference linkage -- Every file under skills/<name>/references/ must be linked from that skill's SKILL.md. heal.sh --strict enforces this.
No symlinks -- The plugin-load-test rejects symlinks. Copy files instead of symlinking.
Skill count sync -- Adding or removing a skill directory requires scripts/sync-skill-counts.sh. CI fails otherwise.
Worker Pre-Task Checks
Run these checks before writing any new code. Each prevents a recurring failure pattern where workers write a function or helper that already exists, leading to duplication, drift, or test surface bloat.
Inject the relevant subset into the worker's task metadata via the dispatch prompt (see SKILL.md "Platform pitfalls" injection point).
1. Grep for existing implementations
Before adding a new utility/helper:
# Search by name pattern
grep -rn "func <YourFunctionName>\b" cli/ --include="*.go"
grep -rn "def <your_function_name>\b" cli/ --include="*.py"
# Search by signature/intent if name is uncertain
grep -rn "ReadFile\|WriteFile\|atomicWrite" cli/internal/ --include="*.go"
# Search by docstring/comment hint
grep -rn "atomic.*write\|durable.*save" cli/ --include="*.go"If the grep returns hits, read the existing implementation before deciding to add a new one. The right choice is usually:
- delegate to the existing function, or
- extend it with a parameter, or
- explicitly justify the duplication in the PR body.
Source: Phase 3 retro — D.1 created estimateTokens while an equivalent existed in context.go. Worker had not grepped first.
2. Check imports and package contracts
Before importing a third-party library:
# What does this module already pull in for the target capability?
grep -rn "^import\|^\s*\"github\." <target-package>/ --include="*.go" | head -20
# Is there a canonical helper package?
ls cli/internal/types/ cli/internal/shared/ cli/internal/util/ 2>/dev/nullIf the package already imports a library that solves the problem, prefer it over a new dep.
3. Confirm symbol existence in deletion-adjacent regions
Before assuming a named function/type exists in the target file:
# Has the target file had recent deletions?
git log --since='30 days ago' --diff-filter=D --name-only -- <target-path>
# Does the named symbol still exist on HEAD?
grep -F '<SymbolName>' <target-file>This pairs with planning rule PR-008 (skills/plan/references/planning-rules.md). The plan author should have already done this; the worker check is the defense-in-depth pass.
4. Verify file manifest matches reality
Before opening a file in the manifest:
# Does the file exist on the current branch?
ls <manifest-path>
# Or, if the manifest is paths-relative-to-repo-root:
git ls-files | grep -F '<manifest-path>'If a manifest entry is missing on disk, emit a scope-escape (see references/scope-escape-template.md) instead of creating the file from scratch. The plan may be stale.
5. Quick-Reference Inject Block
Paste this into worker dispatch prompts (gc nudge, Claude team task, Codex subagent prompt):
PRE-TASK CHECKS (run before writing code):
1. grep for existing impls of any utility you plan to add
2. ls / git ls-files for every file in your manifest — emit scope-escape if missing
3. grep -F '<symbol>' for every named function/type the plan references against current HEAD
4. Read the existing impl before deciding to duplicate; prefer delegate/extend over newSource
Phase 3 retrospective: workers writing duplicate utilities and assuming stale plan symbols still existed. agentops-zm8 post-mortem reinforced.
Worker Specs
Per-worker model, tool, and prompt isolation for/crankand/swarm. Schema:schemas/worker-spec.v1.schema.json.
Why
Anthropic's Managed Agents launch (May 2026) gives each specialist its own model, prompt, and tool set. AgentOps workers currently inherit the lead agent's tools — fine for most cases but limits the "haiku-lead delegates to opus-implementer" pattern that smaller managed-agent setups exploit.
A worker spec is a small YAML/JSON file declaring which model, tool subset, and prompt template a worker uses. /crank reads the spec at spawn time, the worker inherits only the declared surface.
When to use a spec
| Situation | Use a spec? |
|---|---|
| All workers in the wave do the same thing (e.g. all docs edits) | No — inherit lead defaults |
| Different roles in the wave (spec-author, test-writer, impl) | Yes — one spec per role |
| Mixing models (cheap lead, opus implementer) | Yes |
| Restricting tool surface (worker that should only Read+Edit, not Bash) | Yes |
| One-off task | Probably not — specs are for repeated patterns |
Schema
See schemas/worker-spec.v1.schema.json. Minimal example:
version: 1
name: spec-author
model: claude-sonnet-4-6
tools: [Read, Write, Grep, Glob]
effort: medium
timeout_seconds: 300Tool list of [] means no tools (read-only reasoning). Omitting tools means inherit lead's tool set. model: inherit uses the lead's model.
Storage convention
Reusable specs live at skills/<skill>/worker-specs/<role>.yaml (e.g. skills/crank/worker-specs/spec-author.yaml). One-off specs can be inlined in plan documents under a worker_specs section.
How /crank consumes specs
plan/<epic>/issues.json:
- id: epic-1
worker_spec: skills/crank/worker-specs/spec-author.yaml
metadata:
validation: { ... }
files: [...]When crank dispatches epic-1, it: 1. Loads worker_spec, validates against schemas/worker-spec.v1.schema.json 2. Resolves model: inherit to the lead's model 3. Builds the spawn payload using ONLY tools from tools (cross-checked against tool registry) 4. Prepends the prompt file (if any) to the per-task instructions 5. Spawns with effort mapped to the runtime's effort tier
Anti-patterns
Don't ladder model overrides in plan files. If the same role is used by multiple issues, write one spec file and reference it from each. Inline specs are fine for one-offs but become a maintenance hazard at scale.
Don't use specs to gate access to dangerous tools. Specs reduce surface for the worker's convenience and cost; security comes from the runtime's permission model, not the spec.
Don't mix `model: inherit` with `effort: high` if the lead is on Haiku. The runtime will warn and fail the spawn. Pick a concrete model when overriding effort.
Validation
scripts/validate-worker-specs.sh (to be added with the implementation) walks all **/worker-specs/*.{yaml,json} and validates against the schema. CI gate to be added at implementation time.
See also
- Schema: schemas/worker-spec.v1.schema.json
- Spec issue: soc-yjzp.8
- Pre-mortem fix 6: enum strictness on the
modelfield (applied — see schema)
#!/usr/bin/env bash
set -euo pipefail
# OL Ratchet Backflow - Feedback path from AO back to OL
# Called per-bead after worker validation passes.
# Notifies Olympus that a bead completed successfully.
BEAD_ID="${1:?Usage: ol-ratchet.sh <bead-id>}"
# Extract quest ID: strip the trailing sub-bead suffix (e.g., ol-527.1 -> ol-527)
QUEST_ID="${BEAD_ID%.*}"
echo "ol-ratchet: bead=${BEAD_ID} quest=${QUEST_ID}"
# Call Olympus hero ratchet, capturing stderr for error reporting
if stderr=$(ol hero ratchet "$BEAD_ID" --quest "$QUEST_ID" 2>&1 1>/dev/null); then
echo "ol-ratchet: success — ratchet complete for ${BEAD_ID}"
exit 0
else
echo "ol-ratchet: validation failed for ${BEAD_ID}" >&2
if [[ -n "${stderr}" ]]; then
echo "ol-ratchet: error: ${stderr}" >&2
fi
exit 1
fi
#!/usr/bin/env bash
set -euo pipefail
# OL Wave Loader - Bridges OL hero hunt output into AO swarm execution
# Extracts and validates wave data from ol hero hunt JSON output.
# Called once at swarm startup when --from-wave is passed.
WAVE_FILE="${1:?Usage: ol-wave-loader.sh <wave-json-file>}"
# Validate file exists and is readable
if [[ ! -f "$WAVE_FILE" ]]; then
echo "Error: Wave file not found: $WAVE_FILE" >&2
exit 1
fi
if [[ ! -r "$WAVE_FILE" ]]; then
echo "Error: Wave file not readable: $WAVE_FILE" >&2
exit 1
fi
# Extract and validate the wave array from ol hero hunt output
# Check that each wave entry has required fields: id, title, spec_path, priority
wave_entries=$(jq -c '.wave[]?' "$WAVE_FILE" 2>/dev/null) || {
echo "Error: Failed to parse wave array from $WAVE_FILE (not valid JSON or missing 'wave' key)" >&2
exit 1
}
# Process each wave entry
if [[ -z "$wave_entries" ]]; then
echo "Error: No wave entries found in $WAVE_FILE" >&2
exit 1
fi
# Validate and output sorted entries
results=()
while IFS= read -r entry; do
# Skip empty lines (e.g., trailing newline from heredoc)
[[ -z "$entry" ]] && continue
# Validate required fields
id=$(echo "$entry" | jq -r '.id // empty') || {
echo "Error: jq failed parsing 'id' from wave entry: $entry" >&2
exit 1
}
if [[ -z "$id" ]]; then
echo "Error: Missing or invalid 'id' field in wave entry: $entry" >&2
exit 1
fi
title=$(echo "$entry" | jq -r '.title // empty') || {
echo "Error: jq failed parsing 'title' from wave entry: $entry" >&2
exit 1
}
if [[ -z "$title" ]]; then
echo "Error: Missing or invalid 'title' field in wave entry: $entry" >&2
exit 1
fi
spec_path=$(echo "$entry" | jq -r '.spec_path // empty') || {
echo "Error: jq failed parsing 'spec_path' from wave entry: $entry" >&2
exit 1
}
if [[ -z "$spec_path" ]]; then
echo "Error: Missing or invalid 'spec_path' field in wave entry: $entry" >&2
exit 1
fi
priority=$(echo "$entry" | jq -r '.priority // empty') || {
echo "Error: jq failed parsing 'priority' from wave entry: $entry" >&2
exit 1
}
if [[ -z "$priority" ]]; then
echo "Error: Missing or invalid 'priority' field in wave entry: $entry" >&2
exit 1
fi
# Validate priority is a number
if ! [[ "$priority" =~ ^[0-9]+$ ]]; then
echo "Error: Priority must be a number, got '$priority' for bead $id" >&2
exit 1
fi
# Validate fields do not contain newlines or tabs (prevents TSV array corruption)
for _field_name in id title spec_path; do
eval "_field_val=\$$_field_name"
if [[ "$_field_val" =~ [$'\n'$'\t'] ]]; then
echo "Error: '$_field_name' field contains newline or tab characters in wave entry: $entry" >&2
exit 1
fi
done
# Store result for sorting (priority first for sorting, then output columns)
results+=("$priority"$'\t'"$id"$'\t'"$title"$'\t'"$spec_path")
done <<< "$wave_entries"
# Sort by priority (column 1, numeric) and output in correct order (id, title, spec_path, priority)
printf '%s\n' "${results[@]}" | sort -t$'\t' -k1 -n | awk -F$'\t' '{print $2"\t"$3"\t"$4"\t"$1}'
#!/usr/bin/env bash
set -euo pipefail
SKILL_DIR="$(cd "$(dirname "$0")/.." && pwd)"
PASS=0; FAIL=0
check() { if bash -c "$2"; then echo "PASS: $1"; PASS=$((PASS + 1)); else echo "FAIL: $1"; FAIL=$((FAIL + 1)); fi; }
check "SKILL.md exists" "[ -f '$SKILL_DIR/SKILL.md' ]"
check "SKILL.md has YAML frontmatter" "head -1 '$SKILL_DIR/SKILL.md' | grep -q '^---$'"
check "SKILL.md has name: swarm" "grep -q '^name: swarm' '$SKILL_DIR/SKILL.md'"
check "Local mode documented" "grep -q 'Local' '$SKILL_DIR/SKILL.md'"
check "skill requires metadata.issue_type" "grep -rqs 'metadata.issue_type' '$SKILL_DIR/SKILL.md' '$SKILL_DIR/references/'"
check "Backend references documented" "grep -qE 'backend-claude-teams|backend-codex-subagents' '$SKILL_DIR/SKILL.md'"
check "Shared backend docs exist" "[ -f '$SKILL_DIR/../shared/references/backend-claude-teams.md' ] || [ -f '$SKILL_DIR/../shared/references/backend-codex-subagents.md' ]"
check "Cleanup lifecycle documented" "grep -qiE 'cleanup|close_agent|reaper' '$SKILL_DIR/SKILL.md'"
echo ""; echo "Results: $PASS passed, $FAIL failed"
[ $FAIL -eq 0 ] && exit 0 || exit 1
Related skills
How it compares
Use swarm when generated artifacts create merge collisions; use branch-per-feature git flow alone when agents edit only hand-written source.
FAQ
What does swarm do?
Dispatch parallel agents. Triggers: "swarm", "dispatch parallel agents.", "swarm skill".
When should I use swarm?
User asks about swarm or related SKILL.md workflows.
Is swarm safe to install?
Review the Security Audits panel on this page before installing in production.