Skip to main content
A dagraph workflow lives in a single YAML file. The file declares a set of named nodes, their dependencies, and the inputs they accept. When you run the file, dagraph validates the structure, resolves all dependency edges, and executes nodes in parallel waves — running every node whose dependencies have already completed.

Top-level structure

A minimal DAG file needs only a name and a nodes list. Every other top-level field is optional and adds progressively more behaviour.
name: research
description: Parallel three-angle research on a topic, synthesized by Opus.

inputs:
  topic:
    type: string
    required: true
    description: The topic to research.

budget:
  max_tokens: 50000
  max_usd: 2.00

nodes:
  - id: research_a
    type: agent
    model: claude-haiku-4-5-20251001
    prompt: Research "{{ topic }}" from a technical perspective.

  - id: synthesizer
    type: agent
    model: claude-sonnet-4-6
    depends_on: [research_a]
    prompt: |
      Synthesize the findings:
      {{ research_a }}

outputs:
  report.md: synthesizer

hooks:
  on_dag_complete:
    - type: command
      command: echo "Done"

Fields reference

name
string
required
The identifier for this workflow. Used in run logs and trace spans. Must be unique across your workflow library.
description
string
A human-readable summary of what the workflow does. Shown by agentgraph validate and in run listings.
nodes
list
required
The ordered list of node specifications. Node execution order is determined by dependency edges, not list order. See Node types for all available types and their fields.
The inputs map declares the parameters your workflow accepts from the CLI or a webhook call. Each key is the input name; the value is a schema object.
inputs.<name>.type
string
One of string, integer, number, or boolean. Defaults to string. dagraph coerces the raw CLI string to this type before the first node runs, so a typo like --input count=three fails immediately with a clear error.
inputs.<name>.required
boolean
Whether the input must be provided. Defaults to true. Set to false and provide a default for optional parameters.
inputs.<name>.default
string | integer | number | boolean
Default value used when the input is absent and required: false.
inputs.<name>.description
string
Documents the parameter. Displayed by agentgraph validate to self-document the DAG.
inputs:
  topic:
    type: string
    required: true
    description: The subject to research.
  depth:
    type: integer
    required: false
    default: 3
    description: How many research angles to spawn.
Pass inputs at run time:
agentgraph run research.yaml --input topic="quantum computing" --input depth=5
The budget block sets a hard upper limit on the entire run. If either limit is reached, dagraph stops all in-flight nodes immediately and marks the run as failed.
budget.max_tokens
integer
Maximum number of billable tokens (input + output) across all nodes. Cache-creation overhead from the claude_code backend is excluded.
budget.max_usd
float
Maximum equivalent API cost in US dollars. Useful when mixing models with different per-token prices.
budget:
  max_tokens: 100000
  max_usd: 5.00
You can also set a per-node budget on any individual node using the same budget: field. See Node types for details.
The outputs map writes the text output of specific nodes to files on disk after a successful run. Nothing is written for paused or failed runs.
outputs.<file-path>
string
Maps an output file path (relative to the working directory) to a node ID. The node’s text output is written to that path when the run completes successfully. Parent directories are created automatically.
outputs:
  report.md: synthesizer
  data/analysis.txt: analysis_node
The hooks map attaches callbacks to DAG lifecycle events. Hook failures never fail the DAG itself.
hooks.<event>
list
Supported events: on_dag_start, on_dag_complete, on_dag_paused, on_dag_failed. Each value is a list of hook specifications — either a webhook (JSON POST) or a shell command.
hooks:
  on_dag_complete:
    - type: webhook
      url: https://hooks.example.com/notify
  on_dag_failed:
    - type: command
      command: "echo 'Run {{ run_id }} failed' >> /var/log/dagraph.log"

Template variables

dagraph uses Jinja2 to render prompts and commands at run time. Two scopes of variables are available inside any prompt or command string.

Input variables

Reference any declared input by name:
inputs:
  topic:
    type: string

nodes:
  - id: researcher
    type: agent
    model: claude-haiku-4-5-20251001
    prompt: Research the topic "{{ topic }}" and return 5 bullet points.

Upstream node outputs

Reference the text output of any completed upstream node by its id:
nodes:
  - id: research_a
    type: agent
    model: claude-haiku-4-5-20251001
    prompt: Research "{{ topic }}" technically.

  - id: synthesizer
    type: agent
    model: claude-sonnet-4-6
    depends_on: [research_a]
    prompt: |
      Synthesize these findings:

      {{ research_a }}
When a node’s output is a JSON array (such as from a map node), you can iterate over it:
prompt: |
  {% for item in summaries | fromjson %}
  - {{ item }}
  {% endfor %}
dagraph’s Jinja environment uses StrictUndefined, so a typo in a variable name will fail the node immediately with a clear error message rather than silently inserting an empty string.

Externalising prompts with prompt_file and system_file

Long prompts are easier to read, review, and diff when stored in separate text files. Use prompt_file instead of prompt, and system_file instead of system. Paths resolve relative to the directory containing the YAML file.
nodes:
  - id: analyst
    type: agent
    model: claude-sonnet-4-6
    prompt_file: prompts/analyst.txt
    system_file: prompts/analyst-system.txt
You cannot set both prompt and prompt_file on the same node — dagraph will reject the file at validation time.

Complete annotated example

The following example is taken from the dagraph examples directory. It defines three parallel research agents followed by a synthesizer that fans in their outputs.
name: research
description: Parallel three-angle research on a topic, synthesized by Opus.

budget:
  max_tokens: 50000
  max_usd: 2.00

nodes:
  # Three independent researchers — no depends_on, so they run in parallel.
  - id: research_a
    type: agent
    model: claude-haiku-4-5-20251001
    max_output_tokens: 1500
    prompt: |
      Research the topic "{{ topic }}" from a TECHNICAL perspective.
      Cover: mechanisms, architecture, implementation details.
      Return 5–8 concise bullet points. No fluff.

  - id: research_b
    type: agent
    model: claude-haiku-4-5-20251001
    max_output_tokens: 1500
    prompt: |
      Research the topic "{{ topic }}" from an ECONOMIC perspective.
      Cover: market forces, cost structures, winners, losers.
      Return 5–8 concise bullet points. No fluff.

  - id: research_c
    type: agent
    model: claude-haiku-4-5-20251001
    max_output_tokens: 1500
    prompt: |
      Research the topic "{{ topic }}" from a HUMAN/SOCIAL perspective.
      Cover: behavior, adoption, second-order effects on people.
      Return 5–8 concise bullet points. No fluff.

  # Synthesizer waits for all three researchers before running.
  - id: synthesizer
    type: agent
    model: claude-sonnet-4-6
    max_output_tokens: 3000
    depends_on: [research_a, research_b, research_c]
    prompt: |
      Three independent researchers analyzed "{{ topic }}". Synthesize
      their findings into a unified report.

      == Technical perspective ==
      {{ research_a }}

      == Economic perspective ==
      {{ research_b }}

      == Human/Social perspective ==
      {{ research_c }}

outputs:
  report.md: synthesizer
Run it with:
agentgraph run research.yaml --input topic="quantum computing"