Skip to main content
A handler can take different paths. Swarm has two ways to do it, and they are mutually exclusive: pick by what you are branching on.

rules: dispatch on the payload

rules routes on the incoming payload, for example by category. It is an ordered list of named branches; the first whose condition matches wins, and that rule owns the emit:
Each rule can carry its own advances_to, sets_gate, data_accumulation, emit, and action. When rules is present, the matched rule owns both the emit and the action, so a handler-level emit or action alongside rules is a boot error. Handler-level data_accumulation still runs and supplements the matched rule’s writes; a rule’s value for a field overrides the handler-level default for that field. See the execution model for the precedence rules. Rule-level action is the idiomatic shape for conditional side effects: auto-approve a refund when it is under a policy limit, otherwise fire mailbox_write for a human. See Human in the loop for the worked example.

on_complete: decide after computing

on_complete decides after the handler has gathered or computed something, for example once enough scores have accumulated. It is an ordered list, and the first matching condition wins. (accumulate waits for several events — covered on the next page; here, just read it as “the handler has gathered its inputs”.)
on_complete must be a YAML list (ordered), not a map, because order is the tie-breaker.

Choosing between them

  • Use rules when the branch depends on the incoming payload (type dispatch).
  • Use on_complete when the branch depends on what the handler produced (after accumulate or compute).
accumulated.* is readable in on_complete conditions but not in rules conditions, since rules run before accumulation. See Accumulation and computation.