Control flow

Branches, while-loops, foreach, parallel fan-out/join, and the condition grammar.

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"),
]
String literals use single quotes

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.