A short, shared vocabulary. The guides build on these terms.
Glossary
| Term | What it is |
|---|---|
| Workflow | The template — one workflow({ … }) definition with triggers and steps. |
| Run | One execution of a workflow (also called an instance). Identified by an execution id. |
| Step | One node in a workflow. A step, form, signal, webhook, connector, or agent. |
| Handler | The JavaScript function a step runs; returns the variable updates to merge. |
ctx.vars | The run’s mutable variable bag — seeded from initial + start input, carried across steps. |
| Trigger | How a run starts: apiTrigger, formTrigger, webhookTrigger, or scheduleTrigger. |
| Park / resume | A run parks when it needs external input, resumes when the event arrives. |
| Signal / form / webhook | The three ways an external event resumes a parked run. |
| Connector | A durable call out to a service (HTTP, LLM, MCP). |
| Agent | A call into the driving Claude Code session to run a prompt and return a typed result. |
| Query | A read-only view over a run’s variables; never advances the run. |
| Event / narrative | The append-only audit log, and the human-readable progress text on top of it. |
| Workspace | The tenancy unit that owns definitions, runs, and connector credentials. |
The run lifecycle
┌──────────── start ────────────┐
▼ │
RUNNING ──claim──▶ IN_FLIGHT ──step ok, more work──▶ RUNNING
▲ │
│ ├─ needs input ─▶ WAITING_FORM / WAITING_SIGNAL /
event resumes │ WAITING_WEBHOOK / WAITING_CONNECTOR_JOB /
│ │ WAITING_AGENT (parked — zero CPU)
└──────────────────┘
├─ step throws + retryPolicy ─▶ RETRYING ─▶ RUNNING
├─ step throws + onError ──────▶ RUNNING (at the handler step)
└─ no work left ───────────────▶ COMPLETED (terminal)
FAILED (terminal)
CANCELLED (terminal)
You’ll mostly see these in flowctl run status: RUNNING (executing or ready),
WAITING_… (parked on input), COMPLETED / FAILED / CANCELLED (done).
Durability guarantees
flowwork advances a run’s state exactly once — each step’s commit is transactional and guarded, and a crashed worker’s run is automatically reclaimed and continued. But a step’s side effects (an HTTP POST, an email, an LLM call) can run more than once if a worker dies after the side effect but before the commit.
Because side effects are at-least-once, design connector calls and external actions so that running them twice is safe — use idempotency keys, upserts, or “create if absent” semantics. This is the single most important rule for correct workflows.
A few consequences worth internalizing:
- Parked runs cost nothing. A
WAITING_*run holds no thread and no timer; it’s just a row. - Handlers should be deterministic-ish. Put external I/O in
connector()steps, not in plain step handlers, so the engine can retry and journal them properly. - Variables are the memory. Everything a later step needs must live in
ctx.vars(it’s persisted); don’t rely on closures or module globals across steps.
Next: Workflow structure & steps.