Skip to main content

The handler context

Every handler receives a StepContext: the triggering event, the durable step API, and the run’s metadata.
{ name: string; data: TData }
required
The triggering event; event.data has the type passed to workflow.
Step
required
The durable step API - see below.
Webhook
required
ctx.webhook.send(id, { url, data? }): a durable outbound POST with retries and a per-attempt log.
Logger
required
Structured, replay-safe logging: ctx.log(msg, fields) plus .debug/.info/.warn/.error. See Logging.
string
required
This run id.
number
required
Retry attempt, starting at 1 and increasing on each retry.
string
required
The app this run belongs to.
string
required
The runner this run is pinned to; the empty string when the run is anycast.
Array<{ name: string; data: TData }>
Set only on a batched workflow: the coalesced events. event is events[0].
StepError
Set only inside an onFailure handler: the terminal error that failed the source run.

step

Every step takes a stable id, unique within the workflow. The result is recorded under that id, and on replay after a crash or retry a completed step returns its saved result instead of running again.
<T>(id, fn) => Promise<T>
required
Run fn once and memoize its result under id. Overload: run(id, input, fn) also records an explicit input.
AIStep
required
Durable model calls: generate, wrap, embed, loop. See AI steps.
(id, reason?: string) => Promise<void>
required
Record a deliberately bypassed step as a terminal “skipped” step; the optional reason is stored as its output. Durable: id must be stable across replays.
(id, duration: string | number) => Promise<void>
required
Suspend the run for a relative duration - a string like ”30s”/“1h”, or a number of ms.
(id, at: Date | string | number) => Promise<void>
required
Suspend the run until an absolute time - a Date, an ISO string, or epoch ms.
<T>(id, { event, timeout, if? }) => Promise<T | null>
required
Suspend until a matching event arrives, returning its data; resolves to null when timeout elapses first. Optional CEL if filters on the event payload so the run resumes only on the correlated event.
<T>(id, probe, { every, timeout, until?, maxChecks? }) => Promise<T>
required
Re-check an external resource until it is ready, sleeping durably between checks, without spending the step’s retry budget. Returns the ready value; throws PollTimeoutError when the deadline passes.
<T>(id, { name, app?, runner?, data?, tags? }) => Promise<T>
required
Invoke another workflow as a child run and wait for its result.
(id, { name, app?, data? }) => Promise<void>
required
Emit an event from inside a run.
<A>(id, { tool, args?, risk?, summary?, policy?, context?, allow?, escalatesTo?, timeout?, onTimeout? }) => Promise<ApprovalResult<A>>
required
Park the run on a human decision and resolve to it on resume. onTimeout says what the timeout does: escalate (default), approve, reject, or fail.

run

The unit of durable work: fn executes once and its result is memoized under id. The three-argument overload also records an explicit input, which the run inspector shows on the step’s Input tab and hands to fn.

sleep and sleepUntil

The run is suspended, not blocked: it holds no worker while it waits, and it survives a restart.

waitForEvent

Suspends until an event with the given name arrives, returning its data - or null when timeout elapses first, which is how you branch on the timeout.

poll

Re-checks an external resource until it is ready, sleeping durably between checks. The probe reads the resource and returns its value once ready, or a “not ready yet” signal otherwise; a not-ready check is a normal successful read, so it never spends the step’s retry budget. Returns the ready value, or throws PollTimeoutError when timeout elapses first.
string | number
required
Delay between checks - a duration string like “5s” or a number of milliseconds.
string | number
required
Overall deadline for the whole wait. Once it passes, poll throws PollTimeoutError.
(value: T) => boolean
Readiness predicate. When omitted, a non-null probe value is treated as ready.
number
Safety cap on the number of checks.
A probe that throws is a genuine error, not a not-ready signal: it retries under the step’s retry policy and fails the run if it exhausts its attempts. A PollTimeoutError fails the run and routes to onFailure; wrap the call in try/catch to treat a missed deadline as a non-fatal branch instead. See Poll until ready. Each check costs two durable steps (a step.run probe plus a step.sleep gap), not a free suspension - every: "5s" over timeout: "10m" is up to 120 checks, 240 durable steps. Pick the widest every the resource’s provisioning time tolerates.

runWorkflow

Invokes another workflow as a linked child run and waits for its result. Omit app to resolve the name in the caller’s app first, then any app in the project; set runner to pin the child to a specific runner. Pass tags to attach run tags to the child - it also inherits the parent run’s tags, with the child’s value winning on a shared key.

emit

Emits an event from inside a run, which fans out to whatever triggers match it. Omit app to broadcast project-wide; set it to narrow the event to one app’s triggers.

approval

Parks the run on a human decision. The run suspends in needs_attention - checkpoint kept, no worker held - until it is approved or denied, then resolves. args on the result are the effective arguments: the decider’s edits when they changed them, otherwise the proposed ones. A timeout sets a deadline and onTimeout says what reaching it does - by default it escalates and keeps waiting. See Approvals.

hashStepId

Returns the stable hash Duraton keys a step’s memoized result by. It is exposed for tooling that correlates a step id with its recorded entry.