Workflows
A workflow orchestrates a process as a graph of steps. Authors model it in
RuleFlow’s own step vocabulary; RuleFlow compiles it to an AWS Step
Functions state machine at deploy time. Step Functions (Standard, not
Express) is an implementation detail — you never author or read ASL
directly, though POST /engine/compile-workflow will show it to you if you
want to look.
Shape
Workflow
├── start
├── steps
│ ├── service_task
│ ├── human_task
│ ├── decision_task
│ ├── wait
│ ├── gateway
│ └── end
├── events
├── timers
└── error_handlers
Step types
decision_task— calls a named decision from the same project/release. Executes as an in-process call into a Rust Lambda that links the decision engine directly (no network hop, deterministic, scales to zero) — the same engine entry point/v1/simulateuses, so browser/server/runtime stay in parity. The whole workflow state is passed as input; the engine simply ignores fields outside the decision’s declared inputs, which is what lets a downstream decision read an upstream one’s result.service_task— calls out to an external system through a connector, resolved by a logicalactionname bound per-tenant to a connector type + config. Executes via a queued task-token callback: the compiled step sends a message to a work queue and waits; a connector worker performs the call and reports success/failure back.human_task— pauses the execution on a task-token callback until a person completes it via the API. Given no timeout by default (human steps are long-lived) — a token lives up to the Step Functions maximum (one year) before it expires.gateway— branches on a prior step’s output (variable/op/valueagainst a$.decisions.…/$.tasks.…path), with adefaultbranch.wait— a timer delay.end— a terminal state; a workflow can declare several.
retry/catch on a step follow Step Functions’ Retry/Catch shape
directly (errors, max_attempts/interval_seconds/backoff_rate for
retry; errors/next for catch) — authored, passed through by the
compiler verbatim.
Reserved state namespaces
The runtime has exactly one shared mutable object per execution: the state
that flows step to step. Let input be what was passed to
POST .../executions. The invariant:
state = input ⊎ { "decisions": { <stepId>: <outputs> } } ⊎ { "tasks": { <stepId>: <result> } }
$.decisions.<stepId>— the outputs object of eachdecision_task.$.tasks.<stepId>— the result of eachservice_task/human_task.- Everything else under
$is the caller’s original input, never mutated.
decisions and tasks are therefore reserved top-level keys — don’t
declare a schema field with either name; a decision/workflow whose input
shape uses one would get silently overwritten by the next step’s result.
Results accumulate, they never replace: after a decision_task named
score runs, state gains a decisions.score key alongside everything that
was already there. A gateway or a later decision_task reads any prior
step’s result from that namespace.
Compiling and running
Authoring and compiling are pure and read-only — POST /engine/compile-workflow never touches anything running. A workflow only
becomes a runnable machine at deploy time, when the control plane
resolves placeholders (engine ARN, inlined decision models, connector
queues, default timeouts) against the concrete release being deployed. See
Releases, environments & rollback for the deploy lifecycle
and Executions for starting and observing runs.
Failure model
Three error classes, deliberately handled differently:
- Deterministic decision errors (bad input shape, an expression that
can’t evaluate) are reproducible — the same
(model, input)fails identically every time. These fail fast; retrying is wasted effort. An author-declaredcatchon the step is the way to handle them. - Transient AWS faults (throttling, a cold-start hiccup) are not
reproducible and should be retried with backoff — declare a
retryon the step for this class. - Deploy-time errors (an unresolved decision name, malformed compiled ASL) fail the deploy, never a run — the earliest point they can be caught, and the reason decision models are inlined rather than fetched at runtime.