Passing Data Between Steps
Every node in a run writes its output to a variable. Later nodes read those variables through templates (in input messages and arguments) and expressions (in Condition branches and Loop End break conditions).
Inserting a variable
In any field that accepts variables — Input Message Template, function arguments, Model Override — either:
- type
$and pick from the list, or - click a chip under the field: Attributes: lists the workflow's attributes, and Previous node outputs lists the other nodes.
The variable is written as ${name}. Below the field, Reads as shows the template with each variable as a chip, named after the node it points to. Click a chip to point it somewhere else, or its × to remove it. Click (show raw) to see the stored text.
A red chip and the message "N references no longer resolve and will fail at run time" mean the node a variable points to has been deleted.
What you can reference
| Variable | Contains |
|---|---|
${node_2_result} | The text output of node node_2. Every Agent, Team, Function and Mission node writes ${<node_id>_result}. Node IDs never change when you rename a node. |
${attribute.topic} | The value entered for the topic attribute when the mission was launched. ${topic} also works. |
${initial_message} | The text the run started with (see below). |
${message} | The output of the most recently finished Agent, Team, Function or Mission node. |
${my_var} | A Function or Mission node's Output variable name, if you set one. |
${my_var_key} | For an output variable holding a JSON object, each top-level key (for example ${verdict_passed} for {"passed": true}). |
${current_item}, ${current_index}, ${items_remaining}, ${loop_total} | Inside a For Each loop. |
${loop_output}, ${loop_output_history} | A loop's tracked output, if Track output across iterations is on (named after the loop's output variable). |
A variable that doesn't exist is replaced with nothing. Lists and objects are inserted as text.
Templates look up a variable by its exact name. ${node_2.result} and ${current_item.title} don't work in templates — use ${node_2_result}, and an output variable's ${name_key} form for JSON fields. Dotted paths do work in Condition and break-condition rules (see below).
What the initial message is
| How the run started | ${initial_message} |
|---|---|
| Missions page | "Mission: workflow name" |
| Run Workflow in the builder | "Start workflow execution" |
| Schedule | "Scheduled execution" |
| Webhook | "Triggered by webhook event: type", a short summary of the event, then the raw JSON payload (cut at 4,000 characters) |
| Parent workflow's Mission node | That node's input message |
The text people type into attributes is not the initial message. Reference it with ${attribute.name}.
When the input message is empty
An Agent, Team or Mission node with an empty Input Message Template receives ${message} — the previous node's output — or the initial message if nothing has run yet. A Function node with no arguments set receives the same text as its single input.
Attribute values and automatic runs
Attribute values exist only when a mission is launched from the Missions page (or the API with values supplied). Runs started by a schedule, a webhook, the builder's Run Workflow button or a parent workflow get no attribute values — not even defaults. Every ${attribute.…} is empty in those runs. Write fixed text into the node instead, or for webhooks read the event from ${initial_message}.
Condition expressions
Condition branches and Loop End break conditions use rules of the form:
${source} operator value
The rule builder writes these for you. The Source list offers each node's → result, → status and → output and each attribute.
| Operator | True when |
|---|---|
== | Equal (compared as-is, then as trimmed text). |
!= | Not equal. |
> < >= <= | Numeric comparison. False if either side isn't a number. |
contains | Text contains the value; for a list or object, the value is one of its items or keys. |
not_contains | The opposite. |
is_empty / is_not_empty | Empty text, empty list or nothing at all (takes no value). |
Values: true, false, null and numbers are converted; anything else is text. Quote text with spaces or keywords in single quotes when writing by hand.
Combine rules with AND or OR — one or the other per expression, not both.
Sources in expressions can use dotted paths. The builder's Source list offers only node outputs and attributes; the other sources below can be written into a workflow through the Platform API or Platform MCP server.
| Source | Resolves to |
|---|---|
${node_2.result} / ${node_2.output} | Node 2's text output. |
${node_2.status} | Node 2's status, normally completed. A Condition's own result is true/false or the branch name. |
${attribute.severity} | An attribute value. |
${current_item.priority} | A field of the current For Each item. |
${verdict.passed} | A field of a JSON output variable. |
Examples:
${node_3_result} contains 'APPROVED'
${attribute.severity} == 'High' AND ${node_2_result} not_contains 'false positive'
${node_5.result} is_not_empty
${current_index} >= 9
Output variables and JSON
Set Output variable name on a Function or Mission node to keep its result under a friendly name. If the result is valid JSON it is stored as data, not text:
- a function returning
{"passed": true, "reason": "tests green"}with output variableverdictgives${verdict},${verdict_passed}and${verdict_reason}; - a list result can feed a For Each loop's Collection Variable.
A Mission node's result is a JSON object of every node result in the sub-workflow, keyed by node ID.