A step’s outgoing flow is declared in its opts. Use at most one of next, branches,
loop, foreach, or parallel per step.
Branches (conditional routing)
A step routes to the first branch whose condition is true. List a catch-all
branch("true", …) last.
step("decide", {
branches: [
branch("total > 1000", "manual_review"),
branch("payment_status == 'success'", "fulfill"),
branch("true", "reject"), // catch-all
],
}, function decide(ctx) { return {}; }); // handler still required
branch(condition, next) is only valid inside opts.branches.
Loop (while)
step("poll", {
loop: {
condition: "attempts < max_attempts AND status != 'done'",
next: "poll_body", // step run while the condition holds
breakNext: "finish", // step run once the condition is false
},
}, function poll(ctx) { return {}; });
Keys: condition, next (loop body), breakNext (exit target). Update the variables the
condition tests inside the loop body so it can terminate.
Foreach
step("process_items", {
foreach: {
collection: "items", // name of a variable holding an array
itemVar: "item", // each element is exposed as ctx.vars.item in the body
body: "handle_item", // step run per element
next: "after_items", // step run after the collection is exhausted
},
}, function processItems(ctx) { return {}; });
step("handle_item", { next: "process_items" }, function handle_item(ctx) {
return { processed: (ctx.vars.processed || 0) + 1 };
});
collection is the variable name, not an array literal. Each element is available as
ctx.vars.<itemVar> inside the body step.
Parallel (fan-out / join)
step("fanout", {
parallel: {
steps: ["fetch_a", "fetch_b", "fetch_c"], // run concurrently
next: "join", // run after all complete
},
}, function fanout(ctx) { return {}; });
Keys: steps (names to run concurrently) and next (the join target, run once all complete).
Condition grammar
Branch and loop conditions are expressions over the current variables:
- Comparisons:
==,!=,>,<,>=,<= - Connectives:
AND,OR(uppercase) - Literals:
true,false, numbers,'single-quoted strings' branch("true", "fallback")is the catch-all — list it last
branches: [
branch("payment_status == 'success'", "fulfill"),
branch("retry_count < max_retries AND payment_status != 'completed'", "retry"),
branch("true", "handle_failure"),
]
Write status == ‘pending’, not double quotes, and keep AND/
OR uppercase. The values being compared are plain variable names from
ctx.vars.
Next: Human-in-the-loop.