swarm-orchestrator
Local-capable coordination for completing bounded engineering goals with evidence.
The model can say whatever it likes.
It cannot make a gate pass, mark a claim verified, or change a record after the fact.
Explore the docs »
See a real run
·
Report Bug
·
Request Feature
About The Project
Give it a substantial goal and a git repository. Swarm plans the work, dispatches only ready tasks, integrates one candidate at a time, repairs failures against the current tree, and checks the complete goal. What comes back is a reviewable branch plus a signed, hash-chained record of what ran, what passed, and what nobody measured. Anybody can check it without installing this tool.
| | |
| --- | --- |
| Make a bounded change | It declares the files it intends to touch, edits through a chokepoint that records every tool call, runs your gates, and retries failures under a numeric ratchet that refuses a fix trading away tests, assertions or coverage. |
| Verify anybody's patch | swarm ci clones the base commit somewhere the producing tree cannot reach, applies the patch there, and runs the checks in that checkout. Nothing the producer said travels except the patch. |
| Say what a result does not establish | A run reports nine answers rather than a boolean, and unmeasured is one of the values. "Nobody checked" and "checked and failed" are different findings, and flattening them is how a change nothing executed comes to read green. |
For a cross-component change, use the goal controller:
swarm parallel --goal "Add pagination through storage, the API, the SDK, and maintained tests" \
--model local:qwen3.6:35b-a3b --max-tokens 200000
The controller shares one budget, starts dependents when their prerequisites land, and creates bounded repair work when a clean merge fails behaviorally. Tiny or tightly coupled goals stay with one worker. The result names accepted requirements, blockers, the integrated branch, and its evidence.
Built With
[![TypeScript][TypeScript]][TypeScript-url] [![Node.js][Node.js]][Node-url] [![Vitest][Vitest]][Vitest-url] [![Biome][Biome]][Biome-url] [![Zod][Zod]][Zod-url]
Durable state is an append-only JSONL journal, with a read-only importer for older SQLite sessions. The verifier a bundle carries is dependency-free by design, so checking somebody's evidence needs nothing but Node.
Getting Started
Prerequisites
Node 24 or newer. A runtime floor rather than a preference: the coverage cycle spawns the test
runner with --test-isolation=process, which Node 22 rejects as a bad option, so on anything older
that measurement does not happen.
A model, frontier or local:
export ANTHROPIC_API_KEY=... # or OPENAI_API_KEY, GOOGLE_GENERATIVE_AI_API_KEY
or start Ollama / rapid-mlx and pass --model local:<id>
Keys come from the environment or your OS keychain, never from swarm.toml, which is
committed and cloned, so a key in it has already been shared with everyone holding the repository.
Installation
npm install -g swarm-orchestrator
That is 14.1.0, and it leaves swarm on your path. If swarm turns out to be an older version
than you installed, swarm doctor says what owns the command and --fix repairs it.
The adaptive controller and its measured release evidence are recorded in the implementation record.
Anything below 13 is a different program: this package name carried a pull-request auditor through 12.x. Pin the major if you depend on one or the other.
Usage
swarm "make slugify collapse whitespace and strip punctuation"
Real output, swarm gates over a two-test project:
passed tests: 2 collected, 2 passed, 0 failed, 0 skipped (exit 0)
passed placeholder: no placeholder marker was introduced by this change
passed secret-scan: no known credential pattern appears in the added lines
n/a typecheck: package.json declares no typecheck script
bonds, one per gate that passed:
tests: held. the tests gate refused the bond: 3 collected, 2 passed, 1 failed, 0 skipped
secret-scan: held. the secret-scan gate refused the bond: 1 added line(s) match a known
credential pattern: swarm-falsification-bond.env.example.js:1 (github-token)
acceptable: yes (no blocking gate failed, no policy gate failed, and something executed the change)
A pass is a claim until it is shown able to fail. After the gates go green, each one that passed is handed a bond: one file it has to refuse. A check that refused it held. A check that passed over a bond it demonstrably saw is vacuous, and a vacuous blocking gate makes the run not green whatever the cycle said.
The four commands most people need:
swarm # a session: type tasks, one after another
swarm gates # run the gates over a workspace, no model
swarm ci --patch <file> # verify a patch in a fresh checkout of the base
swarm verify <bundle> --signer <f> # check a bundle, and who signed it
Every command and flag is in docs/cli.md. Sessions, several workers at once and
swarm.toml are in docs/using.md.
What it reports
Nine answers, not one. unmeasured is a value, not a missing one:
mechanical unmeasured
every static gate stood down (typecheck, lint, format)
behavioral pass
tests passed
semantic unmeasured
task unjudged
no trusted task oracle was configured for this run
executionTrust restricted
commands ran under a lexical path and program policy, which is not containment
That run passed its tests, so behavioral is a pass, but it declares no typecheck, lint or
format script, so mechanical is unmeasured rather than a pass. A change whose only passing
gate was a linter is not a change anything ran, and the reverse holds too. semantic abstains by
construction, because judging whether a change means what was asked is a judgement about meaning,
and nothing here is allowed to make one.
swarm ci reports two answers where a suite gives you one: regression says nothing broke,
task says the work was done, and only an oracle can say the second. Four of eighteen
real-repository patches passed their project's whole suite and failed a hidden acceptance test.
And it judges the oracle it was handed, not only the patch. Three ways an oracle can fail to be evidence, and all three are checked:
| the oracle | the tool says | why |
| --- | --- | --- |
| accepts the base commit too | task: vacuous | it would have accepted a patch that changes nothing |
| never ran the lines the patch adds | oracleReach: unreached, lines named | it cannot have judged what it did not execute |
| ran them and accepts a change to them | oracleBond: vacuous, mutant and witness printed | it executed the code without asserting anything about it |
All three came out of measuring this tool against real work rather than from reasoning about it.
Certified tasks rested on oracles that could not fail. The first false green found was certified by
an oracle that never ran the branch it broke. The last one standing, commander#1671, was
certified by an oracle that runs every line the patch adds and never tests the precedence those
lines decide, so bonding hands it that same line with the .reverse() dropped and the oracle
passes it.
There are eight mutation operators, read off the language's own statement productions rather than
off the patches that exposed a gap in them, so a guard clause, an assignment and a require all
have something asked of them. Removing a statement is confirmed against node --check first,
because a file that no longer compiles is refused by every oracle and crediting that refusal would
be crediting a syntax error. And a vacuous verdict now says what showed the mutant changed
anything: the oracle's own coverage running a different set of lines, or the repository's own suite
failing where it passed. A refusal nothing witnessed says that too, which is what makes the audit a
named set rather than every verdict.
Reach is read from whichever coverage the oracle's own runner can be made to write: node's lcov
reporter, V8's own coverage for a runner that loads the file as written, or jest's and vitest's
own reports. A runner none of those fits reports unmeasured rather than a guess, and unmeasured
blocks nothing.
None of it is free, and the cost is reported rather than netted off. A patch that restructures
one assignment into an if and an else, judged by an oracle whose cases all take the if, is
refused with the else named. Refusals get their own names, refused-on-reach and
refused-on-bond: not the tool being wrong about the patch, and not a pass either. Only a bond the
oracle demonstrably saw and passed refuses. One that could not be built, or that nothing shows the
oracle read, is reported and blocks nothing, because an absence of evidence about the oracle is not
evidence against it.
Full detail in docs/verifying.md.
The evidence
Every claim this project makes links to a committed artifact of the thing happening. The full table is docs/claims.md. Three of them:
- One changed byte breaks verification. The same bundle verified and then tampered with in a
- A bundle verifies on a machine that has never seen this repo. Run in a
node:24container
- A green verdict is computed by the harness, and the model cannot produce one. In a real run
UNVERIFIED and carried on, twice:
shakedown results.
What is not claimed
It is not production-ready. Of the gates this project agreed not to call itself production-ready without, the historical assessment records eight passing, two partial, two unproven, and two reported rather than barred. Those counts describe the linked campaigns, not a fresh measurement of every gate on this checkout. The old "zero false greens in 400 held-out tasks" gate is retired, for four reasons that are measured rather than argued, and replaced by three statements about three different questions. Each row and what would settle it: docs/beta-gates.md.
- Not "fully secure". The secret detector does known-pattern scrubbing, not secret removal.
- The default execution mode is
restricted, notisolated. A lexical path and program policy
--isolation. Reported before the run starts and
recorded on the chain rather than quietly assumed, but it is not containment.
- The September 6 mined-corpus rate was 0 in 15, 0.0%, 95% CI [0.0, 20.4], and that upper bound is the honest
mined-corpus/. Those tasks came from real pull requests, where maintainers test what they cared about
rather than what the author of a tool thought to check. That historical rate is not a rate for
the current build or for the separate synthetic campaign. The one that used to stand,
commander#1671, is refused now because its oracle accepted a change to a line it had run.
- Shown its oracle, a model still gets past this. Both of those patches now get a bond and both
- The denominator moved when the tool did, and that is a cost. Four patches both oracles
- Every number here has been wrong at least once, and the corrections are in the history. A
- Twelve tasks reported as unjudgeable were the agent having written nothing at all, which is a
- Six known gaps ship open, and none is claimed closed. Four have detections built against them
- A signature does not make the machine honest. It proves the bundle was not altered after it
Gates prove mechanical quality, not design quality. What a bundle buys you is that reviewing the change is fast and its claims are checkable, not that review is unnecessary.
Roadmap
The implementation is ahead of the evidence needed to call this production-ready. The audit repairs are recorded in the implementation record; the local campaign and every excluded case are in the September 11 report.
- [x] Connect verification, displayed acceptance, cancellation, budgets and recovery to the
- [x] Build the campaign machinery: separate case author, checker and solver models; admission
- [x] Run the available Docker security and cleanup matrix. Fourteen declared observations
- [ ] A false-green interval that supports a population claim. The historical 0 in 15 has a
- [ ] A denominator the tool did not choose. The new admission pass checks references and
- [ ] An adversarial verification corpus that covers omitted requirements. Separate local
- [ ] Task success non-inferior to the strongest alternative. The two local baseline arms now
- [ ] Security evidence for every supported backend. Docker was measured here; Podman and
- [ ] No surviving daemons across the supported runtime boundaries. Docker cleanup passed the
- [ ] A new user productive in under ten minutes. The fixture and observer procedure are ready.
Each broader claim stays open until its own evidence meets the bar in docs/beta-gates.md.
Contributing
The bar is the one the tool applies to itself: npm run gates green with the output shown, new
behaviour covered by a test that failed first, and no claim in a document that its linked artifact
does not establish.
- Fork the Project
- Create your Feature Branch (
git checkout -b feature/AmazingFeature) - Run
npm run gatesand paste the real output in the PR - Commit your Changes (
git commit -m 'Add some AmazingFeature') - Push to the Branch (
git push origin feature/AmazingFeature) - Open a Pull Request
License
Distributed under the ISC License. See LICENSE for more information.
Contact
Brad Kinnard, @KChackerman, [email protected]
Project Link: github.com/moonrunnerkc/swarm-orchestrator
Upgrading from v12? It was a PR auditor that ran as a GitHub Action; v13 and later are a coding
agent. Same package name, different product, no migration path: stay on the v12-final tag. See
CHANGELOG.md.
[TypeScript]: https://img.shields.io/badge/TypeScript-3178C6?style=for-the-badge&logo=typescript&logoColor=white [TypeScript-url]: https://www.typescriptlang.org/ [Node.js]: https://img.shields.io/badge/Node.js-5FA04E?style=for-the-badge&logo=nodedotjs&logoColor=white [Node-url]: https://nodejs.org/ [Vitest]: https://img.shields.io/badge/Vitest-6E9F18?style=for-the-badge&logo=vitest&logoColor=white [Vitest-url]: https://vitest.dev/ [Biome]: https://img.shields.io/badge/Biome-60A5FA?style=for-the-badge&logo=biome&logoColor=white [Biome-url]: https://biomejs.dev/ [Zod]: https://img.shields.io/badge/Zod-3E67B1?style=for-the-badge&logo=zod&logoColor=white [Zod-url]: https://zod.dev/