sagas — State Machine Workflows

How this compiles. Each step with on: is macro-expanded at compile time into an ordinary event-triggered core rule (op: merge into state_path, plus current_step). There is no separate Temporal-style saga engine. Optional from: becomes a when.expr guard on entity.<state_path>.current_step. See Defining Sagas for the full guide.

Sagas are entity-attached state machines that track multi-step workflows. State is stored under a _tmp/ path on the entity.

sagas:
  order_lifecycle:
    state: order
    state_path: _tmp/order_saga
    steps:
      - name: idle
        set: { status: idle }
 
      - name: placed
        on: ORDER_PLACED
        from: [idle]
        set: { status: placed }
 
      - name: confirmed
        on: ORDER_CONFIRMED
        from: [placed]
        set: { status: confirmed }
        end: true
 
      - name: cancelled
        on: ORDER_CANCELLED
        from: [idle, placed]
        set: { status: cancelled }
        end: true

Saga fields

FieldRequiredDescription
stateyesEntity type that owns this saga
state_pathyes_tmp/ path to store saga state
stepsyesList of step definitions
steps[].nameyesStep id; stamped as current_step on enter
steps[].onnoEvent that triggers this step (omit for idle / default)
steps[].fromnoPrior current_step values required before this transition
steps[].whennoExtra expression guard (AND-ed with from)
steps[].setnoFields merged into the saga object (alongside current_step)
steps[].endnoTerminal marker (authoring / docs intent; not a hard runtime lock)

Composition with from:

  • Without from: — choreography style: any matching on: event merges the step’s set values.
  • With from: — the expander requires entity.<state_path>.current_step to be one of the listed prior step names before the transition fires.

Every transition always writes current_step: <step.name> into the saga object so guards have a stable field.

Runtime compensation (separate)

DSL sagas: do not run Temporal-style compensations. For multi-entity 2PC abort paths, actions may declare reliability.compensating_intent — see Defining Sagas → Runtime reliability. That is a different subsystem from the sagas: macro.