Skip to content

Workflows

A workflow is the DAG of nodes + edges that defines what an agent does on execution. Workflows live inside agent specs; you don’t manage them separately — every agent create, agent update, and agent draft update carries a workflow inline.

Three structural rules (pre-flight)

The CLI runs three structural checks before any HTTP request leaves the machine. They mirror real bugs that surfaced in early agent builds and silently rendered as orphan handles in the dashboard:

Rule A — conditions only on router edges

Conditional edges must be sourced from a router node. The engine ignores conditions on edges from any other node type. Putting a condition on an edge directly from an ai node looks plausible but never fires.

// ✗ Wrong
{
"from_node_id": "classify", // ai node
"to_node_id": "handler",
"condition": { "field": "output.classify.x", "op": "eq", "value": "y" }
}
// ✓ Right — insert a router
{
"id": "route",
"type": "router",
"config": {
"routes": [
{ "name": "handler", "target_node_id": "handler",
"condition": { "field": "output.classify.x", "op": "eq", "value": "y" } }
]
}
}

Rule B — agent_invocation nodes need config.agent_id

A delegate node with config.agent_id: null shows the “Select agent” placeholder in the UI and silently never fires.

Terminal window
# Look up the delegate's ID by slug:
athena agent get drafter-delegate | jq -r '.id' # → 019f902b-db6f-7ea4-8ef2-60a8ff5747cd

Then set config.agent_id: "019f902b-db6f-7ea4-8ef2-60a8ff5747cd" on the invocation node.

Rule C — router edges need labels matching routes

Every outgoing edge from a router needs a label matching one of the router’s routes[].target_node_id (and by convention also routes[].name). The engine routes by label; without a match the target never fires.

{
"type": "router",
"config": {
"routes": [
{ "name": "yes", "target_node_id": "handler-yes" },
{ "name": "no", "target_node_id": "handler-no" }
]
}
}
// → edges must be labeled "yes" and "no"

Validation behaviour

  • All violations are collected in one pass and surfaced in a single error message. You fix everything in one round-trip, not one rule per round.
  • Empty condition: {} is treated as absent (not an error) — only non-empty condition objects count.
  • The server enforces the same rules at the API. Validation runs on both draft create and draft update, so pre-v1.2 agents surface the issue at the entry point.

A failed validation looks like this:

{
"code": "invalid_workflow",
"message": "2 workflow validation errors:\n 1. agent_invocation node `invoke` is missing `config.agent_id`...\n 2. edge `e3` from router `route` to `h` is missing a non-empty `label`...",
"hint": "Fix each item above and re-run."
}

--workflow @file.json

Many commands accept --workflow @<path> to pull the workflow from a file. Useful for shelling out to a Python builder or hand-editing JSON.

Terminal window
athena agent update email-drafter --workflow @./workflow.json

- reads from stdin:

Terminal window
cat workflow.json | athena agent update email-drafter --workflow @-

Discoverability

Terminal window
athena agent create --schema | jq '.args[] | select(.name=="from-spec")'

The schema dump documents every flag’s type, default, and required-ness without parsing --help output.

Workflow patterns

  • Linear DAG — trigger → step1 → step2 → … No router, no conditions.
  • Fan-out — multiple unconditional edges from the same source.
  • Fan-in — multiple edges into the same target.
  • Conditional routing — requires a router node (Rule A).
  • Loop with cap — set loop_guard + cap + over_cap_target on the edge that closes the loop.
  • Variable propagationlogic nodes with set_variables.
  • Chained AI nodes — sequential edges between ai nodes; later prompts reference earlier outputs via {{ output.<node>.text }}.

See the agent builder UI for visual confirmation that your workflow matches your mental model before publishing.