Flow

DAG pipelines: flow.json, nodes, routing, and input templating.

Flow

A Flow is a fixed, repeatable DAG pipeline that runs a structured multi-agent process. Flows are the right tool when the same sequence of agent handoffs must run consistently, every time.

Directory Layout

flows/<name>/
├── flow.json      # DAG definition (required)
└── agents/        # Flow-scoped agents
    └── <short-name>/agent.json

flow.json

{
  "name": "code-review",
  "description": "Multi-dimensional code review pipeline.",
  "entry": "scanner",
  "maxLoop": 3,
  "nodes": [
    {
      "id": "scanner",
      "agent": "scanner",
      "prompt": "Scan the changes and list all findings with severity.",
      "onComplete": { "type": "goto", "target": "reviewer" }
    },
    {
      "id": "reviewer",
      "agent": "reviewer",
      "prompt": "Classify each finding by severity.",
      "onComplete": { "type": "switch", "cases": [["PASS", "fixer"], ["FAIL", "return"]] }
    },
    {
      "id": "fixer",
      "agent": "fixer",
      "prompt": "Apply fixes for the accepted findings.",
      "onComplete": { "type": "goto", "target": "reviewer" }
    }
  ]
}

Fields

| Field | Type | Required | Description | |-------|------|----------|-------------| | name | string | Yes | Unique flow name | | description | string | Yes | What the flow does (used for triggering) | | entry | string | Yes | Id of the entry node | | maxLoop | int | No | Maximum node executions per run (loop guard) | | nodes | Node[] | Yes | Node definitions |

Node

| Field | Type | Required | Description | |-------|------|----------|-------------| | id | string | Yes | Unique node id (referenced by routing) | | agent | string | Yes | Flow-scoped agent directory name | | prompt | string | No | Task template for this node | | onComplete | Route | No | Where to go after success | | onError | Route | No | Where to go after failure (default: abort) |

Routing

Node routing is declared per node in onComplete:

| Type | Meaning | |------|---------| | goto | Always go to target node | | switch | Choose by the node's JSON output; cases is [pattern, target] pairs | | return | Finish the flow and return the node output |

Example switch routing on a reviewer's verdict:

"onComplete": {
  "type": "switch",
  "cases": [
    ["PASS", "return"],
    ["FAIL", "fixer"]
  ]
}

Input Templating

Node prompts support variable substitution from the flow context:

| Variable | Meaning | |----------|---------| | $task | The flow's input task | | $<nodeId>.output | The output of a previous node (e.g. $scanner.output) |

{
  "id": "reviewer",
  "agent": "reviewer",
  "prompt": "Review these findings: $scanner.output"
}

Flow Agents

Flow-scoped agents live in flows/<name>/agents/<short-name>/. They have one important constraint:

Output must be JSON. The flow engine parses node output for routing — switch nodes inspect status / verdict fields, and return nodes deliver structured results.

{
  "status": "FAIL",
  "verdict": "blocker",
  "summary": "Unhandled null pointer in line 42"
}

Keep flow agents single-purpose and deterministic: they run the same way every time, driven by the flow definition.

Execution Model

  1. Flow is triggered by name with a task string
  2. The entry node's agent runs with $task substituted into its prompt
  3. On success, onComplete routes to the next node
  4. On error, onError routes (or the flow aborts)
  5. maxLoop caps total node executions to prevent runaway loops

Team-invoked Flows

Teams list flows they may invoke in team.json. A team-triggered flow renders as an inline widget inside the team card — the flow runs in the team's context rather than as a separate global pipeline.