Workflows

A workflow is the executable definition of an AI Employee. It is a directed acyclic graph (DAG): a set of nodes connected by edges. Each node does one unit of work — reasoning with an agent, reshaping data, declaring an output. Each edge carries data and an optional condition that decides whether the downstream node runs. Because the graph is acyclic, the platform can sort it into an execution order where every node runs only after the nodes it depends on have finished.

You edit a workflow visually in the AI Employee builder, save drafts as you go, and publish when it is ready. Every run executes against the live published version and records a full step-by-step trace.

The DAG model

A workflow's definition is a single JSON object with two arrays:

{
  "nodes": [ /* DAGNode objects */ ],
  "edges": [ /* DAGEdge objects */ ]
}
  • Nodes are the units of work. Each has a unique id, a type, a human-readable label, and type-specific configuration.
  • Edges connect a from node to a to node. An edge declares a data dependency and may carry a condition. An edge with "type": "ordering" enforces order only, with no data dependency.

The platform builds the DAG, computes each node's in-degree (how many edges point at it), and runs a topological sort. Nodes whose dependencies are all satisfied become eligible at the same time and run in parallel, up to the configured parallelism limit.

Node types

A node's type field is one of the following. The agent node is where reasoning happens; the others are structural or deterministic.

typePurpose
startThe entry point. Maps the run's input into the workflow. Exactly one per workflow. Its input_schema declares the fields the workflow accepts.
agentA reasoning step. Runs a configured agent type (set in agent_config.agent_type), with optional knowledge bases, Tools, and a human-in-the-loop block. This is where LLM work, RAG retrieval, and Tool calls happen. See Agents.
transformA deterministic, non-LLM reshape. Extracts and coerces named fields from an upstream value using a list of rules. Never calls a model and never bills tokens. Use it to pull specific fields out of an agent's output, apply defaults, and coerce types (string, number, boolean, datetime).
publishDeclares one or more named outputs. The output_fields on the workflow's publish nodes are the AI Employee's public output contract — they become the run's named_outputs and the columns of a dashboard. A workflow with no publish nodes produces no named outputs.
endA terminal node marking the close of a path.

Agent type vs. node type. Every reasoning node has "type": "agent". Which agent type it runs is set separately in agent_config.agent_type (for example intent_classification or search_respond). The special feedback_router agent type routes a run based on end-user feedback. See Agents.

Human in the loop, conditions, and Tools

There is no dedicated "ask a human" node type. Two distinct mechanisms pause or branch a run, and both live on the structures above:

  • Human in the loop is configured with a hitl_config block on an agent node. The run pauses when the node reaches it and resumes when a person responds. See Human in the Loop.
  • Conditions live on edges, not nodes. The condition on an outgoing edge decides whether that branch runs. See Conditions and Expressions.
  • Tools (integration functions and MCP servers) are selected on an agent node via action_ids and mcp_server_ids. The agent runtime exposes them to the model as callable tools.

Edges and conditions

An edge looks like this:

{
  "from": "classify",
  "to": "escalate",
  "condition": {
    "type": "field",
    "field": "output.priority",
    "operator": "eq",
    "value": "HIGH"
  }
}

When the from node completes, the platform evaluates each outgoing edge's condition. If the condition is true (or absent), the to node becomes eligible. If it is false, that branch is skipped. Edge conditions can only reference the source node's output.* namespace — workflow_input.* and other namespaces are rejected at save time so misplaced references surface in the builder instead of silently failing every run. The full operator catalog and the branching rules are in Conditions and Expressions.

Passing data between nodes

A node pulls its inputs from upstream nodes and from the run input through input_mapping, using {{...}} references:

  • {{workflow_input.field}} — a field from the run's input_params.
  • {{node_id.output.field}} — a field from the output of an upstream node.

An input can be marked optional. If an optional input's source node was skipped, the input is omitted and the node still runs; if a required input's source was skipped, this node is skipped too (skip propagation). See Conditions and Expressions.

Parallelism and limits

Nodes with no dependency between them run concurrently. The platform caps how many run at once and bounds the size of the graph so execution stays predictable:

LimitDefaultEnvironment variable
Maximum nodes per workflow50EMU_MAX_DAG_NODES
Maximum edges per workflow200EMU_MAX_DAG_EDGES
Maximum nodes running in parallel5EMU_MAX_PARALLELISM

The node and edge limits are enforced on every draft save and again at publish. The parallelism limit shapes execution at run time.

Drafts, versions, and publishing

A workflow is edited as a draft and deployed by publishing. The two states are kept separate so you can iterate freely without affecting what end users see.

  • Saving a changed DAG writes a new immutable version row, marked as a draft (not yet published, not active). You can save as many drafts as you like.
  • Publishing validates the draft, captures the live configuration and the attached knowledge bases into a snapshot, stamps the version as published, and marks it the single active version — all in one transaction. New runs resolve to the active version.
  • Promote makes an earlier published version active again (a forward activation).
  • Revert makes an earlier version active and reconciles the attached knowledge bases back to the state captured when that version was published.

Each version is a self-contained snapshot: agent configuration is stored inline on each node, so editing an agent template later never changes a published workflow. A version may carry an optional name and description as a human-friendly alias.

The builder distinguishes "the current DAG is live" (the active version is the latest) from "you have unpublished changes" (the active version is older than your latest draft), so you always know whether your edits are reaching end users.

Publishing can fail pre-flight. The most common blockers are NO_LLM_PROVIDER (an agent references an LLM provider not enabled for your tenant), HITL_INVALID_ASSIGNEE (a human-in-the-loop node assigns to a user who doesn't exist), and structural errors (a DAG_INVALID_* code such as DAG_INVALID_NODE or DAG_CYCLE_DETECTED, or DAG_TOO_LARGE). Fix the reported issue and publish again.

DAG validation

Validation runs on every draft save and again at publish. It checks structure, not behavior:

  • Size within the node and edge limits.
  • A unique id on every node, and edges that reference only existing nodes.
  • Exactly one start node, and required fields present on each node.
  • No cycles — the graph must remain acyclic.
  • Edge conditions that are well-formed and reference only the allowed output.* namespace.

Structural failures return a specific DAG_INVALID_* code (for example DAG_INVALID_NODE, DAG_INVALID_EDGE, or DAG_CYCLE_DETECTED) — or DAG_TOO_LARGE when a size limit is exceeded — so you get a tight feedback loop in the builder.

Runs and steps

A run is one execution of a workflow. Starting a run creates a new run record; the workflow's identity (workflow_id) never changes, but every run gets a fresh run_id.

Start a run by POSTing to the run endpoint:

POST /api/v1/workflow/workflows/{id}/run
Content-Type: application/json

{
  "input_params": { "message": "Where is my order?" },
  "session_id": "b2c1…"
}

input_params is validated against the start node's input_schema. session_id is optional and groups chat runs into a conversation. Use the parallel /dry-run endpoint to test a workflow without committing the result.

A run moves through these states:

Run statusMeaning
pendingCreated, not yet executing.
runningExecuting nodes.
pausedWaiting on a human-in-the-loop response or an async step.
completedAll reachable nodes finished; named outputs collected.
failedA node failed, or the run timed out.
cancelledCancelled by a user or by the run-cancel cascade.

Each node execution is recorded as a step, with its own status:

Step statusMeaning
pendingNot yet started.
runningExecuting.
completedFinished successfully.
failedErrored.
skippedIts branch condition was false, or a required input came from a skipped node.
pausedWaiting on a human-in-the-loop response.

A step record stores the resolved input, the output, the status, token usage, the agent configuration it ran with, and — when the node completed normally — the per-edge condition results (edge_evaluations), so the run history can show exactly why each branch was taken or skipped.

Reading a run

  • GET /api/v1/workflow/runs/{run_id} — the run record, including status, total_tokens, output, and named_outputs.
  • GET /api/v1/workflow/runs/{run_id}/steps — the per-step trace.
  • GET /api/v1/workflow/runs/{run_id}/stream — real-time run events over SSE while the run is in progress.

named_outputs is a flat map keyed by your publish nodes' output field keys — the AI Employee's public output contract. Workflows with no publish nodes return a null named_outputs by design.

A worked example

Consider a support workflow: a start node, a classification agent, two branches, and a publish node.

start ──▶ classify ──[priority == "HIGH"]──▶ escalate ──▶ publish
                  └──[priority == "LOW"]───▶ auto_resolve ─▶ publish
  1. A run starts with input_params = {"message": "My account is locked!"}.
  2. The classify agent (an intent_classification agent) emits output.priority.
  3. The platform evaluates the two edges leaving classify. If priority is "HIGH", the escalate branch runs and auto_resolve is skipped; if "LOW", the reverse.
  4. The publish node writes the AI Employee's named outputs from whichever branch ran.

The run's step trace shows classify as completed, one branch completed, the other skipped, and the edge_evaluations on classify recording which condition was true.

Where to go next

Last updated: Jul 3, 2026