DAG Execution Model¶
Every wf workflow is a Directed Acyclic Graph (DAG). Each task is a node; each depends_on entry is a directed edge from that task to its prerequisite.
How the DAG is Built¶
- Parse — the TOML file is read into a
WorkflowDefinition - Validate — duplicate task IDs, self-references, and unknown dependency targets are rejected
- Cycle detection — Kahn's algorithm detects cycles; a workflow with a cycle is rejected at parse time with a clear error message
- Topological sort — tasks are assigned to levels (0, 1, 2, …) where level 0 has no dependencies and every higher level only depends on lower levels
Topological Levels¶
Level 0: [lint]
Level 1: [test-unit] [test-integration] ← both depend only on lint
Level 2: [build]
Level 3: [deploy]
Tasks within the same level are independent of each other — they can always run in parallel. Tasks at a higher level only start after all tasks at the level they depend on have completed successfully.
Task States¶
Every node in the DAG moves through a state machine:
pending → ready → running → success
→ failed (non-zero exit / dependency failed)
→ skipped (if condition evaluated false)
| State | Meaning |
|---|---|
pending | Waiting for dependencies to complete |
ready | All dependencies succeeded; eligible to run |
running | Currently executing |
success | Exited with code 0 (or ignore_failure = true) |
failed | Exited with non-zero code, or a dependency failed |
skipped | The if condition evaluated to false |
Early Failure and Cancellation¶
When a task fails:
- Its direct and indirect dependants are marked
cancelled(they will not run) - Tasks at the same level that are already running continue to completion
- If the workflow has a global
on_failurehandler, it fires after the run settles - Task-level
on_failurehandlers fire immediately when their specific task fails
ignore_failure = true changes this: the task is marked success regardless of exit code, and dependants continue normally.
Cycle Detection¶
wf validate (and wf run) will reject a cycle with a detailed error:
Inspecting the DAG¶
# Print ASCII DAG to stdout (default)
wf graph my-workflow
# Write interactive HTML file (open in browser)
wf graph my-workflow --format html
# Export as Graphviz DOT
wf graph my-workflow --format dot | dot -Tsvg -o dag.svg
# Mermaid diagram
wf graph my-workflow --format mermaid
# JSON representation (machine-readable)
wf graph my-workflow --format json
Node Identity and Matrix Expansion¶
When a task has a matrix field, the builder expands it into N nodes — one per parameter combination. Each expanded node has a unique ID of the form:
For example, a task backup with matrix = {db = ["postgres", "mysql", "redis"]} produces:
Each is an independent node in the DAG with its own state, logs, and output. See Matrix Expansion for full details.