Skip to content
Use this GitHub action with your project
Add this Action to an existing workflow or create a new one
View on Marketplace

Repository files navigation

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

gates npm node license


Table of Contents
  1. About The Project
  2. Built With
  3. Getting Started
  4. Usage
  5. What it reports
  6. The evidence
  7. What is not claimed
  8. Roadmap
  9. Contributing
  10. License
  11. Contact

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 Node.js Vitest Biome Zod

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.

(back to top)

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.

(back to top)

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.

(back to top)

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.

(back to top)

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 single byte, exit 0 and exit 1 side by side, with a script to reproduce it: tamper demo.
  • A bundle verifies on a machine that has never seen this repo. Run in a node:24 container with no network and no mount of this repository: clean-container-verification.md.
  • A green verdict is computed by the harness, and the model cannot produce one. In a real run the model asserted a predicate the language does not parse; the harness rendered it UNVERIFIED and carried on, twice: shakedown results.

(back to top)

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. Zero crashes at a fuzz budget is evidence, not proof.
  • The default execution mode is restricted, not isolated. A lexical path and program policy in front of interpreters unless you pass --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 half of it. Every task carries two oracles, one handed to the tool and one held back from it, and fifteen certified patches cannot say more than "under 20%": 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 bonds hold, which is the finding rather than a fix: a patch written to satisfy a visible test has its added lines tested by that test, so the oracle refuses every mutant of them and is right to. Bonding asks whether the oracle judged what the patch added. It cannot ask what the patch left out, and that is what an adversarial patch does.
  • The denominator moved when the tool did, and that is a cost. Four patches both oracles accept are refused because the tool's own oracle never ran part of what they changed, five more because the sealed half rejects work the held-back half accepts, and one because its oracle accepted a change to a line it had run. A tool that refuses more has fewer claims to be wrong about, so the interval over what is left is wider. Both halves are reported, and a refusal is never counted as a pass.
  • Every number here has been wrong at least once, and the corrections are in the history. A reported zero was withdrawn as self-agreement. A patch was refused over a TypeScript declaration file, which hid a real false green behind a wrong refusal. Two mutation operators were producing changes that changed nothing until an audit read every refusal by hand. The pattern is the same each time: read what a check names before believing it.
  • Twelve tasks reported as unjudgeable were the agent having written nothing at all, which is a model failure and is recorded as one. An earlier 0-of-18 was withdrawn as arithmetic rather than corrected quietly: the same test was handed to the tool and then used as the ground truth it was scored against, so it agreed with itself.
  • Six known gaps ship open, and none is claimed closed. Four have detections built against them and have not yet been attacked, so what is claimed is a detection and not a closure.
  • A signature does not make the machine honest. It proves the bundle was not altered after it left the machine that produced 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.

(back to top)

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.

  • Connect verification, displayed acceptance, cancellation, budgets and recovery to the records that establish them. Use standard DSSE signing bytes and literal replacement text.
  • Build the campaign machinery: separate case author, checker and solver models; admission controls before grading; frozen schedules; actual baseline dispatch; every failed launch retained; raw evidence that can be checked from the checkout.
  • Run the available Docker security and cleanup matrix. Fourteen declared observations passed, with working attack controls and a separate check that ordinary work still runs. Repair after abrupt harness death was exercised too.
  • A false-green interval that supports a population claim. The historical 0 in 15 has a 20.4% upper bound. The new synthetic pilot admits one evaluation case and cannot narrow that bound for real work. Freeze an independent population and a sufficient sample first.
  • A denominator the tool did not choose. The new admission pass checks references and predetermined counterexamples, but model authorship alone does not establish independence or complete requirements. Independent admission and review are still needed.
  • An adversarial verification corpus that covers omitted requirements. Separate local models supplied fresh checks and attacks. Mutation of added lines still cannot establish that a patch implemented something it left out; the report keeps those outcomes visible.
  • Task success non-inferior to the strongest alternative. The two local baseline arms now execute, with matched tasks and budgets. This pilot is too small to establish which tool is strongest or to support a non-inferiority claim.
  • Security evidence for every supported backend. Docker was measured here; Podman and nerdctl were unavailable. Independent attacks and those runtime matrices remain open.
  • No surviving daemons across the supported runtime boundaries. Docker cleanup passed the declared lifecycle cases. Restricted host execution still cannot own a descendant that leaves its process group; abrupt harness death requires supervision or later repair.
  • A new user productive in under ten minutes. The fixture and observer procedure are ready. No new users were observed, so setup checks cannot close this item.

Each broader claim stays open until its own evidence meets the bar in docs/beta-gates.md.

(back to top)

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.

  1. Fork the Project
  2. Create your Feature Branch (git checkout -b feature/AmazingFeature)
  3. Run npm run gates and paste the real output in the PR
  4. Commit your Changes (git commit -m 'Add some AmazingFeature')
  5. Push to the Branch (git push origin feature/AmazingFeature)
  6. Open a Pull Request

New dependencies need a one-line justification; the standard library is preferred. docs/build-guide.md is worth reading before structural work.

(back to top)

License

Distributed under the ISC License. See LICENSE for more information.

(back to top)

Contact

Brad Kinnard, @KChackerman, bradkinnard@proton.me

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.

(back to top)

About

Contract-first swarm orchestration for AI coding agents, with parallel execution, deterministic verification, adaptive repair, and auditable integration recovery.

Topics

Resources

Stars

111 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages