Skip to content

Building swarms — the complete playbook

This is the end-to-end guide to building a complete automated agent swarm on SwarmKit, the open-source AI platform runtime — from a single agent to a governed, multi-app delivery flow that your application sequences over weeks. It is written to be read top to bottom: each step adds exactly one capability, shows the smallest real artifact that unlocks it, gives the command to run it, and links to the deep reference.

If you only read one thing first, read the mental model. Everything else is a specialisation of it.

For LLMs and coding agents

The repo root ships llms.txt — a compact, link-rich map of every feature with inline schemas. Load it into context first; use this playbook for the ordered build recipe and the worked example.

The mental model

Three claims, in priority order — they are the tie-breakers for every design decision:

  1. Topology is data. A swarm is YAML/JSON the runtime interprets. There is no code-generation step and no "compile to Python" escape hatch — the portability guarantee is the openness of the artifacts plus the open-source runtime. A different swarm is new data, never new framework code.
  2. Skills are the only capability-extension primitive. When you want an agent to be able to do something new, you add a skill (or compose existing ones). You never bolt on a parallel capability mechanism. How a node executes — a model call vs. a coding harness — is a separate executor seam, not a capability.
  3. Swarms grow through human-approved authoring. The runtime records the capability gaps it hits; you surface them, author a skill through conversation, test it, and publish — gated at every step. A swarm you run is a swarm that tells you how to improve it.

Everything below is built out of a small vocabulary of artifact kinds. Learn these ten nouns and the two embedded configs and you can read any SwarmKit workspace.

The artifact kinds

Every artifact is a YAML/JSON file starting with apiVersion: swarmkit/v1 and a kind. There are eleven canonical schemas — ten standalone artifact kinds plus one embedded config (ApprovalPolicy, which lives inside a gate, not on its own).

Kind What it is Reference
Workspace The root manifest — names the workspace, picks the governance provider, wires servers/memory/canary. workspace
Topology A bounded swarm run — the agents, their roles, delegation edges, IAM scopes. The unit the runtime executes. topology
Archetype A reusable agent template — model/prompt/skills/IAM/executor defaults a topology node instantiates. archetypes
Skill A capability, decision, coordination, or persistence unit — the only capability-extension primitive. skills
Funnel A reusable per-artifact quality gate: validate → judge → review → approve, referenced by id from a node or stage. funnel
Contract An integration contract between apps — makes the lock ids your sequencer holds a checked, pickable vocabulary. contract
RoleRegistry Named roles → member identities + the scopes they confer — how approval rules resolve to real people. role-registry
Trigger An external event source (webhook/schedule) that starts a topology or delivers a signed event. trigger
ExecutorAdapter A declarative adapter (adapter.yaml) that runs a coding harness as a node — data, not per-harness Python. executor-adapter
ApprovalPolicy Embedded config (no kind) inside a gate's approve: — the multi-party rules, quorum, four-eyes floor. approval-policy

Step 0 — install and scaffold

uv is the recommended way to install and maintain SwarmKit — it installs swarmkit as an isolated global CLI, no virtual env or system-Python setup needed:

curl -LsSf https://astral.sh/uv/install.sh | sh   # if you don't have uv yet
uv tool install "swarmkit-runtime[ui]"       # the runtime, the `swarmkit` CLI and server, the portal
swarmkit init                                       # scaffold a workspace through conversation

The server is part of the runtime; [ui] adds the web portal swarmkit serve hosts (without it serve runs headless, API only) and [postgres] the Postgres backend. uv tool install swarmkit-runtime alone is the CLI plus a headless server. Re-running uv tool install upgrades in place.

swarmkit init is a conversational authoring swarm — you describe what you want and it produces the workspace, topology, archetypes, and skills as artifacts you own and can edit. You can equally hand-write the files; the rest of this guide shows the artifacts directly so you can read any workspace, however it was authored.

A workspace root is one file:

apiVersion: swarmkit/v1
kind: Workspace
metadata:
  id: my-swarm
  name: My Swarm
governance:
  provider: mock          # `mock` for local dev; `agt` (Microsoft AGT) for real policy/audit

Workspace reference · Installation

Step 1 — one agent

A Topology is the unit the runtime runs. The smallest one is a single root agent instantiating an Archetype:

# archetypes/business-analyst.yaml
apiVersion: swarmkit/v1
kind: Archetype
metadata: { id: business-analyst, name: Business Analyst }
role: leader
defaults:
  model: { provider: openrouter, name: openai/gpt-4o-mini, temperature: 0.3 }
  prompt:
    system: >
      You are a business analyst. Read the requirement, identify the business flows
      it touches, and produce a clear, testable summary plus affected applications.
  iam:
    base_scope: [kb:read, kb:write]
provenance: { authored_by: human, version: 1.0.0 }
# topologies/intake.yaml
apiVersion: swarmkit/v1
kind: Topology
metadata: { name: intake, version: 0.1.0 }
agents:
  root:
    id: intake
    role: root
    archetype: business-analyst
    iam:
      base_scope: [kb:read, app:oms:read]     # this run's authority — least privilege
swarmkit validate .                    # resolve + type-check the whole workspace
swarmkit run intake                    # one-shot execution

The archetype carries the reusable defaults; the topology node carries the run-specific wiring (id, IAM scopes). IAM scopes are structural — an agent can only touch what its base_scope grants.

Topology reference · Archetypes · Tutorial 1: Hello World

Step 2 — give it a skill

A Skill is how an agent gains a capability. Skills come in four categories — capability (do a thing), decision (judge/score), coordination (route work), persistence (remember). A decision skill produces a structured verdict:

# skills/impact-analysis.yaml
apiVersion: swarmkit/v1
kind: Skill
metadata: { id: impact-analysis, name: Impact Analysis }
category: decision
outputs:                                 # structured output — validated before anyone reads it
  type: object
  properties:
    affected_apps: { type: array, items: { type: string } }
    reasoning: { type: string }
  required: [affected_apps, reasoning]
implementation:
  type: llm_prompt
  prompt: >
    Given the requirement and the apps' architecture summaries, decide which apps are
    affected and why. Return affected_apps (ids), rationale, and any open_questions.
provenance: { authored_by: human, version: 1.0.0 }

Attach it in the archetype: skills: [impact-analysis]. The outputs schema is enforced by the runtime — the model's answer is validated and field-corrected before it flows anywhere, so shape-level hallucination never propagates.

Skills reference · Structured output governance · Tutorial 3: Skills

Step 3 — many agents

Add nodes and delegation. SwarmKit's compiler runs independent work in parallel and dependent work in order via depends_on, and coordinators use structured delegation — a planner builds a dependency-ordered task plan (create-task-plan) instead of ad-hoc prose hand-offs. This is the difference between a swarm that reliably fans out and one that loses track of its own work.

agents:
  root:
    id: architect
    role: root
    archetype: solution-architect
    children: [oms-dev, web-dev]        # delegates to focused workers
  oms-dev:  { id: oms-dev,  role: worker, archetype: developer }
  web-dev:  { id: web-dev,  role: worker, archetype: developer }

DAG dependency graph · Tutorial 4: Multi-Agent · Tutorial 6: Structured Delegation

Step 4 — real tools via MCP

Agents get tools by connecting to MCP servers (stdio or Streamable HTTP), configured in the workspace — never coded per-vendor. Every tool call routes through governance, so an agent can only invoke tools its scopes allow. SwarmKit ships its own servers too (swarmkit knowledge-server, swarmkit docs-reader).

MCP client · MCP discovery pattern · Tutorial 5: MCP Tools

Step 5 — governance and decision skills

Governance is not a prompt suggestion — it is structural. All policy/identity/audit flow through the GovernanceProvider interface; the audit log is append-only from the executive's perspective; and a set of scopes reserved for human identity (skills:activate, mcp_servers:deploy, topologies:modify, iam:modify, approvals:resolve) can never be granted to an agent, regardless of prompt. Decision skills run mandatory evaluations at workspace/topology boundaries with a bounded retry loop.

Governance provider · Structured output governance · Tutorial 7: Governance & Safety

Step 6 — a quality gate with a Funnel

A Funnel chains four optional layers into one reusable gate, referenced by id from an agent node. Present layers always run in the fixed order validate → judge → review → approve; the automated layers filter and drive a bounded retry loop but never decide — the only exit is human approve. On retry exhaustion it escalates to a human with the last critique attached; it never silently advances.

apiVersion: swarmkit/v1
kind: Funnel
metadata: { id: consolidated-design-approval, name: Consolidated Design Approval }
validate:
  schema: schemas/consolidated-design.json    # deterministic; the judge never sees malformed input
  autocorrect: true
judge:
  skill: artifact-judge                        # a decision skill scoring against a rubric
  rubric: rubrics/consolidated-design.md
  threshold: 0.8                               # below this → a retry, not a rejection
  max_retries: 2                               # then escalate to a human, never drop
review:
  archetype: architect-reviewer                # optional heavyweight harness reviewer (Step 7)
  read_scope: [app:oms, app:web, app:mobile]
  route_back_at: high                          # findings >= this cause a retry; lower ones attach
approve:                                        # required — the only exit
  rules:
    - scope: design:approve
      roles: [oms-lead, web-lead, mobile-lead]
      quorum: all
  exclude_author: true
  min_distinct_approvers: 2
provenance: { authored_by: human, version: 1.0.0 }

Drop layers to taste: a Funnel with only approve is a plain multi-party sign-off.

Funnel reference · Gate funnel design

Step 7 — a coding harness as a node

Sometimes a node should be a real coding agent (Claude Code, opencode, Codex, Gemini CLI) that opens a repo and produces a diff — not a single model call. That is the executor seam. An archetype selects a harness with an executor block; everything else (governance, observability, the funnel it feeds) is unchanged:

apiVersion: swarmkit/v1
kind: Archetype
metadata: { id: architect-reviewer, name: Architect Reviewer (harness) }
role: worker
executor:
  kind: harness
  ref: claude-code            # swap for opencode / codex / gemini-cli
defaults:
  prompt: { system: "Investigate  verify the design matches the code. Read only." }
  iam: { base_scope: [app:read, kb:read] }
provenance: { authored_by: human, version: 1.0.0 }

Harnesses are data: a declarative ExecutorAdapter (adapter.yaml) interpreted by one engine — no per-harness Python. A harness runs in an ephemeral git worktree by default (produces a diff, never integrates); out-of-grant permissions relay to a human inbox mid-run (swarmkit review) and resume; an opt-in container sandbox adds real isolation. Authoring a new harness is writing one adapter.yaml:

apiVersion: swarmkit/v1
kind: ExecutorAdapter
metadata: { id: echo-harness, name: Echo Harness }
spec:
  launch: { command: [echo-harness, "{task.statement}"] }
  stream: { format: jsonl }
  event_map:
    - when: { type: done }
      emit:
        - event: result
          with: { status: success, output: "$.text" }
provenance: { authored_by: human, version: 0.1.0 }

Executor adapter reference · Executor abstraction · Authoring a harness adapter

Step 8 — sequence the runs from your application

A single topology run is bounded — minutes, one team, one concern. Real delivery work spans weeks, many teams, external events (Jira, CI, SAST), and human gates.

That sequencing is yours, not SwarmKit's. SwarmKit shipped a StageGraph + saga controller until runtime 1.189.0 and then removed them: what an event means, when to retry, which calendar applies and when to give up are application decisions, and hosting them here was turning a swarm framework into a workflow engine. See Extracting the pipeline.

What you get instead is a small, honest HTTP contract:

# your orchestrator — a script, a Temporal workflow, an Airflow DAG, whatever you already run
job = http.post("/run/consolidated-design", {
    "input": brief,
    "correlation_id": "WMS-35",          # "same ticket" — groups every run of the flow
    "labels": {"app": "oms"},            # opaque to SwarmKit; reaches jobs AND audit_events
})["job_id"]

# a gated run parks instead of holding a process open
while http.get(f"/jobs/{job}")["status"] == "deferred":
    gate = http.get(f"/gates/{job}:designer")          # policy already applied — quorum, four-eyes
    if gate["status"] == "approved":
        http.post(f"/jobs/{job}/resume")               # a resumed run can park again, identically
    else:
        sleep(POLL_SECONDS)                            # a gate waits on a person

Three fields carry the thread: correlation_id ("same ticket"), labels (your model, opaque to SwarmKit), and parent_job_id ("this run replaces that attempt" — what makes cost across retries answerable). GET /artifacts/{ref} fetches what a gate is about.

The locks your sequencer holds reference Contract artifacts — making a lock id a checked, pickable vocabulary instead of a free-form string a typo could silently fork:

apiVersion: swarmkit/v1
kind: Contract
metadata: { id: oms-web, name: OMS ↔ Web order API }
parties: [oms, web]                         # >= 2 app ids — an interface *between* apps
provenance: { authored_by: human, version: 1.0.0 }

Read examples/pipeline-orchestrator/: a reference application that drives a multi-stage flow with no swarmkit_runtime import anywhere in it. That is the proof the boundary is real rather than claimed.

Driving SwarmKit from your application · Contract reference · Reading a gate, approving without a saga · Tutorial 16: Sequencing & Contracts

Step 9 — multi-party human approval

A gate resolves to real people through a RoleRegistry. A gate's approve rules name roles; the registry maps roles to member identities and the scopes they confer; scopes reserved for human identity can never be held by an agent.

apiVersion: swarmkit/v1
kind: RoleRegistry
metadata: { id: sdlc-roles, name: SDLC role registry }
roles:
  - { id: oms-lead,    members: [alice], scopes: [design:approve] }
  - { id: infosec-lead, members: [dana], scopes: [security:approve] }
  - { id: eng-manager, members: [grace], scopes: [release:approve] }   # human-only prod authority
  - { id: cio,         members: [heidi], scopes: [release:approve] }

The ApprovalPolicy (the approve: block — embedded config, not a standalone artifact) has two independent axes: which roles signed (quorum: all | any | { k-of: N }) and how many distinct humans signed (min_distinct_approvers, the four-eyes floor). A dual-hatted person can satisfy two roles but never two distinct-approver slots.

Role registry reference · Approval policy reference · Multi-party approval

Step 10 — triggering

Delivery work advances on the outside world. A Trigger is an external event source that starts a topology or delivers a signed event your application acts on. A signed CI webhook:

apiVersion: swarmkit/v1
kind: Trigger
metadata: { id: ci-build-ready, name: CI build-ready webhook }
type: webhook
targets:
  - pipeline: oms-delivery                 # the event STREAM your application listens on
    emit: build.ready-in-qa                # the event name — SwarmKit routes it, you interpret it
    correlation_id: $.correlation_id       # opaque handle extracted from the JSON body
config:
  auth: { method: hmac, credentials_ref: CI_WEBHOOK_SECRET }

The swarmkit serve HTTP front door receives it: the receiver validates the HMAC, extracts the opaque correlation_id, and hands the event to your listener (POST /events/signal). What the event means is your application's call — that judgement left with the sequencer. A trigger whose credentials_ref names an absent environment variable refuses to start, because accepting unsigned requests is a fail-open indistinguishable from working.

Trigger reference · Serve mode · Tutorial 12: Triggers & Canary

Step 11 — serve, observe, evolve

Ship it behind the server, watch it, and let it tell you how to grow:

  • Serve. swarmkit serve exposes topologies as async jobs with SSE streaming, an MCP endpoint, pluggable auth (API key / JWT-JWKS), webhook triggers, and canary version routing with auto-promotion. Install with the extras to get the server and the hosted web UI: uv tool install "swarmkit-runtime[ui]" — then swarmkit serve hosts the portal (dashboard, chat, topology canvas) at its own origin; without [ui] it runs headless (API only). → Serve mode · Tutorial 11: Serve & HTTP API
  • Observe. Every run is a trace of agent-step spans with token counts. swarmkit trace <run>, swarmkit status, swarmkit logs, swarmkit why <run> (LLM post-mortem), swarmkit ask. OpenTelemetry export is built in. → Telemetry · Human interaction model
  • Remember. Workspace memory lets agents carry insight across conversations (local JSON or a GBrain backend). → Workspace memory · Tutorial 9: Conversations & Memory
  • Grow. The runtime records capability gaps (swarmkit gaps); you author the missing skill through conversation (swarmkit edit), test it, and publish — human-approved at every step. → Skill authoring · Tutorial 13: Authoring & Review

The worked example — the SDLC workspace

Everything above is assembled, end to end, in examples/sdlc-pipeline: a complete software-delivery lifecycle — intake → design → build → sit → pt → security-review → deploy → support-handover — carrying three multi-party human gates, integration contracts, a harness build/review node and IAM-scoped agents. Its sequencing half left with the bundled pipeline in 1.189.0; the artifacts, the gates and the per-stage demos remain. It is the reference for how the pieces fit.

  • Watch it. The captioned video walkthrough tours every artifact and runs a stage end to end.
  • Run it. just demo-sdlc-stage-run runs a single gated stage end to end; just demo-consolidated-design, just demo-harness-build and just demo-sit-pt each exercise one capability deterministically (no keys, no server).
  • Read it. The SDLC example design note is the build-order narrative (slices 1–9) and the automation map (which stages are agent-run vs. human-gated).

Validate everything

The whole point of topology-as-data is that a swarm is checkable before it runs:

swarmkit validate .                    # resolve + type-check the workspace, print the tree or errors
python examples/sdlc-pipeline/validate_library.py   # validate every artifact in a library

The resolver rejects a lock that names no contract, an approval rule whose scope no role confers, a stage that kicks an unknown topology, and any artifact that fails its schema. Validation is the fast feedback loop; a live swarmkit run is the confidence loop — do both.

swarmkit validate reference

Reference index