ConceptsWorkflows

Workflows

A Workflow is a standing delegation — the way you'd tell an assistant "watch these Slack messages and prepare a report." It has two parts: when it happens (Trigger) and what happens, step by step (Steps) — a pipeline the platform interprets directly when the trigger fires. An Agent isn't the whole job anymore; it's one kind of step you reach for when a step actually needs judgment.

Trigger

When the Workflow fires: manually from the workflow editor's Run popover, a webhook, a form submission, a Slack event, or a schedule. Each kind is covered in Triggers.

Steps

Seven step kinds, in two families. Three do work:

  • Tool — one deterministic call to a tool on a workspace MCP connection: search Slack, create a Linear issue, fetch a page. No model involved, so it's fast, cheap, and does the same thing every time.
  • Infer — a single direct model call on one of the workspace's model presets: a prompt in, text or a declared structured shape out. For cheap transforms like summarizing or classifying.
  • Agent — a real session against a published Agent, run as a child run with its own full timeline. For open-ended work that needs the Agent's tools and judgment.

And four control the flow, interpreted by the platform itself: For each (repeat a body of steps per item of a list), Branch (run different steps by condition), Filter (continue only when a condition holds — false at the top level skips the rest of the run, false inside a loop drops that item), and State (write durable keys that persist across runs).

The doctrine is the cheapest kind that suffices: if the arguments are knowable up front, use a tool step; if it's a bounded transform, infer; only reach for an agent step when the work is genuinely open-ended.

References and the run scope

Steps talk to each other with @ references, resolved at run time against the run's scope: @trigger.<field> reads the trigger event's data, @steps.<slug>.<path> reads an earlier step's output (every step has a slug — its handle), @state.<key> reads the Workflow's durable state, @item is the current item inside a For each body, and @now is the run's start timestamp. In a prompt or template, a reference that resolves to nothing renders as "(not provided)" rather than failing the run.

Two scoping rules matter. A step can only reference steps before it. And a For each body is iteration-scoped: a body step's output is addressable only from later steps of the same iteration — after the loop, only the loop step's own aggregate output survives.

Workflow state

Each Workflow carries a small durable key-value store that outlives any single run — written by State steps, read with @state.<key>. Its canonical use is a cursor: "search since @state.cursor, process what's new, advance the cursor" is how a polling Workflow avoids re-processing the same items. See Build a scheduled Workflow for that pattern end to end.

Agent steps and versions

An agent step binds one published Agent and hands it instructions rendered against the run scope. The child run uses the Agent's current published version at dispatch — the Agent's own equipment (connections, skills, model) is what it runs with, exactly as in chat. On a Slack-triggered Workflow, an agent step can opt into thread continuity, so replies in one Slack thread continue one ongoing session; see Triggers.

No builds

Publishing a Workflow builds nothing. Publish validates the pipeline — the trigger's shape, at least one runnable step, agent steps bound to published Agents, tool steps on real enabled workspace connections, every @ reference legal for its position — then snapshots it, so edits go live instantly. Runs always execute the published snapshot, never the draft.

Where the result goes

Every run lands in the Workflow's Runs tab as a per-step timeline — each step's status, timing, and rendered input and output, with agent steps carrying their child run's full transcript. Beyond that, output goes exactly where the steps put it: a tool step that files an issue has filed it. Two trigger-specific notes: a webhook's HTTP response is only an acknowledgement that a run started, never the result; and a Slack-triggered Workflow posts a reply to the thread only when its configuration declares one (onComplete.slackReply, a template rendered when the run completes) — nothing is posted when it doesn't.

One run at a time

By default a trigger firing while another run of the same Workflow is still live is skipped, not queued — deliberately, so a slow run can't overlap the next window and corrupt cursor state. A skipped webhook dispatch still answers 2xx (the caller did nothing wrong); the run simply doesn't start.

What a Workflow is not

A Workflow has no persona and no model of its own — infer steps borrow workspace presets, and agent steps borrow published Agents whole. And it's not something you converse with: there's no chat surface for a Workflow the way there is for an Agent — its only interface is its trigger, and its only record is its runs.