Skip to content

Choose Execution Paths

How do you choose which steps run? Use Only when to skip one action, If / Else to choose the first matching branch, and Router to run every matching route. Use Join Paths before their shared action.

Start with Invoice intake’s flow contract and configured actions in the development version. Each alternative below reviews an invoice when Amount is over 1000. In the app, open Workflows → Invoice intake → Dev → flow.

These commands assume a pinned workflow. Start by listing them:

Terminal window
cai workflow list --limit 100 --json

Choose the exact Invoice intake entry’s data.items[].id as <workflowId>. If names collide, ask which one is meant. Check data.hasMore before concluding it is absent. The CLI can request a larger limit, while MCP caps at 100.

Pin it, then read the outline:

Terminal window
cai use <workflowId> --json
cai workflow outline --json

From data.flows[].id, note <flowId>. From that flow’s nodes[].id, note <noteNodeId>, <reviewNodeId>, <ordinaryNodeId> and <sharedNodeId> by name. These examples use one action per branch. Scoped MCP calls always require workflowId.

In the action’s menu, choose Enable skip condition → Only when. A false condition skips that node and leaves its outputs null. Everything downstream stays eligible. To exclude the entire storage path, use branching.

Read the expression context before setting a condition. These examples assume flow.amount. If you renamed the input, substitute the binding that context advertises throughout.

Terminal window
cai expr context <noteNodeId> --json
cai node only-when <noteNodeId> --js 'flow.amount > 1000' --json

MCP uses node_only_when_set with nodeId and js.

Scalar conditions reject && and ||. In a compound rule, entries in a row are joined with AND, and rows are joined with OR. This replacement limits the note to amounts above 1000 and below 2000:

Terminal window
cai node only-when <noteNodeId> --groups-json '[["flow.amount > 1000","flow.amount < 2000"]]' --json

MCP node_only_when_set takes parsed groups; branch commands use --condition-json, mapped to parsed conditionJson.

Choose one branch and configure its fallback

Section titled “Choose one branch and configure its fallback”

Choose Add action, search Actions for If / Else, then edit the initial If’s When. A new If is blank, and a blank If fails execution validation. Else must be unique, last and condition-free. Add branch adds conditions. Move up and Move down change first-match priority.

Find each control before adding it:

Terminal window
cai integration actions 'If / Else' --json
cai integration actions 'Router' --json
cai integration actions 'Join Paths' --json
cai integration actions 'Wait' --json

MCP uses integration_action_list for searches and integration_action_get for details.

For each matching data.items entry, note nodeSlug and key as its named placeholders below. Inspect If / Else, then add it:

Terminal window
cai integration action --integration <ifSlug> --key <ifComponentKey> --json
cai node add --flow <flowId> --node <ifSlug> --key <ifComponentKey> --name "Choose invoice review" --json

Note data.nodeId as <ifNodeId>, then read its branches and bindings:

Terminal window
cai branch list <ifNodeId> --json
cai expr context <ifNodeId> --json

Note the data.items[].id values for If and Else as <ifBranchId> and <elseBranchId>. Update the existing If, then connect both branches:

Terminal window
cai branch update <ifNodeId> --route <ifBranchId> --name "Needs review" --js 'flow.amount > 1000' --json
cai branch connect <ifNodeId> --flow <flowId> --route <ifBranchId> --to <reviewNodeId> --json
cai branch connect <ifNodeId> --flow <flowId> --route <elseBranchId> --to <ordinaryNodeId> --json

MCP branch_update and branch_connect use branchId for --route.

To reorder conditions, replace <ids> with every condition ID from branch list, comma-separated and listed exactly once. Exclude Else:

Terminal window
cai branch reorder <ifNodeId> --order '<ids>' --json

MCP branch_reorder takes an order array.

In the app, draw each branch’s output handle to its action. Ordinary node connect supports main and Error outputs, not branch IDs. If you connect exclusive branches directly to one ordinary action, that action is blocked whenever either incoming path is untaken.

When the checks overlap, use Router instead, under Routes → Add new route → When. Routes have no order, so the app has no move controls and branch reorder rejects Router. Blank Router conditions are true at runtime, and contrary CLI warnings are stale. Set each condition explicitly.

Inspect Router, then add it:

Terminal window
cai integration action --integration <routerSlug> --key <routerComponentKey> --json
cai node add --flow <flowId> --node <routerSlug> --key <routerComponentKey> --name "Check invoice routes" --json

Note data.nodeId as <routerNodeId>, then read its routes and bindings:

Terminal window
cai branch list <routerNodeId> --json
cai expr context <routerNodeId> --json

Use the initial data.items[].id as <reviewRouteId>, then name that route and add a second one:

Terminal window
cai branch update <routerNodeId> --route <reviewRouteId> --name "Needs review" --js 'flow.amount > 1000' --json
cai branch add <routerNodeId> --name "Positive amount" --js 'flow.amount > 0' --json

Note the add result’s data.id as <positiveRouteId>, then connect both routes:

Terminal window
cai branch connect <routerNodeId> --flow <flowId> --route <reviewRouteId> --to <reviewNodeId> --json
cai branch connect <routerNodeId> --flow <flowId> --route <positiveRouteId> --to <ordinaryNodeId> --json

Add Join Paths, wire every branch tail into it, and select Mode. It waits for all incoming sources to finish or skip.

ModeActive inputsResult
chooseActivePathOnePasses that input’s value.
chooseActivePathZeroskipped, skipReason: "no_active_path"; downstream is blocked. Enabling Continue execution when no path is active instead completes with null.
chooseActivePathMultipleFails.
passThrough (default)AnyOne field per input; blocked inputs are null. Use for overlapping routes.

Inspect Join Paths, then add it:

Terminal window
cai integration action --integration <joinSlug> --key <joinComponentKey> --json
cai node add --flow <flowId> --node <joinSlug> --key <joinComponentKey> --name "Join invoice paths" --json

Note data.nodeId as <joinNodeId>. With Router, keep the default passThrough and skip the mode and type writes below, but use the same connections. For exclusive paths, set the mode and read both tails:

Terminal window
cai node set <joinNodeId> --prop mode --value chooseActivePath --json
cai node props <joinNodeId> --json
cai node get <reviewNodeId> --json
cai node get <ordinaryNodeId> --json

These connections use each tail’s Main output. Select its data.outputs[] entry, excluding Error, and confirm the dataType values agree before you set <pathDataType>. For a join that already exists, inspect its edges first:

Terminal window
cai flow get <flowId> --json

Match each join edge’s data.edges[].sourceHandle (output-<outputId>) to that source’s data.outputs[].id. Use that exact output’s type.

pathDataType has no options list. Every connected input whose type resolves must match, including inactive inputs. Unresolved types escape the check, so resolve dynamic outputs and validate.

Set that type, then wire both tails into the join and the join into the shared action:

Terminal window
cai node set <joinNodeId> --prop pathDataType --value '<pathDataType>' --json
cai node connect --flow <flowId> --from <reviewNodeId> --output main --to <joinNodeId> --json
cai node connect --flow <flowId> --from <ordinaryNodeId> --output main --to <joinNodeId> --json
cai node connect --flow <flowId> --from <joinNodeId> --to <sharedNodeId> --json

MCP uses node_prop_set for node set and node_prop_list for node props.

Add Wait, set Seconds, and wire Join → Wait → shared action. Wait returns true, so keep Join → shared action to preserve its payload. The shared action then waits for both inputs. Wait defaults to 1 second, accepts 0–2,592,000 seconds and uses a durable timer.

Inspect Wait, then add it after the join:

Terminal window
cai integration action --integration <waitSlug> --key <waitComponentKey> --json
cai node add --flow <flowId> --node <waitSlug> --key <waitComponentKey> --after <joinNodeId> --props '{"seconds":30}' --json

MCP node_add takes parsed props.

Note data.nodeId as <waitNodeId>, then wire it into the shared action:

Terminal window
cai node connect --flow <flowId> --from <waitNodeId> --to <sharedNodeId> --json

Continue on error is unavailable on If / Else, so handle errors on the preceding action. Turning it off on an action deletes Error-output edges and the target inputs they supplied. Inspect those dependents afterwards.

A selected route that is not wired can end in a green run with no intended output. Audit your chosen <controlNodeId> (If / Else or Router), fix unwired paths, then validate:

Terminal window
cai branch list <controlNodeId> --json
cai flow layout <flowId> --json
cai workflow validate --json
cai run inputs <flowId> --flow --json

MCP run_inputs takes the flow ID as nodeIdOrFlowId and flow: true.

From the input result’s data.flowInputs[], note Invoice ID’s id as <invoiceInputId> and the amount input’s id as <amountInputId>. The fixtures use these IDs, so a display-name change does not affect them.

In Dev, choose Test (tooltip: Test current flow), then Run history. Provider actions execute for real, so choose test destinations first.

Run each fixture separately. After each run, note data.workflowExecutionId as <workflowExecutionId> and inspect it before you continue. A failed, paused or timed-out CLI run reports error.detail.workflowExecutionId instead.

Terminal window
cai run flow <flowId> --target dev --inputs '{"<invoiceInputId>":"INV-104","<amountInputId>":120}' --json
cai exec tree <workflowExecutionId> --json
Terminal window
cai run flow <flowId> --target dev --inputs '{"<invoiceInputId>":"INV-104","<amountInputId>":1000}' --json
cai exec tree <workflowExecutionId> --json
Terminal window
cai run flow <flowId> --target dev --inputs '{"<invoiceInputId>":"INV-105","<amountInputId>":1500}' --json
cai exec tree <workflowExecutionId> --json
Terminal window
cai run flow <flowId> --target dev --inputs '{"<invoiceInputId>":"INV-104","<amountInputId>":0}' --json
cai exec tree <workflowExecutionId> --json

MCP run_flow takes flowId and parsed inputs; execution_tree takes workflowExecutionId.

Expect Else at 120 and 1000, and Needs review at 1500. With Router, 1500 selects both routes and 0 selects neither. Confirm one shared action after a pass-through join. Distinguish only_when_false, upstream_skipped and no_active_path in run details.