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.
# Look up the delegate's ID by slug:athena agent get drafter-delegate | jq -r '.id' # → 019f902b-db6f-7ea4-8ef2-60a8ff5747cdThen 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.
athena agent update email-drafter --workflow @./workflow.json- reads from stdin:
cat workflow.json | athena agent update email-drafter --workflow @-Discoverability
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
routernode (Rule A). - Loop with cap — set
loop_guard+cap+over_cap_targeton the edge that closes the loop. - Variable propagation —
logicnodes withset_variables. - Chained AI nodes — sequential edges between
ainodes; 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.