Output Contract & Built-in Verbs
The output contract
Section titled “The output contract”The output: block is typed and it is both documentation and a runtime check — values passed to return: must match. Anything in the final payload not declared in output: is dropped on the way out.
output: total: !int rows: !obj-list summary: !obj
steps: - return: total: "${= len(products.rows)}" rows: "${products.rows}" summary: { fetched-at: "${= str(_invocation-id)}" }The contract is what makes a flow callable from REST, MCP, the CLI, and other flows with the same guarantees — every caller knows the shape it gets back.
return: — the simple form
Section titled “return: — the simple form”In the simple form, top-level keys map directly to declared output fields. The full output: step form lets you set a MIME type, attach a cache policy, or redirect:
# Presigned-URL handoff- return: redirect: "${upload.url}" status: 302If you declare an output: field that no return: populates, the runtime contract check fails the flow at the end. Either populate the field or remove it from the contract.
Built-in verbs
Section titled “Built-in verbs”Three verbs you’ll use constantly that aren’t operators:
# Log a line at info level- log: "Loaded ${= len(items)} items from ${source}"
# Single variable assignment (mutable var or persist key)- $counter: "${= counter + 1}"
# Batch assignment — multiple keys in one step, committed atomically- set: cursor: "${products.last-id}" last-sync: "${= str(_invocation-id)}" seen-count: "${= seen-count + len(products.rows)}"log:writes to the invocation’s log stream, readable live viazen logs <invocation-id>or after the fact via REST.$var:assigns a singlevars:orpersist:key.set:is preferred over multiple$var:lines when updating several variables at once because it commits them atomically.
The other terminating verb is halt: — which stops without producing output, in contrast to return:.