Chio/Docs
LOGIN · JOIN

Swarm Protocol

Look up the bundle a delegated hop presents, the order a verifier checks it in, and the graph rules that reject it whole.

Reference chio@5f63e6e

On this page

When one agent delegates to another, the hop carries a bundle of signed records: the task graph, the hop’s continuation token and witness chain, and the route, budget, revocation, and terminal records they name. A verifier accepts the bundle whole or refuses it whole.

The verifier checks those relationships against caller-pinned issuer keys, so anyone holding the bundle can inspect who authorized each hop, how authority narrowed, where a task may run, and how its budget is accounted for. Swarm Authority describes the operating model around it.

Synopsis

A hop presents one bundle, and verify_swarm_authority_bundle accepts it whole or rejects it.

crates/kernel/chio-swarm-authority/src/types.rs29-40rust
pub struct SwarmAuthorityBundle {
    pub task_graph: SwarmTaskGraph,
    pub continuation_tokens: Vec<SwarmContinuationToken>,
    pub witness_chains: Vec<SwarmDelegationWitnessChain>,
    pub join_receipts: Vec<SwarmJoinReceipt>,
    pub route_plan_receipts: Vec<SwarmRoutePlanReceipt>,
    pub budget_pool: SwarmBudgetPool,
    pub revocation_epoch: SwarmRevocationEpoch,
    #[serde(default)]
    pub terminal_receipts: Vec<SwarmTerminalGraphReceipt>,
    pub now_unix_ms: u64,
}

The bundle is chio-swarm/v1. Validate each artifact against the schema identifier it carries; a change to the shape or meaning of any required field mints a new version identifier.

Bundle artifacts

Signed task graphChoose a view.
depth 0depth 13 of maxFanout 3maxDepth 2joinbudget-pool-swarm-valid · 10,000 usd_minornext task: task-rootκtask-rootrevocation-epoch-swarm-valida1task-child-aa2task-child-b2,500a3task-child-c2,500ρjoin-child-resultscontinuation-child-aroute-child-abudget-child-awitness-child-amaxDepth 2 · maxFanout 3pool 10,000κtask-rootrevocation-epoch-swarm-valida12,500a22,500a32,500ρjoin-child-resultsnext task: task-roottask-child-a carriescontinuation-child-aroute-child-abudget-child-awitness-child-a

a1task-child-aa2task-child-ba3task-child-c

The graph indexes the rest of the bundle

task-child-a names continuation-child-a, route-child-a, and budget-child-a, and witness-child-a covers its edge. The graph names budget-pool-swarm-valid and revocation-epoch-swarm-valid. The verifier accepts the bundle whole or refuses it, with no partial report. Swarm Protocol.

The signed task graph and budget pool from the valid-recursive-delegation fixture, with widths drawn to the pool’s units; the overdrawn pool is the budget-allocations-exceed-pool fixture and the two-hop chain is the verifier’s source test. Route plans, continuations, and the revocation epoch appear by name only.Task Graphs

The drawing is the signed valid-recursive-delegation fixture. task-root delegates to task-child-a, task-child-b, and task-child-c under a signed maxDepth of 2 and maxFanout of 3, and the results meet at join-child-results, whose next task is task-root. task-child-a names continuation-child-a, route-child-a, and budget-child-a, and witness-child-a covers its edge. The graph names budget-pool-swarm-valid and revocation-epoch-swarm-valid.

The pool holds 10,000 usd_minor units, with 2,500 allocated to each child. The terminal graph receipt lists all four tasks, the one join, and the three route plans, and its rollup of 7,500 active units equals the allocations summed by dimension.

The registry tracks 9 schema files under chio-swarm/v1. Every artifact has a closed field shape. Signatures authenticate the graph and the signed delegation, route, revocation, and terminal records. The budget pool is unsigned and is checked through its graph and allocation bindings, and the verifier report is derived output. Each entry links to the page that specifies its fields.

Chio Swarm Task Graph

chio.swarm.task-graph.v1

The signed DAG the whole bundle belongs to, carrying the structural ceilings a verifier enforces across every task and every hop.

Fields and behavior: Task graphs.

Chio Swarm Continuation Token

chio.swarm.continuation-token.v1

That one hop was authorized, binding the child task to its graph digest, its single parent context, its route, its allocation, and the revocation epoch it was checked against.

Fields and behavior: Continuations.

Chio Swarm Delegation Witness Chain

chio.swarm.delegation-witness-chain.v1

That authority only ever narrowed from parent to child across the hop, with a checked scope subset proof and a pinned signature at every step.

Fields and behavior: Witness chains.

Chio Swarm Join Receipt

chio.swarm.join-receipt.v1

That a fan-in fired against exactly the parent set the graph declared for it, under the predicate that fan-in carries.

Fields and behavior: Terminal receipts.

Chio Swarm Route Plan Receipt

chio.swarm.route-plan-receipt.v1

That egress for one task was pinned to a chosen route, bridge, and target before dispatch, under the single egress constraint the protocol defines.

Fields and behavior: Route plans.

Chio Swarm Budget Pool

chio.swarm.budget-pool.v1

An unsigned pool checked through the signed graph and its continuation allocations. It records each task’s spending ceiling and accounting rollup; allocations must balance within the pool total. A market purchase names the pool by its projection digest rather than by the pool JSON.

Fields and behavior: Budgets.

Chio Swarm Revocation Epoch

chio.swarm.revocation-epoch.v1

The signed revocation epoch the bundle was checked against. Its content digest and pinned-key signature make changes detectable.

Fields and behavior: Revocation epochs.

Chio Swarm Terminal Graph Receipt

chio.swarm.terminal-graph-receipt.v1

That the graph closed over exactly the task set, the fan-in set, and the route set it declared, with a final spend rollup that reconciles against the pool.

Fields and behavior: Terminal receipts.

Chio Swarm Authority Verifier Report

chio.swarm.authority-verifier-report.v1

The verifier’s derived output: an accepted verdict, one entry per continuation-bearing task, and the claim ids for the checks that ran. The report does not carry its own signature.

Fields and behavior: Swarm authority.

An accepted report carries claim ids drawn from a closed set of 8: claim.swarm.task_graph_bound, claim.swarm.continuation_fresh, claim.swarm.attenuation_witness_chain_bound, claim.swarm.route_plan_bound, claim.swarm.join_receipt_bound, claim.swarm.budget_pool_bound, claim.swarm.revocation_epoch_bound, and claim.swarm.terminal_graph_receipt_bound. Every acceptance carries all of them except claim.swarm.join_receipt_bound, which appears only when the graph has a fan-in and the bundle carries its fan-in receipt.

Verification order

A verifier runs these steps in this order. Any failing step rejects the bundle immediately and produces no partial report.

  1. Reject if the trusted witness issuer key set is empty, before any artifact is read.
  2. Validate task-graph shape, then its signature.
  3. Require at least one continuation token and one witness chain.
  4. Validate and index route plan receipts, then join receipts, then the budget pool, then the revocation epoch, in that order.
  5. Validate terminal graph receipts against the task, route, fan-in, and budget indexes.
  6. Validate continuation tokens against the task graph canonical sha256, witness chains, routes, budget allocations, and the revocation epoch.
  7. Validate that witness chains cover every task-graph hop exactly once, with continuous scope hashes and capability digests hop to hop.
  8. Assemble the verifier report: one hop report per continuation-bearing task, plus the claim ids for the checks that ran.

Step 4 binds its artifacts in two ways. Route plan receipts, join receipts, and the revocation epoch each carry an issuer and a signature, and a verifier checks the signature against a pinned key. The budget pool carries neither. It binds to the bundle through the signed graph, which names the graph the pool must belong to and the pool identifier itself, and through the allocations the continuation tokens draw on, so its trust comes from those bindings alone.

Invariants

A bundle that conforms to its schemas still has to pass the structural rules below. Each is checked in code, and a bundle that breaks any one of them is rejected whole.

  1. Single root. A task graph MUST contain exactly one task at root depth, that task MUST have no parent, and every task below root depth MUST name one. Checked by validate_roots.
  2. Acyclic. The graph MUST be acyclic. A verifier walks it depth first and rejects on re-entry to a task already on the current path. Checked by validate_acyclic and visit_task.
  3. Exact depth arithmetic. Every hop target MUST sit at exactly the source depth plus one. Depth overflow MUST reject instead of wrapping. Checked by validate_edge_depths, and stated in spec/PROTOCOL.md section 6.4.2.
  4. Signed ceilings, enforced graph-wide. The depth ceiling and the fan-out ceiling MUST sit inside the signed body, so widening either one requires a fresh signature from a pinned key. A verifier MUST enforce both across the whole graph: any task deeper than the depth ceiling rejects the bundle, and so does any task with more outgoing hops than the fan-out ceiling. The fan-out ceiling MUST be positive. Checked by validate_graph_limits.
  5. Exactly one parent context per hop. Each continuation token MUST name either a direct parent task or a fan-in receipt. Naming both rejects. Naming neither rejects. Checked by validate_continuation_parent.
  6. Witness coverage exactly once per hop. Every hop in the graph MUST be covered by exactly one witness chain. A missing chain rejects and a duplicate chain rejects. Every chain MUST terminate on a hop the graph declares. Checked by validate_witness_chains.
  7. Budget balance and budget ceiling. Each allocation’s own five-way unit rollup MUST equal its ceiling exactly, and arithmetic overflow MUST reject instead of clamping. The allocation ceilings summed MUST NOT exceed the pool total. A terminal receipt’s per-dimension rollup MUST equal the sum over allocations exactly, and its total MUST NOT exceed the pool total. Checked by validate_budget_allocation_units, validate_budget_pool, and validate_terminal_budget_rollups. A cognition-market pool_sha256 MUST hash the RFC 8785 canonical bytes of the chio.swarm.budget-pool-digest-projection.v1 preimage, never the wire serialization of the pool. That preimage carries the projection identifier, the source pool schema, the pool id, graph id, and currency, and the allocations in their original order; the pool total and every allocation unit field MUST be the shortest unsigned base-10 string, with 0 as the only representation carrying a leading zero. Built by swarm_budget_pool_digest_projection_bytes and hashed by swarm_budget_pool_sha256.
  8. Closed egress constraint set. A route plan receipt MUST carry a non-empty, duplicate-free constraint list, and every entry MUST be deny-private-network. That is the whole set: any other string rejects the bundle as an unsupported constraint, and the schema enum lists the same one value. Checked by validate_route_plan_egress_constraints. Route plans carries the rest of the receipt.

Example runs

The agent-os example mints a three-task incident graph and its supporting records, signs each signed artifact family, verifies the bundle, and then refuses four tampered copies of it. Every key and artifact is minted in process, so the run touches no store and no trust anchor on disk.

Terminalbash
chio new agent-os --example agent-os && cd agent-os
agent-os · runtranscript
$ cargo run --locked --example agent_os
chio swarm authority  ·  one task graph, verified before any child runs

task graph  swarm-incident-42
  orchestrator      depth 0  scope 6ab7b09faf2a  route -                budget holds the pool
  researcher        depth 1  scope c5a04ca641ec  route route-researcher budget 2500 of 10000 units
  writer            depth 1  scope c5a04ca641ec  route route-writer     budget 2500 of 10000 units
  join researcher + writer -> orchestrator  (all_success)

verdict  verified  (3 tasks, 2 continuations, 1 joins, 2 routes)
  researcher   continuation continuation-researcher    witness witness-researcher (1 hop)
  writer       continuation continuation-writer        witness witness-writer (1 hop)
claims   claim.swarm.task_graph_bound, claim.swarm.continuation_fresh, claim.swarm.attenuation_witness_chain_bound, claim.swarm.route_plan_bound, claim.swarm.join_receipt_bound, claim.swarm.budget_pool_bound, claim.swarm.revocation_epoch_bound, claim.swarm.terminal_graph_receipt_bound

then someone tries to
  add an edge from the writer back to the orchestrator rejected: swarm task graph cycle at task-orchestrator
  hide a hop by understating the writer's depth        rejected: swarm task depth mismatch: task-researcher -> task-writer
  allocate 5,000 units out of a 100 unit pool          rejected: swarm budget allocations exceed pool total
  run the researcher after its task was revoked        rejected: swarm task is revoked: task-researcher
exit 0in Chio source checkout

The same refusals replay through the CLI on bundles you generate. chio proof fixture generate writes the valid bundle, every negative bundle of its family, and a trust file that pins only the fixture keys those bundles need:

Terminalbash
chio proof fixture generate recursive-runtime-swarm --with-negatives --out ./swarm
Output
generated  recursive-runtime-swarm  ./swarm
trust      ./swarm/trust.toml  (fixture profile, 4 roles)
negatives  11 under ./swarm/negatives

The proof doctor loads the valid bundle and the negative bundles beside it, and reports whether each was rejected for the reason its fixture pins, which checks more than rejection alone.

Terminalbash
chio proof doctor --scenario swarm-authority --in ./swarm --trust ./swarm/trust.toml
Output
chio proof doctor swarm-authority
  [passed] swarm_recursive_delegation: transaction passport verified
  [passed] swarm_stale_continuation: transaction passport rejected
  [passed] swarm_budget_allocations_exceed_pool: transaction passport rejected
  [passed] swarm_graph_cycle: transaction passport rejected
  [passed] swarm_join_parent_set_mismatch: transaction passport rejected
  [passed] swarm_replayed_continuation_nonce: transaction passport rejected
  [passed] swarm_revoked_task: transaction passport rejected
  [passed] swarm_stale_route_plan: transaction passport rejected
  [passed] swarm_route_plan_mismatch: transaction passport rejected
  [passed] swarm_witness_child_scope_mismatch: transaction passport rejected
trust    ./swarm/trust.toml (fixture keys)
verdict: passed

The refusals in that output are the verifier’s own sentences. Swarm denial codes indexes every one of them back to the check that produced it, and chio proof verify ./swarm/negatives/ --trust ./swarm/trust.toml --expect refuse replays the 11 signed negative bundles in one command.

Evidence and boundaries

One function decides admission. The runtime admission hook, the proof room, and the CLI proof path all call verify_swarm_authority_bundle, so the workspace holds one definition of acceptance. Acceptance is whole or absent: any failing check returns immediately, and the authority-verifier-report schema pins a single verdict value, so a partial report has no representation.

An empty trusted key set rejects the bundle before any artifact is read (require_trusted_witness_issuer_keys), and a bundle carrying no continuation token or no witness chain is refused, so a well formed graph with no delegation in it never verifies (require_signed_swarm_delegation_evidence). Each claim id is backed by signed negative fixtures, written under ./swarm/negatives/ by the generate step above:

Claim idRefused caseNegative fixture
claim.swarm.task_graph_bound
A back hop from a child to the root
graph-cycle/
claim.swarm.continuation_fresh
A stale token, or a reused nonce
stale-continuation/, replayed-continuation-nonce/
claim.swarm.attenuation_witness_chain_bound
A child scope that differs from the signed scope
witness-child-scope-mismatch/
claim.swarm.route_plan_bound
A stale route plan, or an unsupported constraint
stale-route-plan/, egress-constraint-unsupported/
claim.swarm.join_receipt_bound
A fan-in that omits a declared parent
join-parent-set-mismatch/
claim.swarm.budget_pool_bound
Allocations that outrun the pool total
budget-allocations-exceed-pool/
claim.swarm.revocation_epoch_bound
A revoked task in the bundle
revoked-task/

Regression tests cover the same cases, including a revocation epoch that names a subject the bundle’s authority rests on and a terminal rollup that fails to reconcile against its allocations. Widening a ceiling and re-sealing every downstream token against the new graph digest still fails. 12 fixture scenarios ship, 11 of them negative; the randomized conformance test starts from the signed positive fixture, mutates it case by case, and asserts the rejection message each mutation is expected to produce.

  • The spec is the contract. spec/PROTOCOL.md section 6.4.2 states the same admission binding, the same two ceilings, and the same depth arithmetic as the code, and a third-party implementation is held to that text.
  • Schemas publish the shape. The 9 schemas are hash-pinned in spec/schemas/MANIFEST.sha256 and closed to unknown fields. Acceptance is decided by the verifier’s checks.
  • Refusals are sentences. SwarmAuthorityError carries two variants over free-form text. Swarm denial codes maps each sentence to the runtime code that replaces it.
  • Verification is the specified contract. Issuance is a separate contract; the crate’s minting and signing helpers serve fixtures, examples, and tests.
  • Spend is bounded by the pool. The ceilings bound depth per task and outgoing hops per source, and leave the total task count open: a full tree at both ceilings is well formed and grows exponentially in the depth ceiling. The pool is the quantitative bound on spend.
Specification and implementation sources

The protocol is spec/PROTOCOL.md section 6.4.2, version 1.0, and the schemas under spec/schemas/chio-swarm/v1/ in the Chio repository. The keywords MUST, SHOULD, and MAY are normative.

  • Verifier: crates/kernel/chio-swarm-authority/src/verifier.rs with verifier/witness.rs (validate_witness_chains), verifier/util.rs, and verifier/budget_accounting.rs; the egress constraint check at verifier.rs:979, mirrored in spec/schemas/chio-swarm/v1/route-plan-receipt.schema.json:70.
  • Bundle types and the CLAIM_SWARM_* constants: crates/kernel/chio-swarm-authority/src/types.rs.
  • Budget-pool digest projection: crates/kernel/chio-swarm-authority/src/finding_pool.rs.
  • Error type: crates/kernel/chio-swarm-authority/src/error.rs. Issuance scope: crates/kernel/chio-swarm-authority/ARCHITECTURE.md.
  • Callers: crates/kernel/chio-runtime-core/src/admission_hook/swarm_authority.rs and crates/products/chio-proof-room/src/source_verifier.rs.
  • Worked example: crates/kernel/chio-swarm-authority/examples/agent_os.rs.
  • Regression tests: swarm_authority_stage0_rejects_graph_cycle, swarm_authority_stage0_rejects_witness_child_scope_mismatch, swarm_authority_stage0_rejects_join_parent_set_mismatch, swarm_authority_stage0_rejects_budget_allocations_exceeding_pool, swarm_authority_stage0_rejects_terminal_budget_rollup_mismatch, swarm_authority_stage0_rejects_revoked_task, swarm_authority_stage0_rejects_revoked_authority_subject, and swarm_authority_stage0_rejects_task_graph_tampering_after_continuations_are_resealed.
  • Randomized conformance: crates/tooling/chio-conformance/tests/r_t03_recursive_swarm_conformance.rs:132-138 over the valid-recursive-delegation fixture. Claim bindings: crates/core/chio-core-types/tests/claim_registry_integrity.rs.

Next: trace a refusal to its check