Cases
Every branching node routes through an ordered list of cases. Each case pairs a condition (when) with a destination and optional effects (then):
on_no_match, or the definition-wide on_no_match if the node doesn’t declare one — so an execution always has somewhere to go. Point the definition-wide fallback at a dedicated end node (an unhandled ending) and it doubles as your safety net.
Operands
Conditions compare operands, each one of three forms:
Arithmetic supports
+, -, *, /. Addition and multiplication take any number of args; subtraction and division take exactly two:
Comparisons
Combinators
Combine conditions withall (AND), any (OR) and not, nested up to 32 levels:
{"exists": {"var": "..."}} is true when the variable is present, and {"always": true} matches unconditionally — the standard last case or single-exit route.
Effects
A matching case can write to durable state before moving on:set_value targets are always state.<name> (one level deep). state.* is the execution’s scratchpad — it survives retries, later calls and waits, and is never reset.
Variable namespaces
call.*, response.* and whatsapp.* hold the latest node’s values of that kind. When a workflow has two agent nodes and you need the first call’s status after the second call ran, read it from node.<first_node_id>.* instead.Variables in node configs
Node configs (agent prompt variables, API URLs/bodies, WhatsApp templates) don’t embed expressions directly. They use{placeholder} references resolved by the node’s config.variables map:
value operand, an optional type (one of string, number, boolean, timestamp, phone, email, url, json — the value is coerced, and the execution treats a failed coercion as a missing value), and required. A missing required variable stops the execution with termination_reason required_variable_missing; a missing optional one resolves empty and the execution continues with a warning event on its timeline.
Next Steps
Nodes
What each node writes and branches on
Quickstart
See conditions in a complete working definition

