Multi-agent orchestration
Run many agents. Let a controller decide the order.
Some work has an order you cannot write down in advance. Set `type: controller`, declare what must be true when the run ends, and Dagu lets a model choose which agent step to run next as findings come back. Every action stays an ordinary workflow step with logs, retries, approvals, and audit history.
# code-review.yaml
type: controller
llm:
provider: anthropic
model: claude-opus-5
system: |
Get top_n.py past both reviews. When a review fails, pass its finding
to revise, then ask that same reviewer again. A revision made for one
reviewer can break the other.
steps:
- name: review_simplicity
description: Judge simplicity. Prints PASS, or FAIL with what to change.
action: harness.run
with:
provider: opencode
prompt: Read top_n.py. Print "PASS" or "FAIL: <what to change>".
- name: review_correctness
description: Judge correctness. Prints PASS, or FAIL with the bug.
action: harness.run
with:
provider: codex
prompt: Read top_n.py. Print "PASS" or "FAIL: <the bug>".
- name: revise
description: Edit top_n.py to resolve one review finding.
action: dag.run
with: { dag: revise }
tasks:
- name: simplicity_passed
description: The latest simplicity review returned PASS on the current file.
- name: correctness_passed
description: The latest correctness review returned PASS on the current file.Declare completion criteria, not step order
Every action is a real agent CLI: Claude, Codex, Gemini, OpenCode
Tasks settle as completed, skipped, or failed
Durable pauses for human answers, with no process left running
At a glance
Controller workflows vs. agent frameworks
You declare completion criteria. The run ends when no task is left open.
The model decides it is finished, or every path is drawn in advance and maintained by hand.
A waiting run exits its process and resumes on a new one.
Long waits usually mean a process to keep alive and a state store to operate.
Schedules, queues, retries, artifacts, and audit history come from the DAG run.
Rebuilt per project, or delegated to a hosted control plane.
The set of steps in the workflow file.
Whatever the tool definitions allow.
In depth
Where each tool fits
Order is the part you cannot write down
A graph can branch on an exit code. It cannot branch on what a review actually said. A controller workflow keeps the actions fixed and hands over only the ordering.
- Steps become a catalog of actions, so there is no `depends` to maintain.
- A `tasks` list declares what must be true when the run is over.
- The controller carries one agent's finding into the next agent's parameters.
The model chooses the order, never the capability
The controller picks among the steps you declared. It cannot invent a step, write its own shell command, or reach anything the file does not name, so the blast radius is the workflow definition.
- Run each agent on the host or in a container sandbox with explicit mounts and egress rules.
- Give each role its own provider and model, so no single model grades its own work.
- Move anything you come to trust into a sub-workflow and it stops being a decision.
Production controls come from the run, not a framework
A controller run is a DAG run. Schedules, queues, retries, artifacts, and audit history apply unchanged, and the limits that cap an agent's spend are engine settings rather than prompt instructions.
- `ask_user` suspends the run durably: the process exits and the worker slot is released.
- A person answers hours later and the run resumes on a fresh process.
- Turn, action-attempt, and question limits fail the run instead of spending without a bound.
Reconstruct any run afterwards
A controller has no dependency edges, so the run is presented as the sequence of decisions it actually made rather than as a graph.
- A decision timeline: one row per turn, with attempt counts, durations, and the child run each action produced.
- A task view showing why the controller settled each goal as completed, skipped, or failed.
- The full transcript, including every tool result the model saw.
FAQ
Practical questions before adopting Dagu
How is a controller workflow different from an agent loop?
A bare loop lets the model decide when it is finished. A controller keeps the loop but takes the termination condition back: you declare the tasks and what done means, and the run ends when no task is open.
What happens when a task turns out to be unnecessary?
The controller marks it skipped and records why, and the run still succeeds. Skipped and failed are separate states because 'there was nothing to do' and 'this could not be done' are different outcomes in an audit log.
Can different steps use different models?
Yes. Each Agent Harness step names its own provider and model, and the controller's own model is configured separately, so a cheap model can drive expensive specialists or two providers can check each other.
How do I stop a run from spending without a bound?
Limits are enforced by the engine. An action runs at most five times per run, a run asks at most five questions, and the turn limit defaults to fifty and can be lowered. Hitting a limit fails the run and names what was left open.
When should I still use a plain graph?
If you can draw the graph, draw the graph. `type: graph` stays the default because it is faster, cheaper, and reproducible. Reach for a controller only when the order genuinely depends on what earlier steps produced.
Next step
Start with one workflow.
Install Dagu, move one fragile script or agent task into YAML, and decide from a real run history.