WAR — Work · Audit · Refine. A Claude-native Workflows-based multi-agent orchestration skill that executes a detailed, multi-phase implementation plan end-to-end — and stops to check in with you at every phase boundary. Fresh workers implement, independent auditor panels review, a serial refinery gates every merge: the code that lands is production-grade, even when it lands while you sleep.
It's a portable, dependency-free re-imagining of Steve Yegge's Gas Town, built on Claude Code's own primitives — Agent, the Workflow tool, git worktrees, and GitHub issues — with no Go binary, no Dolt, no beads. WAR keeps Gas Town's worker / auditor / refinery roles, absorbs the witness's live coordination into the Workflow itself, and adds a servitor that records each phase's learnings.
Multi-agent parallelism is table stakes now. WAR's bet is different: verification discipline you can reproduce.
- Audits are the product. Every task's diff faces a roster of 1–5 independent, read-only auditor seats — each reviewing through a distinct lens (
correctness,cascading-impact,plan-faithfulness,security, …), each judging the same pinned SHA. Findings are severity-tagged, Critical/Major block, and approval is unanimous; then a serial refinery rebases, re-runs your gate, and merges. Nothing lands on the say-so of the agent that wrote it. Paired with your CI/CD, this is what makes agent-written code production-grade instead of merely plausible. - Plans in, intent honored. WAR executes plans, not vibes. The pipeline grills the ambiguity out before anything spawns —
/war-strategy+ Grill Me interview a spec into a plan,/red-teamadversarially proves the plan's claims in throwaway sandboxes — and the plan's Commander's Intent (purpose, method, checkable end state) rides into every worker and auditor prompt: the plan slice is the floor, your intent is the ceiling. - Deterministic where it counts. The coordination — phase loop, dependency waves, serial merge queue, severity gate — is knowable up front, so it lives in a deterministic, resumable Workflow script rather than emergent agent negotiation (why). Same plan, same shape; git is the resume authority (ADR 0008).
- Runs compound. After each phase, a write-scoped servitor records durable learnings under a provenance ladder (
agent-unverified<code-verified<user-confirmed), verifying each referent against the codebase before writing. The loop closes the other way too: at each phase launch the Lead prefetches the most relevant prior lessons and pushes them into the worker and auditor prompts, so past pitfalls arrive as context before the mistake repeats./lessons-learnedkeeps the store honest against the live repo over time. By default the store stays local to your machine; turn oncommitLearnings(via/war-room) to commit distilled, lint-scrubbed lessons underdocs/learnings/so they travel with the repo and compound across your team. Your fiftieth run knows what your fifth one learned. (Retrieval and publication use a zero-dependency Node ≥ 24 CLI —node:sqlite's in-memory FTS index; on older Node the memory features simply no-op and the run proceeds unaffected.) - Nothing but the plugin. Stock, generally-available Claude Code primitives —
Workflow,Agent, git worktrees,gh. No server, no daemon, no framework, no experimental flags. Every Claude Code release makes WAR stronger, not obsolete. - Built for overnight. Queue plans with
/war-campaignin the evening; the audit gate + your CI hold the line unattended; wake up to stacked, ready-to-review PRs.
Given a plan like docs/plans/2026-06-18-war-room.md, /war will:
- Decompose the plan into one or more phase(s) → task DAG and propose it to you as GitHub issues — all phase epics up front, task sub-issues just-in-time per phase. You approve before anything spawns.
- For each phase, run a Workflow that:
- Works — fresh worker agents implement each task in isolated git worktrees, writing the plan's mapped tests.
- Audits — independent, read-only auditor seats review each task (severity-tagged findings; Critical/Major block; unanimous on one SHA). Each task convenes its own roster of 1–5 distinct-lens seats, each at its own depth; the default roster is the trio (
correctness,cascading-impact,plan-faithfulness) atdeep. - Refines — a serial merge queue rebases, re-runs the gate (
tests/lint), and lands approved tasks on a per-phase integration branch. - Records — after the phase lands, a write-scoped servitor captures durable learnings into memory (and at each phase's launch the Lead prefetches the most relevant prior lessons into the worker/auditor prompts).
- Lands each phase onto your working branch as one
--no-ffcommit, pushes, and checks in with you. - Opens one PR from the working branch to the landing branch at the end.
Run autonomously inside a phase; gated by you between phases (--afk to loosen).
Add the marketplace:
/plugin marketplace add Ljferrer/WorkAuditRefine
Install the plugin:
/plugin install work-audit-refine@work-audit-refine
When a new version ships, pull it into your install.
Git-pull the marketplace:
/plugin marketplace update work-audit-refine
It automatically bumps your install to the new version. Changes apply to the next session — or run /reload-plugins to force a reload without restarting.
Authors — bump the version or the update is a silent no-op. Claude Code caches plugins by the
versionstring in.claude-plugin/plugin.json, so pushing new commits without bumping it leaves every consumer on the cached copy. While iterating locally, skip the round-trip: launch withclaude --plugin-dir /path/to/WorkAuditRefineand run/reload-pluginsafter each edit — local paths resolve to versionunknown, so every reload picks up your latest files.
These plugins improve the quality of code generated by the WAR agentic workflow:
The command set, in the order you'll run it: /war-help orients you → /war-room configures a run → /war-strategy structures the spec and the plan (and converts spec → plan) → /red-team hardens the plan → /war executes it → /war-review tallies what the run cost and flags any friction. Scaling up: /survey-corps turns open issues and hot memories into specs → /war-machine turns specs into plans + a roadmap → /war-campaign runs the plans back-to-back unattended → /aftermath cleans up the debris → /lessons-learned keeps the accumulated memory honest.
New to WAR, or just want a refresher? Run the orientation card:
/war-help
It prints a one-screen map — what WAR is, the command set, the five roles, how a run flows, and the
prerequisites — then offers deep-dive links and a handoff to /war-strategy. Design notes:
docs/specs/2026-07-01-war-companion-skills-design.md.
By default WAR runs opus workers on max effort and opus auditors on xhigh, and under rosterPolicy: auto the Lead composes each task's audit roster from the lens catalog — 1–5 seats, each at its own depth with a one-line rationale — at the approval gate (a triggered lone seat later widens toward the auditor's own nomination, or the default roster if it names none). To change that — pick models per role, put a worker on ultrathink, shape the roster (seats, lenses, per-seat depth) or its seeding policy — run the companion skill first:
/war-room
Or invoke it in natural language — e.g. "To the war room!".
It interviews you (starting from a balanced / thorough / economy preset, then only the overrides you ask for), validates your choices, and writes .claude/war/config.json. /war auto-discovers that file on its next run (or pass --config <path>). No config file → today's defaults, unchanged. Design notes: docs/specs/2026-06-18-war-room-design.md.
What "today's defaults" actually are. With no config file WAR runs the built-in DEFAULTS: opus workers on max effort, opus auditors on xhigh, rosterPolicy: auto (the Lead composes each task's roster), the pre-merge ace-fix on, and a 3-round fix budget. For memory the defaults are retrieval: true with topK: 10 (prefetch the ten most relevant lessons into each seat's prompt) and commitLearnings: false — distilled project-typed lessons stay local to your machine unless you opt in via /war-room (see Tidy the memory for the publication pitch). The three presets move the whole profile at once: balanced is the defaults, thorough widens rosters and deepens effort (and pumps tokens), and economy pins the cheaper knobs it always had — sonnet across every role, a solo roster, a 2-round budget, and ace off. /war-room only ever asks about the overrides you want on top of the chosen preset.
Spec ≠ plan — the what vs. the how. A design spec (docs/specs/) is the ratified decision record for a change — problem, pivotal constraints, numbered decisions with alternatives considered, affected surfaces, test intent. It answers what changes and why, and carries no dispatch structure — /war cannot execute one. An implementation plan (docs/plans/) is the executable artifact /war consumes — phases and tasks with exact file sets, requiresTest, deps, and target repo. It answers how: who does what, in which order, against which files. Every plan opens with a Commander's Intent — Purpose (why), Method (how you envision winning), End state (numbered, individually checkable conditions) — drafted from your answers, confirmed by you explicitly, and threaded into every worker and auditor prompt: the plan slice is the floor, your intent is the ceiling. Full glossary: CONTEXT.md.
Structure a spec or plan. Bare invoke loads the authoring primer — the WAR-shaped spec/plan/roadmap templates plus the code-boundary decomposition rule in one sentence: file-disjoint tasks in a phase, a dependency crossing a phase edge, one task per repo, release as its own trailing phase — then routes you to your installed grilling skill to actually interview you (its dependency check points you at the Grill Me install under Recommended Auxiliary Plugins when that skill isn't installed):
/war-strategy
Convert a spec into a plan. Bring it an existing draft — a design spec, rough plan, roadmap, or design doc — and it reviews the artifact for war-shape gaps, interviews you gap-by-gap, and applies the structural fixes. Given a spec, it authors the war-shaped implementation plan into docs/plans/ itself (drafting the plan's Commander's Intent from your answers and echoing it back for explicit confirmation):
/war-strategy docs/specs/design.md
Pipeline doctrine: war-strategy converts; /red-team validates plans and never converts (see
CONTEXT.md). Design notes:
docs/specs/2026-07-01-war-companion-skills-design.md.
Before you hand a plan to /war, attack it. /red-team <plan-file> reads the plan, runs a universal spine of adversarial checks plus probes tailored to the plan, and proves the plan's claims by running its tests/edits/commands in throwaway sandboxes — never touching your repo. It then grills you on every blocker and patches the plan in place until it is CLEARED, leaving a report under docs/red-team/.
/red-team validates plans; it never converts a spec into one (war-strategy converts, red-team ratifies — see CONTEXT.md). Have a design spec instead of a plan? Bring it to /war-strategy first, then red team the resulting plan.
Or invoke it in natural language — e.g. "Red team my plan at docs/...". Design notes: docs/specs/2026-06-18-red-team-design.md.
The main command:
/war <plan-file> [--working <branch>] [--landing <branch>] [--afk] [--ace] [--config <path>]
Or invoke it in natural language — e.g. "Go to war on issues #20 & #22".
Prerequisites: a clean git working tree, a GitHub remote, and authenticated gh — WAR files issues and opens a PR on your behalf, and refuses to start on a dirty tree. No experimental flags or settings.json changes are required — /war runs on the stock Workflow and Agent tools, not the experimental agent-teams feature (why WAR uses Workflows instead).
Arguments:
| Argument | Required | Default | What it does |
|---|---|---|---|
<plan-file> |
yes | — | Path to the multi-phase plan to execute, e.g. docs/plans/implementation_plan_A.md. |
--working <branch> |
no | current branch | Branch each phase lands on, one --no-ff commit per phase. |
--landing <branch> |
no | repo's default branch | Branch the final PR targets. |
--afk |
no | off | Don't stop at phase boundaries — post a report + push notification and keep going. Hard escalations still halt. |
--ace |
no | on via config run.ace (economy preset: off) |
Fix auditor-flagged Minor/Nit findings on the spot: an approved task's absorb-routed findings get one pre-merge ace commit + a full panel re-audit at the new SHA, instead of being filed as war-followup issues. Never blocks a land — on any regression the ace commit is reverted and the originally-approved work lands anyway. (/war-campaign passes --afk --ace by default.) |
--config <path> |
no | .claude/war/config.json if present |
Use a specific run config (per-role model/effort, roster policy, …) produced by /war-room. |
Example:
/war docs/plans/implementation_plan_A.md --working dev/planA --landing master
What happens when you run it:
- Setup — WAR confirms the repo/
ghstate, detects your gate command (uv sync && ruff check && pytest, yourpackage.jsonlint/test scripts, or it asks once), and picks a learnings target for the servitor. No phase ever runs without a gate. - Decompose + approve — it reads the plan, proposes a phase → task DAG as a GitHub-issues preview, and waits for your approval. Nothing spawns until you say go; all phase epics are filed up front, task sub-issues just-in-time per phase.
- Per phase — the Lead prefetches relevant prior lessons into the seat prompts → workers implement each task in isolated worktrees → read-only auditors review the pinned SHA (Critical/Major findings block; approval is unanimous) → a serial refinery rebases, re-runs the gate, and merges → a write-scoped servitor records durable learnings.
- Checkpoint — the phase lands on
--workingas one--no-ffcommit and is pushed; WAR posts a phase report and checks in with you before the next phase (skipped under--afk; hard escalations halt regardless). - Finish — after the last phase, it opens one PR from
--working→--landingand reports the URL.
Resuming: every run writes a ledger at .claude/teams/<run-id>/ledger.json — the richest resume record, reconciled toward git on resume (git branch state is the authority, ADR 0008). If a run is interrupted, re-invoke /war with the same plan to continue from the ledger + open issues.
Once a run lands, see what it cost — and whether WAR itself hit any friction worth filing back to the plugin:
/war-review [--run <runId>] [--scavenge [<plan-slug>]]
It reads the newest run manifest /war leaves under .claude/war/runs/ (or the one you pin with --run), mines the referenced workflow transcripts, and renders the full telemetry set — workflows and sub-agents by role, tool calls, tokens (in/out/cache when available), wall-clock total and per phase, audit rounds against the limit, findings by severity and disposition, tasks by terminal status, relands, lessons, and issues — both in chat and saved to <runId>-review.md beside the manifest. Anything it can't source renders n/a; it never fabricates a number.
It closes on friction — held:* escalations, env-blocked tasks, reland loops, round-limit exhaustion, dropped agents, guard denials, sweep failures — each row backed by evidence, with a verdict of clean or friction found (N). On friction it drafts one issue against the plugin's own repo (resolved from its metadata) and files it only on your explicit confirm. --scavenge reconstructs a pre-manifest run best-effort from session artifacts, labeled as scavenged.
Your backlog is raw material. Before the issue sweep, /survey-corps mines both memory roots — hot lessons that name open, actionable defects become memory-mined issues, lint-guarded (redaction hits withheld, never scrubbed) and slug-deduped against open and closed issues so nothing sensitive or already-filed is re-filed. It then sweeps the repo's open GitHub issues (run-bookkeeping labels dropped, war-followup debt first-class), fans out a reader agent per issue, clusters the summaries into coherent groups, and synthesizes one war-shaped design spec per group into docs/specs/ — then verifies every swept issue is claimed or explicitly deferred. It commits nothing; it hands off to /war-machine via an uncommitted survey manifest.
/survey-corps [--erwin]
--erwin pauses after clustering so you approve the proposed groups before synthesis. Bare invoke is fully autonomous end to end, so the step stays cron-able.
The middle step of the pipeline: /war-machine consumes the freshest survey manifest (or the spec paths you pass), runs a drafter + adversarial-grill agent pair per spec strictly serially, writes the implementation plans to docs/plans/ and a campaign roadmap to docs/roadmaps/, and prints the /war-campaign handoff — it never launches the campaign and never red-teams. It relies on /war-strategy's templates and conversion doctrine rather than forking them.
/war-machine [spec-paths…] [--afk]
Interactive by default (it interviews you lightly, including the Commander's Intent echo-back per plan); --afk makes it cron-able — it authors a provenance-marked AI-Commander's Intent block instead (ADR 0014) and its closing commit leaves the tree clean for /war.
Once you have several plans, run them back-to-back, unattended, in one chat:
/war-campaign <plan…|roadmap-path> [--wait-for-merge] # start
/war-campaign # resume the latest unfinished campaign
/war-campaign add <plan-path> # from any chat — drop a plan into the queue
Each plan is hardened (/red-team) and executed (/war … --afk --ace) in turn, stacking each plan's branch on the
prior plan's tip and its PR on the prior plan's branch — so later plans see earlier plans' code without a
human merging overnight (the stack-and-plow model, ADR 0011). --wait-for-merge switches to the linear alternative: wait for each PR to merge before
basing the next plan off fresh master.
/war-campaign never auto-invokes — you must run it explicitly. A plan that can't be hardened or hard-halts
halts the whole campaign (halt-and-hold) rather than letting later plans build on incomplete work; every
plan below the failure has already landed as its own stacked PR, merged bottom-up. To ride out overnight
context compaction, the Lead keeps a write-ahead CAMPAIGN-STATE.md resume brief current before each long
wait, and a campaign-gated SessionStart(compact|clear|resume) hook re-injects it into the fresh window so
the campaign re-anchors where it left off. Design notes:
docs/specs/2026-07-01-war-companion-skills-design.md.
WAR campaigns leave debris — stray integration and task branches, orphaned run worktrees, done-but-open bookkeeping issues, survey-swept issues whose PRs merged. /aftermath deletes or closes only what a checkable evidence chain proves is safe, with git as the source of truth at every gate (ancestry and reachability checked against git ls-remote truth, never a ledger claim alone). Anything without a complete chain — including any unmerged branch — is reported, never touched, and anything an active run or campaign ledger references is out of scope.
/aftermath [--afk] [--scorched-earth]
Bare invoke = categorized dry-run report → one confirm → execute the safe list. --afk skips the confirm and executes only the provably-safe class. It never auto-triggers — a deleting verb must never fire because a sentence pattern-matched. --scorched-earth widens the candidates to every local branch and worktree (interactively still report → one confirm).
⚠️ /aftermath --afk --scorched-earthis dangerously destructive. The combo widens cleanup to all local branches and worktrees and force-deletes unmerged work with no human review. Only a non-negotiable protected core survives it.
Why WAR carries its own memory. A one-shot agent forgets everything the instant a run ends; WAR's premise is the opposite — runs compound. After each landed phase a write-scoped servitor distills what the run actually taught — a floor discovery set that has to mirror the gate, a line-number reference that rots across the merge queue, a plan-shape trap — into one-fact Markdown files under a provenance ladder (agent-unverified < code-verified < user-confirmed), which records how each fact was established and drives both recall ranking and eviction order. The servitor verifies every referent against the live repo before writing, so a lesson that names a function or flag is checked to still exist. The loop closes the other way at launch: the Lead runs a full-text query per worker and auditor seat and prefetches the top lessons straight into their prompts, so a past pitfall lands as context before the mistake repeats. That machinery — retrieval ranking, referent verification, provenance-ordered eviction, a byte-budgeted index — is why this is a purpose-built store and not a NOTES.md: it is what keeps what run #5 learned findable and trustworthy by run #50. (Design: ADR 0007 provenance, ADR 0015 two-root.)
Two roots, and when lessons commit. Every lesson routes by its metadata.type. user / feedback / untyped lessons are yours — they stay in the local root (~/.claude/projects/<project>/memory/, untracked, never leaves your machine). A project-typed lesson — a durable fact about this codebase — can be committed to the repo root (docs/learnings/) so it travels with the repo and compounds across your whole team, not just your laptop. That publication is memory.commitLearnings, and it defaults to false — the store stays on your machine until you opt in via /war-room. Turn it on and a lesson about the code travels with the repo, human-reviewed like code, worth more shared than siloed — so the fiftieth run anyone does knows what the fifth one learned. Commit is guarded, not blind: a fail-closed redaction lint scrubs every candidate for home paths, emails, handles, and credential shapes, and anything it trips is demoted to the local root and reported — never dropped, never silently published. So once you opt in, the rule is "share what's about the code, keep what's about you," erring toward local whenever it's unsure.
Over many runs the store still accretes fixed-bug warnings, drifted references, and bloated per-release logs. /lessons-learned does a full housekeeping pass over it:
/lessons-learned
It fans out agents to verify every memory against the live repo, classifies each as still-relevant vs. stale (current / anchor-drift / resolved / superseded / dated-done / stale), then compresses, re-anchors, retires, and merges the topic files and regenerates the MEMORY.md index (a derived projection — nobody hand-edits it) — telling you how full the index is against its budget and reporting at every phase.
It is fault-tolerant to interruption (a closed laptop mid-run). The live memory store is never mutated in place: the pass backs up to a tarball, does all work in a .staging copy, verifies index↔file integrity and link health, and only then performs a single atomic swap — with a recover path if it dies between steps. The deterministic backup / stage / verify / swap / recover logic lives in skills/lessons-learned/assets/safe-swap.sh.
Graduation candidates — when a lesson has earned an enforced guard. The same pass now watches for lessons that keep recurring. As it reads each memory it tallies the re-trigger count from that lesson's recurrence annotations, and flags any lesson that has fired ≥ 2 times and encodes a machine-checkable invariant — a greppable pattern, a diff property, an enum mirror, a string-presence rule — as a graduation candidate: a fact the pipeline keeps relearning that is now worth promoting from advisory memory into an enforced guard. The report lists each with its slug, recurrence count, and a one-line proposed enforcement shape (a hook, a merge floor, a drift-guard test, or a lint). It is strictly flag-only — the pass never writes the guard and never files an issue; it surfaces which repeatedly-relearned lessons are worth mechanizing and leaves the decision to you. A lesson that recurs but encodes a judgment call, with no mechanical invariant, is deliberately left off. (This closes the compounding loop one turn further: the memory system notices its own recurring failures and nominates them for hardening.)
Four more modes go beyond the routine pass above. migrate and evict are one-time moves that manage the two-root split itself; tighten and seed are both repeatable — tighten shrinks the projection, seed imports the portable corpus:
/lessons-learned migrate— the adoption playbook for a store that predates the repo root. In place of the housekeeping pass it retypes theuntypedbucket (agent-assisted), archives[RESOLVED]lessons, backfills retrieval keywords, and splits the operator-confirmedproject-typed lessons out of your local root intodocs/learnings/, opening a reviewed PR so a human approves exactly which lessons go public (the redaction lint runs fail-closed on that PR). Run it once when you decide to start sharing a repo's accumulated memory./lessons-learned evict [slug…]— the undo. It returns repo-root lessons to the local root (temperature preserved — repoarchive/lands in localarchive/), re-renders the projection local-only, and opens a reviewed deletion PR. It also asks whether to setcommitLearnings: false— skip that flip and the next landed phase simply republishesdocs/learnings/, making the eviction temporary./lessons-learned tighten— the repeatable shrink pass that manages the projection's size. The projection's two-column, per-cell-capped rendering already keeps any single row from blowing the budget, soMEMORY.mdis never again one lesson-write from the hard render-refuse ceiling;tightenis what keeps the whole file under the softer 17,000 B advisory line as the corpus keeps growing — Phase 0 and the renderWARNboth point here once you cross it. It ranks eviction candidates by ascending usage (least-queried first) behind hard floors — neveruser-confirmed, never a ≥2-inbound concept hub, never a lesson under 14 days old — then presents the full candidate list as one strike-list gate: a single ask, slug · hits · tier · age · inbound · bytes, never a row-by-row negotiation. Approved local strikes go through the same staged swap as the housekeeping pass above; approved repo strikes land on a dedicated branch as a reviewed PR. If the approved set still leaves the file over target, it reports the shortfall loudly instead of re-asking./lessons-learned seed— the one-command warm-seed: it unpacks the plugin-shipped portable corpus (docs/seed/seed.tar.gz) into your choice ofdocs/learnings/or the local memory root, skipping any slug already present and stamping each placed lessonmetadata.seededFrom. The corpus itself is capped — ≤ 50 members and ≤ 1,500,000 B uncompressed, with an archive tier (≤ 500 members / ≤ 100 MB) for operator-gated overflow — so it ships small enough to live inside the plugin cache. Anyone can grow it back without push access: the bare pass nominates portable lessons, re-packing in-WAR candidates directly behind one operator gate and opening a redaction-lintedseed-candidateissue on the plugin's own repo for everything else, which a later WAR-repo pass sweeps and ingests.
Or invoke any of these in natural language — e.g. "Do a lessons-learned pass on this repo's memory."
This is the workflow WAR exists for: queue plans in the evening, sleep, review PRs over coffee.
The first overnight run (2026/06/25-26) was a hand-written /loop over five plans. It orchestrated 272 subagents across 28 phases, consumed 14.1M tokens, and I woke up to 5 ready-to-merge PRs for this repo — the main context window stayed under 90% capacity (@1.0M) without any compactions. No CRITICAL/MAJOR problems were escalated to me while I slept; 8 follow-up issues were filed for the MINOR/NIT bugs that arose during implementation.
That hand-written loop is now one command:
/war-campaign docs/plans/<plan-1>.md docs/plans/<plan-2>.md ...
It hardens each plan (/red-team), executes it (/war … --afk), stacks each plan's PR on the previous plan's branch, and halts the whole line rather than let later plans build on a failure. If your plans are fleshed out enough, they get implemented overnight — and the multi-lens audit gate + your CI/CD are why you can trust what landed while nobody was watching. For the AI Vampires who don't sleep because they're coding all night: you don't have to anymore. It codes while you sleep; you just review.
Grill Me — author the input plan with
/grill-me./waris only as good as the plan it executes. Matt Pocock's/grill-me&/grill-with-docsskills interview you relentlessly down every branch of the design tree, resolving each decision one at a time, until the plan is unambiguous and cleanly phase-decomposable — exactly the shape WAR needs to fan out workers and auditors./war-strategy's dependency check links here when Grill Me isn't installed.
Run this sequence of commands:
/survey-corps # issues + memories → grouped design specs + survey manifest
/war-machine # specs → implementation plans + roadmap (interviews you lightly)
/war-campaign docs/roadmaps/<date>-<slug>-roadmap.md
/aftermath # evidence-gated cleanup of branches, worktrees, issues
Every step has an autonomous mode — /war-machine --afk, /war-campaign (unattended by default: it passes --afk --ace to each /war itself; there are no operator --afk/--ace flags on its own invocation), /aftermath --afk — so the sequence remains cron-able end to end (a nightly cron job or scheduled task). The clean-tree prerequisite is owned by /war-machine --afk's closing commit: /war refuses a dirty tree, so the autonomous path cannot leave specs/plans/roadmap uncommitted.
| WAR | Gas Town | Built on |
|---|---|---|
| Lead (your chat) | Mayor | the main Claude Code session |
| Worker | Polecat | war-worker — Agent (sonnet) in a git worktree |
| Auditor | none — the "Nun" (a Refinery audit gate) was the author's own idea that never made it into Gas Town; WAR builds it first-class | war-auditor — read-only Agent (opus); file tools plus a fail-closed guard restricting Bash to read-only git |
| Refinery (merge queue) | Refinery | war-refiner — Agent + the serial Workflow merge loop |
| Servitor | bd remember |
war-servitor — write-scoped Agent (sonnet); records per-phase learnings to memory |
| -- | Witness | no standalone agent — its live coordination is absorbed by the Workflow's control flow + hooks |
See skills/war/references/design.md for the full architecture.
WAR runs on the generally-available Workflow + Agent tools — not Claude Code's experimental Agent Teams feature — because its coordination (phase loop, dependency waves, serial merge queue, severity gate) is knowable up front, so it belongs in a deterministic script rather than emergent agent negotiation.
| Workflow of subagents (what WAR uses) | Agent Teams | |
|---|---|---|
| Control flow lives in | your orchestration script (deterministic) | the agents' judgment (emergent) |
| Agents are | ephemeral: prompt in → result out | long-lived, named, addressable peers |
| Inter-agent comms | none — funnels through the orchestrator | direct SendMessage between teammates |
| Human steering mid-run | no (runs to completion) | yes (converse with a running teammate) |
| Task graph | fixed when you write the script | grows dynamically (shared task list) |
| Determinism / resume | high (same script+args → same shape; journal-resumable) | low (model-driven coordination) |
| Gating | GA, no flag | CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1 |
Rule of thumb: scripted, reproducible coordination → Workflow; emergent or interactive coordination → Teams. Full rationale: design.md §2.
A version bump must update all four version slots across three files together (marketplace.json carries two) — Claude Code dispatches plugin updates by the marketplace.json version string, so a stale marketplace.json makes a release a silent no-op (release-drift / mirrored-value pattern):
| File | Field(s) to bump |
|---|---|
.claude-plugin/plugin.json |
version |
.claude-plugin/marketplace.json |
metadata.version and plugins[0].version |
README.md |
the ## Status line/paragraph |
Run this over the ## Status paragraph before landing a release. Overclaims here are semantic —
no lint can judge them — and they are this repo's most frequent recurring release-prose defect,
so the checklist is the guard:
- Bound every absolute. Before writing "every", "all", "never", or an "X is Y too" claim,
confirm the enclosing scope word ("those
tryregions", "that lock", "the body") really does bound every instance the absolute covers. A quantifier inherits the region's boundary in the writer's head, not on the page — and the excluded cases are usually the ones that fire before the region is entered. - Repeat the guard's own scope word. When a guard's code comment already declares a narrower
reach than your sentence — a token-literal match, a
casearm's pattern rather than its body, one named field rather than every line — the blurb repeats that same scoping noun. Dropping it silently promotes a narrow true claim to a broad false one, even when the artifact you are paraphrasing got it right. - Trigger surface, not topology. Say what property of a diff makes a guard refuse, never the shape of the repo it happens to run in.
- Conditional side effects carry their condition. A diagnostic behind its own runtime
ifis "prints X when Y" — never a bare "prints X" with the trigger left implicit. - Scoped labels name their scope. Reserve a bare "No behavior change:" for a release that ships literally none; otherwise name what the label actually covers ("No routing or enum change:"), or a skim-reader gets a headline that contradicts the paragraph's own first sentence.
- Appositives restate their subject. A trailing "…, itself unchanged" binds by proximity to the nearest noun. Name the subject outright whenever the sentence lists both something this release changed and something it did not.
- Provenance. Every item above is a distilled recurrence of
docs/learnings/release-blurb-overstates-guard-semantics.md— read it when a blurb claim feels stronger than the evidence you have.
0.14.67 — A doc-and-comment truth sweep across seven live surfaces, plus the mechanical guards three of those seven earned. Five are standing-doc or source-comment edits: three retire a claim the adjacent artifact already contradicted (#1115, #1146, #1152), one extends an existing rule to a case it already implied (#1107), and one adds a missing routing paragraph (#1096). A sixth (#1153) contributed no reword at all — both of its retirement greps already measured zero at this plan's base — so what ships under it is the new authoring-time guard alone. The seventh (#1136) is a real remedy-path defect, filed independently by three auditor seats. No engine code path, exit code, status enum, floor script, or workflow-template.js dispatched-prompt string moved in this release. That label covers those surfaces and nothing wider: this release does change what the Lead is instructed to do at Gate 2 and what a worker is instructed to return on a config mismatch, and it ships three new test rows across two suites — the checklist presence lock and its unwired negative reference in version-slots.test.mjs, and the D25 cross-ADR mirror row in skill-doc-contracts.test.mjs — plus one extended row (D22). (1) #1136 — the Gate-2 pre-push staged-file remedy now removes the commit it condemns. The probe was already there: before pushing a docs(learnings): phase N promotion, the Lead lists the commit's staged file set and refuses the push if any path falls outside the promotion destination or CLAUDE.md. But refusal alone re-provisioned and re-committed while leaving the condemned commit sitting on the working branch inside the publication worktree — a release-reverting commit one ensure-origin from origin. skills/war/SKILL.md's bullet now carries the undo between the do-not-push clause and the push step: git reset --hard HEAD~1 in the publication worktree. Its precondition holds by construction — the probe inspected HEAD, so the commit it just condemned is HEAD in the same pass — and the target is provably unpushed. The bullet states the carve-out outright, as the sanctioned exception to the no-reset --hard shared-branch doctrine scoped to an unpushed commit in the transient Lead-owned publication worktree, so a reader takes it as chosen rather than as a doctrine conflict. When a re-entry shape shows the condemned commit is no longer HEAD (the branch advanced past it), the bullet routes to git revert instead and never rewinds; a conflicted revert is git revert --abort plus escalate. Re-provision and re-commit are unchanged, and now bounded: a second condemnation escalates rather than looping. Its D22 lock moved with it, in the same task: the skill-doc-contracts.test.mjs row that polices that flow is ONE ordered regex, and its span now runs commit step → git show --name-only probe → do-not-push clause → undo → ensure-origin push, so dropping any arm or relocating one outside the span reds. The undo arm is pinned on the token reset --hard HEAD~1, deliberately not on a bare reset --hard: the remedy's own carve-out sentence names the no-reset --hard doctrine inside that same extracted region, so a bare key would be satisfied by the doctrine mention alone. A new inline unwired negative reference — the pre-#1136 region shape with the undo clause absent and a bare reset --hard doctrine mention present — runs through the same key and is asserted not to match, which proves the pinning decision rather than just asserting it. The row's extraction is untouched (the **Post-servitor publication (Gate 2 marker to the next ## heading, markup-tolerant on the emphasis spans), and its banner comment enumerates the same ordered arms. (2) #1153 — a Status-blurb authoring checklist, and this paragraph is its first live exercise. ## Releasing gains a ### Status-blurb authoring checklist subsection: seven items distilled from the recurring release-prose overclaim lesson — bound every absolute, repeat the guard's own scope word, name a property of a diff rather than the repo's shape, carry a conditional's condition, scope a "no X change" label instead of leaving it bare, restate an appositive's subject, and the provenance pointer. Overclaims here are semantic, so no lint can judge them; the checklist is an authoring-time surface, not a linter. version-slots.test.mjs gains a presence lock, deliberately light: the subsection heading plus one distinctive anchor token that lives in a bullet body, never a byte-pin of the bullet prose — so a wording tweak stays a one-file change, while deleting the bullets and keeping the heading still reds. Its extraction anchors on the \n## Releasing heading boundary rather than a bare first-occurrence search — the defensive idiom the Status-token reader already records, after a table row quoting ## Status in backticks turned out to precede that real heading. It is a separate reader from the existing four-slots undersell guard; that guard's own extraction is unchanged. The second new row is the both-ways half: a ## Releasing region string with the entire subsection absent, run through the same extraction-and-assert path and asserted red, so a lock that quietly stopped firing cannot read green forever. The two retirement greps #1153 also asked for were no-ops — both measured zero hits at this plan's base, so no README sentence was retired for them. (3) #1115 — ADR 0019's Amendment now names both routing sites. Its no-chaining clause characterized a baseline-proceed re-dispatch that then fails environment by the merge-site half alone, while its own next sentence already routed exhaustion by two sites. The clause now names both — soft env-blocked at the merge site, held:land-failed at the land site — mirroring ADR 0040 §B, which is the canonical source. The superseded original Decision text above the Amendment is byte-unchanged: an Amendment is edited in place, the Decision it supersedes is append-only. Because 0040 §B already carried the fact, the corrected clause is a new cross-ADR prose mirror, so its guard ships in the same phase: the new D25 row reads both ADRs and asserts the two-site characterization on each, so dropping a site on either ADR alone reds. On the 0019 side the key is scoped to the no-chaining clause — its own (ADR 0040 §B) cross-reference through to the start of the exhaustion sentence — not to the whole Amendment paragraph, because the following exhaustion sentence already carries merge site, land site and held:land-failed, and a paragraph-wide presence check would read green against the reverted single-site clause. Each extracted block is separately asserted to span its own baseline-proceed sentence, so a truncated extraction fails loudly instead of vacuously. (4) #1146 — the (N) lock numbering claim in lessons-learned-doc-contract.test.mjs. A banner parenthetical said the numbering restarts per banner. Walking that file's banners shows it does not: the numbering runs on across banners, with two backward jumps — the lessons-learned-seed banner resumes at (17), re-spending numbers an earlier banner had already used, and the banner carrying this correction starts over at (1), colliding the same way in the low numbers. The reworded parenthetical says that, tells a reader to cite an (N) together with its banner, and pins no terminal count literal, so appending a lock does not stale it. Comment lines only — no assertion, fixture, or expected value moved. (5) #1152 — the T2.9 census in provision-worktrees.test.sh. It claimed route identity rests on (b)+(c)+(d) together. The corrected census states the proof in two steps: (b)+(d) exclude the loud exit-3 routes, then (c)+(e) discriminate between the two silent ones — (c) proves the push is pre-receive-declined, so the post-push origin readback living inside the push_rc -eq 0 arm never ran, and (e) shows the origin tip still at the seed, which the readback-mismatch route cannot produce because it requires an advanced origin. The remaining loud dies (unresolvable HEAD, unresolvable <new-sha>) are closed by construction, since the call detaches at a resolvable SHA. Every changed line in that file sits inside a # comment — zero expect lines moved. (6) #1107 — the cross-summability ban now reaches the run total. war-review's §2 defensive-read bullet already banned cross-summing a transcript-mined split against an envelope total; the same bar now binds the run total for tool calls and tokens explicitly — it is envelope-sourced only when every phase carries an envelope, and any envelope/mined mix renders n/a (mixed-source) rather than a silent sum, since the roughly 20× transcript undercount makes such a sum disinformation, not approximation. §3's metric table gains a preamble binding its total tool calls and total tokens rows to that §2 rule, so a reader of §3 is sent to the ban rather than reading those two rows as a standalone render instruction — a prose coupling, not a new mechanical guard. Per-phase cells' sourcing is unchanged. (7) #1096 — a floor/tooling config mismatch is not a plan defect. agents/war-worker.md gains one paragraph immediately after the PLAN-DEFECT: paragraph; that PLAN-DEFECT: paragraph is byte-unchanged. A floor/tooling config mismatch — the shape a threaded floor_diagnostic naming the active test-pattern set and suggesting --pattern / overrides.testPattern has — is run configuration, not a plan defect, so the worker blocks quoting the diagnostic verbatim and without the PLAN-DEFECT: prefix. The paragraph says what that omission buys, matching what the live classification does: only that literal prefix sets defectClass: 'plan', and only that tag auto-routes an escalation to a /red-team plan amendment, so leaving it off keeps the escalation in ordinary Lead adjudication as a config question. That edit is to the standing worker card; the dispatched worker prompt is untouched.
MIT © Ljferrer