Skip to main content
Swarm flows are pure declarative YAML. The platform spec is machine-readable on purpose, the analyzer is fast and offline, and the conformance suite ships 200+ verifying bundles you can grep. This page is what to read first and what loop to run if you are an LLM agent helping a human author a Swarm flow.

Pull these first

Ranked by how authoritative they are. Read them in order; do not skip past one expecting the next to make up the gap.
  1. platform-spec.yaml: the source of truth for every field, every value, every check id — if this page and any doc disagree, the spec wins. Machine-readable YAML, designed to be queried.
  2. openrpc.json: the generated public API surface. Use it for runtime/RPC questions instead of grepping handler code.
  3. /reference/field-index: human-friendly orientation across every YAML field, with links to the deeper docs for each.
  4. tests/: 200+ test bundles, all of which pass swarm verify — the most reliable way to learn a pattern is to find a bundle that already uses it.
Two governance rules in the spec to internalize before authoring:
  • review_artifact_boundary: private review/audit/maintainer notes are not binding. Only platform-spec.yaml content (and what generates from it) is authoritative. Do not cite an internal-looking artifact as if it were the spec.
  • platform_namespace_violation: platform.* event names are reserved. Don’t emit them from a flow.

The author loop

Run this loop, not a freestyle “write the whole thing then verify” pass.
  1. Sketch the minimum that should verify: one input event, one system node, one transition to a terminal state. Get to verify ok first.
  2. Run swarm verify --contracts ./your-flow: fast, offline, no DB, no Docker, no LLM credential. Treat it as your compiler.
  3. Read analyzer errors literally. They cite a check id (e.g. entity_writer_coverage, event_producer_exists, transition_reference_validation), a scope ([root], [<state>], [<event>]), and the exact field or path. The check id is searchable in platform-spec.yaml and on /reference/analyzer-checks.
  4. Add one thing, re-verify. Three small iterations beat one large one.
  5. When you need a pattern you haven’t authored before, grep tests/ for the construct (grep -rln "rules:" tests/, grep -rln "mailbox_write" tests/, etc.). Read a bundle that uses it; mirror its shape.
  6. swarm run start is the fastest end-to-end check: it boots a runtime in-process, fires one event, exits when the run quiesces. No DB service, SQLite by default; use it for one-shot deterministic flows.
For flows that need follow-up interaction (timers, human mailbox decisions, multiple external events), use swarm serve instead and drive it with the CLI from a second terminal; see Running the runtime → swarm run vs swarm serve.

Cost-free testing of agent-flow contracts

A flow that declares agents normally needs an LLM credential to advance past agent deliveries. For agent turns themselves, use the mock backend — zero credentials. The event publish pattern below is for skipping the agent entirely and driving the deterministic half (CI, repeated iteration, no token spend):
This works because the deterministic engine treats agent emissions and operator emissions identically; both are just events. Your handler advances regardless of who produced the trigger.
swarm event publish reliably starts a run from a root input-pin event. Injecting a follow-up event into a run that is already going is not yet reliable — use swarm test scenarios or a long-lived swarm serve for multi-step offline tests.

Implementation gaps: expected, tracked, fix them with us

Swarm is pre-1.0. Gaps between the docs and the implementation, and between the spec and the binary, are a known class of issue and are being closed actively. When you encounter one:
  • Treat the spec as binding when it disagrees with the docs. The docs aim to track the spec; when they drift, that’s a docs bug.
  • Treat the binary as the bug when it disagrees with the spec. That’s a runtime issue.
  • File it. Concrete repros in the issue tracker get turned around quickly; a repro is the highest-leverage thing you can contribute.
A good gap report has:
  • Version: commit hash from swarm version --server, or just git rev-parse HEAD of the swarm checkout.
  • Repro: smallest verifying bundle that exhibits the behavior (package.yaml, schema.yaml, events.yaml, nodes.yaml, plus any others). 5-10 lines per file beats a 50-file dump.
  • Expected vs observed: spec citation or docs citation for “expected”; literal output for “observed.”
  • Surface: SQLite vs Postgres, swarm run start vs swarm serve, etc. Gaps often live on one path and not the other.
  • One issue per defect class. Don’t bundle a routing bug with a docs typo.
For known gaps currently under work, browse the open issues on the swarm repo. Search before filing. The most useful filter is the symptom itself (mailbox, entity.list, event publish, lint_evidence, etc.); the issue tracker is the live source for “is this me, or is this a known thing.” If your symptom doesn’t match anything open or recently closed, file fresh.

Anti-patterns

  • Don’t invent fields not in the spec. The analyzer rejects them with UNDEFINED-FIELD. Faster to grep the spec first.
  • Don’t ship a flow that fails swarm verify. The “boot only on a flow that verifies” pitch is the contract; a non-verifying flow is incomplete, not “almost done.”
  • Don’t redeclare events the platform owns. Platform-emitted events (mailbox.item_decided, platform.run_stalled, etc.) are auto-registered; subscribe directly. Redeclaring them locally now fails verify with platform_namespace_violation.
  • Don’t model intent in YAML comments and expect the engine to read them. The engine reads structure, not prose. If a behavior matters, it’s a field somewhere.
  • Don’t infer field types from JSON Schema in platform-spec.yaml’s OpenAPI section. Swarm’s contract type system has its own scalars (text, integer, numeric, boolean, timestamp, uuid) plus named types. The OpenAPI portion describes the runtime API, not authoring types.
  • Don’t bypass the analyzer because “the runtime will catch it.” It probably won’t; the analyzer is the strict layer, and the runtime trusts what the analyzer accepted.

Minimum-viable verifying flow

If you need a starting skeleton, this verifies and runs end to end on SQLite default with no credentials:
greeting-flow/package.yaml
greeting-flow/schema.yaml
greeting-flow/events.yaml
greeting-flow/nodes.yaml
Four files, two commands, no credentials, no Docker, no DB. This is the smallest thing that proves your environment works; everything else extends from here.

When in doubt

The spec wins. The analyzer is the contract. Issues get fixed. File the gaps.