Event Sourcing

All state in Argyll lives in event logs that only grow. Each aggregate records changes for one resource, and each projection is current state produced by applying those events in order. Includes the full event-type catalog.

Foundation

Every state change in Argyll is recorded as an event in a log that only grows. A projection is current state rebuilt by applying events in order, never stored separately. This makes results repeatable, preserves state after failures, and provides a complete audit trail.

Aggregates

Events are organized into aggregates: one event stream for one resource, identified by an ID path:

Aggregate IDContents
["catalog"]Registered step definitions
["cluster"]Per-step health across the cluster
["flow", "flow-id"]One flow’s execution history

Event Types

Catalog (["catalog"])

  • step_registered
  • step_unregistered
  • step_updated

Cluster (["cluster"])

  • step_health_changed

Flow Lifecycle (["flow", "flow-id"])

  • flow_started
  • flow_completed
  • flow_failed
  • flow_deactivated

flow_completed and flow_failed establish an outcome that callers can use immediately: no new Steps start, but work that has already started may still produce side effects (changes to external systems) and compensation may still run. flow_deactivated is recorded only after no pending, active, or compensating Work Items remain.

Step Execution (["flow", "flow-id"])

  • step_started
  • step_completed
  • step_failed
  • step_skipped

Work Items (["flow", "flow-id"])

  • work_started
  • work_succeeded
  • work_failed
  • work_not_completed
  • work_retry_scheduled
  • dispatch_deferred — raised when a node cannot dispatch work, retry, or compensation locally; propagates to all nodes so one with a healthy path to the step can pick it up

Compensation (["flow", "flow-id"])

  • comp_started
  • comp_succeeded
  • comp_failed
  • comp_retry_scheduled

Compensation event names use the short comp_* prefix. The Work Item status set by comp_failed is compensation_failed; it is a state value, not an event name.

Attributes (["flow", "flow-id"])

  • attribute_set

Side Effects Follow Committed State

The engine writes the event before it triggers any external action. If a node crashes mid-write, the event either committed (and the work runs after recovery) or it didn’t (and nothing ran). Retries resume from the last committed state, with no double execution from missing acks.

A terminal outcome does not mean side effects have stopped: a caller can need the outcome as soon as flow_completed or flow_failed is recorded while previously started work or compensation is still running.

State Reconstruction

A Flow’s current state is the result of applying all its events in order. You can:

  • Replay any flow’s event log to inspect its history
  • Subscribe to live events via WebSocket to track execution in real time
  • Verify why a flow reached its current state by reading the event sequence

Subscribing

The WebSocket API streams events as they occur. Subscribers can filter by aggregate ID and event type, and request the current state before new events are streamed. See the WebSocket API for the protocol.