interface.yaml, and canvas draws one dot per entry.
interface.yaml
Sending something to an output
Declaring an output only creates the dot.api/events.yaml is what puts a value on it.
One row per output connector, in the same order interface.yaml declares them. Read that
one file and you know everything the node ever emits.
api/events.yaml
emit names the connector. value shapes what lands on it, as an expression over the
reply. An output with no row is a dot that never carries anything, and lint warns about it.
Emitting once, or many times
This is where the nodeβskind shows up.
A PromiseNode settles. One call, one reply, and each row fires once over that reply.
The rows above are a settling node.
A CallbackNode emits. The reply arrives as a stream of events, so a row says which
event it fires on, and it fires every time that event arrives.
api/events.yaml
Where a row fires from
from says where a row fires. response is the default, which is why most rows do not
write it. complete fires once at the end, over everything already emitted, and is how a
streaming node also produces one settled value.
from: tool exists because a toolβs result is never in the HTTP stream. The tool loop
produced it.
Two things are recorded without any row here, because they are execution facts rather
than node outputs:
- Every tool call becomes a bar on the execution timeline the moment it returns, with its arguments, its result, its duration, and whether it succeeded.
- Token usage is read off the vendorβs reply and summed across the turns of a run,
with nothing declared. The
usageconnector on a node that declares one is a different thing: the node choosing to hand the block downstream as data.
Reading what arrives
A downstream node reads an upstream output by name:quote1 is the id canvas gives the node on the canvas, and quote is the output
connector. So signal.quote1.quote is the quote text.
Give outputs names worth reading. They become the reference someone types into a Handlebars string
later, and a good name is the difference between signal.crm1.contact and
signal.crm1.output.
Types
type also decides how a wired field is written. A string field takes a Handlebars
string, an object or array field takes a return expression.
Config schema covers both.
Required, and what waiting means
required: true means the node waits for that connector before it runs.
Looping over a list
A node does not loop itself. You loop in the workflow, with the Loop nodes, and your node runs once per item like any other step. That keeps a node simple: it takes what it is given, does one job, and emits. A service connector is a different thing entirely. It is a node calling another node on demand, rather than a value travelling along an edge, and it fires no outputs. See Service connectors.When it goes wrong
Next steps
Node types
Settling once or emitting many times, and how the platform tells.
api/events.yaml
Every field an events row takes, generated from the schema.

