initializdocs
Workflows

Branching and approval gates

Add conditional branches (switch nodes) and human decision points (approval gates) to a pipeline, and follow the branch taken or the decision made on each run.

A pipeline is no longer only a straight chain. Two step kinds besides agent steps control how a run proceeds:

  • A switch routes the run down one of several branches based on a previous step's output — deterministically, with no model involved.
  • An approval gate pauses the run at a human decision point until a listed approver approves or rejects it.

Both are added from the canvas toolbar — Approval and Branch buttons sit next to the Add agent menu — and both are configured by selecting the node, which opens its inspector panel. They work on the create screen and in the detail page's edit mode alike.

Switch nodes (conditional branching)

A switch evaluates its cases in order against one input value; the first matching case decides which node runs next, and if none match, the mandatory default target runs — there is no silent fallthrough.

Authoring a switch

Click Branch on the canvas toolbar to add a switch node (rendered dashed, with a split icon), then select it to open the switch editor:

  • Input — a single $ref naming the value to route on: $userinput.<key> or $<nodeId>.<key> from an upstream step. Dotted paths reach into structured output (for example $classify.result.severity), and a $ref quick-pick lists the available run inputs and upstream output keys.
  • Cases — an ordered list. Each case is an operator, a comparison value, and a target node. The operators are eq, neq, in, contains, exists, gt, gte, lt, and lte; in takes a comma-separated list of values, and exists needs no value (it matches when the input resolved to something non-empty). String comparisons are tolerant of type — "3" equals 3 — while the numeric operators treat an unparseable side as a non-match.
  • Default (required) — the target when no case matches. Point it at an error-handling step or at End run.

The switch itself never calls a model. For AI-judged routing, compose it: add an agent step that outputs a short classification value, then switch on that value — this is the intended pattern, and the planner knows it too.

Explicit next steps

Once a pipeline branches, step order can no longer be implied by the node list, so every agent and approval editor also carries a Next step select: (in order) for plain sequential flow, a specific node, or End run to terminate that branch. After the first switch in a pipeline, an explicit next step is required on subsequent nodes — otherwise a branch's last step would silently fall through into a sibling branch.

The canvas renders the real graph: one labeled edge per switch case (for example eq "fraud") plus a default edge, and branches fan out visually so you can read the routing at a glance.

Validation at save

A pipeline with branches is checked when you save it. Rejected outright: duplicate node ids (or a node named end), a case or default pointing at a node that does not exist, a switch with no cases or no default, an unknown operator (or in without a list), a cycle in the graph, nodes unreachable from the entry node, a switch whose input comes from a step that cannot have run before it, and a missing explicit next step after the first switch.

What a branched run looks like

On the execution page, the switch joins the step timeline as a Switch row showing the decision it made: the input reference, the value it resolved to, the case that matched (or default), and the node it routed to. Steps that were reachable only through untaken branches appear with a terminal skipped status, so the timeline still accounts for every node; a node that several branches converge on runs exactly once.

If the switch's input cannot be resolved (for example, the upstream step produced no such field), the run is not stuck: the switch routes to the default target and records the resolution error on its row — the default branch doubles as the error handler.

Each decision also emits a Branch taken (workflow_branch_taken) runtime event carrying the same input → case → next summary, so branch decisions are visible in the event stream too.

Downstream steps can chain off the decision itself: $<switchId>.matched, $<switchId>.value, and $<switchId>.next resolve like any other step output.

Approval gates (human decision points)

An approval gate parks the run until a person decides. Unlike a compliance deferral — which pauses a single governed tool call inside an agent — an approval gate is authored into the workflow itself as a step: the run reaches it, stops, and waits.

Authoring an approval gate

Click Approval on the canvas toolbar, then select the node to open the approval editor:

  • Approver emails — a comma-separated list of people who may decide.
  • Org-admin role — a checkbox that additionally allows any org admin to decide. At least one email or the org-admin role is required.
  • Timeout (hours) — how long the gate waits, 72 hours by default.
  • On timeout — what happens if nobody decides in time: fail the run (the default), auto-approve, or auto-reject.
  • Payload to review — an optional $ref (with a quick-pick) naming the upstream value the approver should see, for example $draft.output. It is resolved when the gate opens and shown alongside the approval prompt.

The approver list is snapshotted when the gate opens: editing the workflow while a run is parked never changes who may decide that in-flight gate.

What a paused run looks like

When a run reaches the gate, the step shows awaiting approval in the timeline — with a direct link to the Approvals page — while the run itself stays Running; waiting is a per-step state. The gate appears in the Workflow approvals section of each listed approver's My Approvals queue, with the resolved payload, a link to the execution, and the absolute time it auto-resolves.

  • Approve — the step completes and the run continues. The decision is chained into the run as the gate's output, so downstream steps can reference $<gateId>.approved, $<gateId>.approver, and $<gateId>.comment.
  • Reject — the run stops and is marked failed.
  • Nobody decides in time — the gate's On timeout policy applies: fail the run, or auto-approve/auto-reject and continue accordingly, with the decision attributed to the timeout policy rather than a person.

Decisions are attributed to the approver's verified signed-in identity, and a second decision on an already-decided gate is refused. Decided gates move to the Completed tab of the Approvals page, so there is a reviewable history of what was approved, rejected, or timed out.

The gate's lifecycle is recorded in the runtime events for the execution: approval_requested when the gate opens (alongside the standing workflow_step_waiting breadcrumb), then approval_granted, approval_rejected, or approval_timeout.

An approval gate waits on its own clock — the timeout you author on the gate (72 hours by default) — not the per-step execution time budget that bounds agent steps. A parked gate survives platform restarts, and a run cannot be resumed past an undecided gate: the decision is the only way through.

On this page