Agentic Engineering

SwarmForge Reviewed: How Uncle Bob's Agent Swarm Actually Works

Six AI agents, six git worktrees, one durable message queue, and a set of quality gates that are shell commands rather than good intentions. The tmux part is the least interesting thing about it.

The Problem It Is Built to Solve

Give one coding agent a real feature and it will write the implementation and the tests in the same breath, from the same understanding, with the same blind spots. If it has misread the requirement, the tests encode the misreading and pass. Ask that same agent to review its own work and it will agree with itself, because the reasoning that produced the code is still in its context and still looks sound. Volume makes this worse rather than better: the output is plausible, abundant, and cheap, so the reviewing human becomes the bottleneck and starts skimming. SwarmForge is a bet on a specific answer to that: quality cannot come from the author, so give every reviewing discipline its own agent, its own context, its own working tree, and a check that either exits zero or does not.

The load-bearing design decision is not parallelism. It is that roles communicate only through committed code. A reviewing agent never sees the author's explanation of why the code is fine — it sees a commit and a task name, and it runs its own tools against them.

What It Is, Mechanically

SwarmForge is a shell and Babashka harness around primitives most teams already have. Each role is a tmux window running one agent CLI against its own git worktree under .worktrees/, so no two agents ever touch the same working tree. Behaviour comes from plain text: a constitution.prompt that claims precedence over everything else and tells the agent to read and obey every file in swarmforge/constitution/articles/ on startup and on every task, plus a role prompt at swarmforge/roles/<role>.prompt. Shared articles cover engineering rules, handoff rules and workflow; local articles are where a project overrides them. Communication is a file-based queue owned by a daemon, and the only two message types an agent may send are a git handoff and a note. The ./swarm script is a thin bootstrap: it fetches the scripts archive if the directory is missing and then hands off to swarmforge/scripts/swarmforge.sh.

Three Swarm Shapes

Each branch is a different answer to how much process a task deserves. main is documentary; the runnable topologies live on the pack branches. The flow is a ring, not a queue.

two-pack

coder → cleaner → coder

A coder working test-first and a cleaner doing cleanup, CRAP and DRY review, and architectural fixes. The smallest loop that still separates writing from judging, and the only shape whose cost is easy to justify on ordinary work.

four-pack

specifier → coder → refactorer → architect → specifier

Gherkin acceptance specs enter at the front. A refactorer does behaviour-preserving cleanup and coverage, and an architect reviews structure and dependency direction before the ring returns to specification.

six-pack

specifier → coder → cleaner → architect → hardener → QA

Adds a hardening pass that mutates the code to find where the suite is blind, and an independent QA role that verifies through the user interface. Four of the six roles run in batch mode so whole-repo tooling amortises over a priority band.

How One Change Actually Travels the Ring

This is the six-pack, and it is worth reading as a pipeline of exit criteria rather than a list of job titles. Each row is a role prompt in the repository, and each exit condition is a command that has to succeed.

1

specifier

→ coder
Receives
A request from the human, in the master worktree
Does
Writes Gherkin acceptance specifications and the end-to-end QA suite specification, asks questions where intent is ambiguous, and prunes example parameters down to the values that actually affect acceptance mutation.
Exit criteria
Does not commit until the human explicitly approves. That is the one human gate in the ring, and it is at the front where it is cheapest.
2

coder

→ cleaner
Receives
A git handoff naming a commit and a stable task name
Does
Writes focused unit tests that express the requested behaviour and, in the role prompt's own words, would fail for a plausible wrong implementation. Then writes only enough production code to pass them. Generated acceptance tests are explicitly not accepted as a substitute for unit tests.
Exit criteria
Local verification passes. It does not run mutation, CRAP or DRY — those belong to later roles, so the coder cannot grade its own work.
3

cleaner

→ architect
Receives
A batch of equal-priority handoffs
Does
Runs the CRAP tool first and drives complexity down to 6 or below, then the DRY tool to remove duplication, then the mutation tool in scan-and-count mode only — splitting any file that exceeds 100 mutation sites — and raises coverage where reasonable.
Exit criteria
Behaviour unchanged, tests still green, complexity and duplication reduced. Explicitly forbidden from running mutation tests or adding behaviour.
4

architect

→ hardener
Receives
A batch of cleaned commits
Does
Partitions code into modules with real boundaries, keeps dependencies pointing inward, hunts cycles and framework leakage, and isolates application policy from UI, filesystem, database and network. Adds automated architecture checks where practical.
Exit criteria
Behaviour preserved and the suite green. Forbidden from running git merge by hand: merging happens only through ready_for_next.sh.
5

hardener

→ QA
Receives
A batch of structurally reviewed commits
Does
Runs the language mutation tool one file at a time, differentially against existing manifests, with up to eight parallel workers, and fixes surviving mutants before moving on. Then a soft-level Gherkin acceptance mutation pass, then CRAP, then DRY, in that exact order.
Exit criteria
Every tool in the chain clean before the next one runs. This is the role that decides whether the tests actually test anything.
6

QA

→ specifier
Receives
A batch of hardened commits
Does
Independent final verification: the acceptance specification, the end-to-end suite driven through the user interface with no API shortcuts, unit and property tests, and project release checks. Reproduces any failure before changing code.
Exit criteria
Runs CRAP and DRY again before completing. If the QA suite contradicts the Gherkin or the unit tests, it stops and asks a human rather than picking a winner.

The Transport Is the Unusual Part

Most agent frameworks let agents talk to each other. SwarmForge deliberately does not: a daemon owns delivery, the filesystem is the queue, and tmux is used only to poke an idle window.

The topology is one config file

conf

The shipped six-pack puts every role on the same backend with permission bypass enabled, and marks the whole back half of the ring as batch consumers. The role name must match the prompt filename, which in this repository is spelled hardender.

# swarmforge/swarmforge.conf
# window-invisible <role> <agent> <worktree> [task|batch] [extra-cli-args...]
window-invisible specifier codex master           --yolo
window-invisible coder     codex coder            --yolo
window-invisible cleaner   codex cleaner    batch --yolo
window-invisible architect codex architect  batch --yolo
window-invisible hardender codex hardender  batch --yolo
window-invisible QA        codex QA         batch --yolo

The queue is a directory, and file location is state

text

There is no database and no in-memory broker. A handoff's position in the tree is its status, the filename sorts by priority then time, and the headers carry the audit trail. A crashed swarm resumes by reading the disk.

.swarmforge/handoffs/
  outbox/
    tmp/            # drafts land here, then get renamed in atomically
  sent/
  failed/           # malformed or undeliverable, with diagnostics
  inbox/
    new/
    in_process/
    completed/

# filename sorts the queue for you
<priority>_<timestamp>_<sequence>_from_<sender>_to_<recipients>.handoff
# priority 00-99, lower first; UTC YYYYMMDDTHHMMSSZ

An agent may only ask, never deliver

sh

The agent writes a draft with four headers and calls the gate script. It cannot write id, from, recipient or any timestamp — those are reserved, so provenance in the audit trail cannot be forged by the thing being audited. It also does not type a SHA: the script canonicalises and validates the commit as a real, unambiguous ten-character object.

# ./tmp/handoff.txt — drafted inside the assigned worktree
type: git_handoff
to: hardender
priority: 00
task: task-1-cave-setup

# hand it to the protocol gate; the daemon does delivery
swarm_handoff.sh ./tmp/handoff.txt

# receiving side, driven by the role's mode in .swarmforge/roles.tsv
ready_for_next.sh     # -> TASK: / BATCH: / NO_TASK, plus the payload
done_with_current.sh  # -> stamps completed_at, then pulls the next item

The gates the hardener has to clear, in order

sh

This is what makes the swarm more than role-play. The constitution installs these tools fresh from the author's own repositories at startup — crap4go, crap4java and crap4clj for complexity, mutate4go, clj-mutate and mutate4java for mutation, and the dry4* family for duplication — and the role prompt fixes the order they run in.

# hardener: nothing advances until the previous check is clean
mutate4go ./...            # one file at a time, differential, <= 8 workers
gherkin-mutator --level soft   # mutate the acceptance examples too
crap4go ./...              # complexity against coverage
dry4go ./...               # duplication

# then, and only then
swarm_handoff.sh ./tmp/handoff.txt   # to: QA

Why Each Mechanism Is Shaped That Way

Read as engineering, most of the odd-looking choices are defences against specific agent failure modes.

The message is a commit, not an explanation

A git handoff carries a task name and a validated commit. It cannot carry the author's argument for why the code is good, because an argument invites the next agent to agree with it. A commit invites verification instead. This is the single most transferable idea in the project.

Wake-ups are generic and allowed to be lost

The daemon's tmux notification says only that mail has arrived and to run ready_for_next.sh if idle. It never names a file, so an agent cannot cherry-pick the interesting item and skip the queue order, and a busy agent can safely ignore it because completing a task also pulls the next one.

Notes are capped at eighty characters and discouraged

Agents may send a freeform note only when a human, the role prompt or the constitution explicitly says to. Faced with ambiguity or contradiction the instruction is to stop and ask a person. That is a deliberate refusal to let agents negotiate requirements with each other, which is where multi-agent setups usually go quietly wrong.

Each role gets a worktree, not just a branch

Isolation is at the filesystem level, so the entire class of failures where two agents edit the same file at the same moment cannot occur. It also makes every role independently inspectable while it works, which matters more than it sounds when you are trying to work out what a swarm did.

The back half of the ring consumes batches

Cleaner, architect, hardener and QA take every queued handoff at the same priority as one unit. Mutation runs, coverage runs and architecture checks are expensive per invocation and cheap per extra file, so batching is the difference between a gate you run and a gate you disable.

The standard is a prompt tree with explicit precedence

constitution.prompt claims authority, articles carry the rules, local articles override for the project, role prompts sit on top, and the agent is told to re-read all of it on every task. Your coding standard stops being a document about the work and becomes an input to it.

The Verdict

The valuable half of SwarmForge is the constitution and the gate ordering: named roles with single responsibilities, exit criteria that are executable commands, and a hard rule that the author of a change never grades it. That half is genuinely good, it is language-agnostic in spirit, and you can implement it this quarter in whatever CI you already run — no tmux involved. The other half, the daemon and the durable file queue, is beautifully built and mostly solving a problem you can avoid: if your gates run in CI on a pull request, you get durability, audit trail and priority ordering for free from tools your team already operates.

Read it as a reference implementation of a workflow, not as a platform to adopt. Start with the two-pack to feel whether split roles help your work at all, steal the gate chain regardless, and reach for the six-role ring only when the cost of a defect clearly exceeds the cost of six agent runs per change.

What It Gets Right

  • + Quality gates are commands with thresholds — mutation, CRAP, DRY, coverage — instead of adjectives in a style guide
  • + The reviewer never sees the author's reasoning, only a commit, which is the only way agent review is worth anything
  • + Ordering matches real engineering sequence: specify, implement, clean, restructure, harden, verify independently
  • + Worktree isolation eliminates concurrent-edit corruption by construction rather than by locking
  • + Queue state lives on disk with an audit trail agents are structurally unable to forge, so a crash resumes and a run can be reconstructed
  • + The single human approval gate sits at specification time, where changing your mind is cheapest
  • + Everything is observable plain text — windows you can read, prompts you can edit, a queue you can list with ls

What It Costs You

  • The shipped configuration runs every agent with permission bypass, so the whole design assumes you are willing to let six agents execute commands unattended in your repository
  • Six agent runs per change is economically absurd for small work, and nothing in the ring decides that a task deserves less process
  • The executable toolchain is the author's own crap4*, mutate4* and dry4* projects for Go, Clojure and Java — outside those languages the constitution's startup contract does not apply and you supply your own equivalents
  • Reinstalling those tools fresh from GitHub on every startup is slow, network-dependent, and a supply-chain surface you now own
  • zsh, tmux and Babashka on macOS is the happy path; Windows means WSL and a terminal adapter shim
  • The chain-forwarding rule requires a role to forward downstream regardless of whether it changed anything, so the ring generates traffic even when a stage was a no-op
  • Role prompts are not enforcement: nothing prevents a role from skipping its own gate except the sentence telling it not to, so the real guarantees are only as strong as your CI copy of them
  • It is visibly in progress — a dashboard, a heat indicator, a window watchdog and diverging pack branches, with main deliberately not runnable

What to Borrow Even If You Never Run It

Never let the author grade the work

  • - Run the quality tools in a separate step, with a separate context, from the one that wrote the code
  • - Give the reviewing step the diff and the tools, not the author's rationale
  • - For agent workflows this is not process hygiene, it is the difference between a review and a rubber stamp

Turn every gate into an exit code

  • - Complexity, duplication, coverage and mutation survivors all have tools that return non-zero
  • - Fix the order they run in, and stop the pipeline at the first one that fails
  • - An agent acts correctly on a failing command and vaguely on a paragraph of advice

Make handoffs narrow, validated and auditable

  • - A commit reference plus a stable task name forces intent into the code and the message
  • - Validate at the boundary so a malformed request fails before the next stage wastes a run on it
  • - Keep provenance fields out of the sender's reach if you want the audit trail to mean anything

Keep the standard where the work happens

  • - Rules written as prompt articles are read on every task, unlike a wiki page nobody opens
  • - Separate shared rules from project-local overrides so one team's exception does not become everyone's rule
  • - Version them with the code and review changes to them like code

The Workflow Is the Contribution

Strip away tmux, Babashka and the tarball install, and what remains is a claim about software engineering: the disciplines that keep code habitable are separable, each deserves its own turn with its own instructions, and none of them can be performed credibly by the party that wrote the code. That was true before agents. What agents change is the stakes, because output volume went up and the reviewing human did not get faster.

So take the parts that survive translation. Name your passes and give each one job. Make every exit criterion a command. Put the human gate at specification time. Deny the author of a change any role in judging it. Whether that pipeline is six tmux windows, two engineers, or a CI file with five ordered jobs matters far less than whether the gates exist and actually run.

FAQ

What do you need to run SwarmForge?

zsh, git, tmux and Babashka, plus a configured agent CLI such as Claude, Codex, Copilot or Grok. There is no cloud service and no orchestration layer to stand up: the swarm is tmux windows you can watch, per-role worktrees on disk, and a queue of text files.

Which branch should a team start with?

two-pack. Two roles are enough to tell you whether separating writing from judging helps your work, and the cost of a six-role ring is very hard to justify before you know that. main is documentary and does not run a swarm.

Is it safe to run agents with permission bypass?

That is the biggest operational question the design leaves you. The shipped config passes bypass flags to every role, which is what makes an unattended ring possible at all. If you try this, do it on a disposable clone or a container with no credentials, and keep the real quality gates in CI where the swarm cannot skip them.

Does it only work for Go, Clojure and Java?

The orchestration is language-agnostic, but the executable gates are not. The constitution names the author's own mutation, CRAP and DRY tools for those three languages. On other stacks you keep the role structure and substitute equivalents, such as Stryker or PIT for mutation and any complexity-plus-coverage report for the CRAP calculation.

Does an agent swarm remove the need for QA?

No, and this design does not claim it does. It promotes QA into a named role with executable scripts and an explicit rule to stop and ask a human when the QA suite contradicts the specification. Somebody still has to know what the product owes its users, and somebody still signs off on the release.

What is the single idea most worth copying?

That the agent which wrote the code is the worst possible judge of it, and that the fix is a separate context holding a tool with an exit code. Everything else in the repository is an implementation detail of that sentence.

© 2026 - Ryware.