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.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.openrpc.json: the generated public API surface. Use it for runtime/RPC questions instead of grepping handler code./reference/field-index: human-friendly orientation across every YAML field, with links to the deeper docs for each.tests/: 200+ test bundles, all of which passswarm verify— the most reliable way to learn a pattern is to find a bundle that already uses it.
review_artifact_boundary: private review/audit/maintainer notes are not binding. Onlyplatform-spec.yamlcontent (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.- Sketch the minimum that should verify: one input event, one system node, one transition to a terminal state. Get to
verify okfirst. - Run
swarm verify --contracts ./your-flow: fast, offline, no DB, no Docker, no LLM credential. Treat it as your compiler. - 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 inplatform-spec.yamland on/reference/analyzer-checks. - Add one thing, re-verify. Three small iterations beat one large one.
- 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. swarm run startis 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. Theevent publish
pattern below is for skipping the agent entirely and driving the deterministic half (CI,
repeated iteration, no token spend):
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.
- Version: commit hash from
swarm version --server, or justgit rev-parse HEADof 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 startvsswarm 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.
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 withplatform_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

