workflows/.
Three core guarantees
Completeness
A workflow either completes every step, or compensates every side
effect it produced before failing. There is no middle state invisible
to operators.
Observability
Every step transition, decision, tool call, cost increment, and
approval event is a typed event, persisted to the audit log. Any run
can be replayed as a complete narrative.
Isolation
A tenant’s workflow accesses only that tenant’s agents, memory, data,
and API quotas — even executing on the same shared worker pool as
other tenants’ runs.
Step types
DAG execution
Steps form a directed acyclic graph — cycle detection runs at definition load time, not at execution time. Independent steps at the same topological depth execute in parallel (the “frontier”); a step becomes eligible the moment all its dependencies complete, not on a fixed schedule. (Simplified fromfull-content-pipeline.yaml’s real 17 steps.)
State machine
Runs and steps each have their own state machine, persisted to PostgreSQL with CAS-guarded transitions — a step can only movePENDING → RUNNING
via a compare-and-swap that fails cleanly if another worker already
claimed it (claim_step), which is the actual idempotency mechanism, not
just a Redis lock.
Checkpointing and resume
Every step completion writes a checkpoint. A worker crash mid-run doesn’t lose progress — on resume, completed steps are never re-run; only the step that was in-flight (or never started) executes. Idempotency for resume depends on the same ADR-006 layers agents already use, so a resumed step that partially executed before the crash doesn’t double-apply its side effects. A heartbeat + stale-run reaper detects workers that died without a clean shutdown (no crash signal, just silence) and reclaims their in-flight steps after an idle threshold — this is the same mechanism that recovers Redis Streams’ pending-entries list after a rolling deploy (see Events).Compensation (saga pattern)
On unrecoverable failure, the engine runs compensation steps in reverse order of the side effects that succeeded — a saga, not a distributed transaction. Compensation steps are isolated: a failure compensating one side effect doesn’t prevent compensating the others.Retry, timeouts, and dead-letter
Each step has its own retry policy (exponential backoff) and timeout hierarchy (step timeout, workflow-level timeout, idle/stall detection). A step that exhausts retries routes to a dead-letter path rather than silently failing the whole run — the article gets areview_required
status, not a vanished workflow.
Human approval gates
Approval steps are non-blocking — the workflow suspends (not a worker thread spinning idle) and resumes on an external event (Slack interactive action or a dashboard click). Approval requests carry an escalation timeout and can be delegated. For content specifically, approval is mandatory on every publish in the standard pipeline — thecontent-evaluation gate (see AI Agents)
picks the queue an article lands in, but never approves or publishes
itself.