When to use execution graphs
Execution graphs are the right tool when your workflow has multiple steps that need to coordinate:- Research pipelines — search for information, analyze results, write a summary (sequential chain)
- Fan-out/fan-in — analyze 5 repositories in parallel, then synthesize findings into a single report
- Adversarial debate — have bull and bear analysts argue before a synthesizer makes a final call (
debatenode type) - Consensus voting — have multiple agents vote independently in parallel (
votenode type) - Editorial refinement — draft, review, and polish through sequential agents (
refinenode type) - Human-in-the-loop — pause for user approval before executing a high-stakes action (
approval-gatenode type) - Budget-controlled batch processing — process multiple items with a total cost ceiling
Quick example
Here is a 3-node graph that researches a topic, analyzes the findings, and writes a report:research node runs first (no dependencies). When it finishes, analyze starts with the research output injected into its task text via {{research.result}}. Finally, write produces the report.
Key concepts
Nodes
Each node represents a sub-agent task. A graph can have between 1 and 20 nodes. Every node requires anode_id (unique within the graph) and a task (the instruction for the sub-agent).
Optional node settings:
Node types
By default, each node spawns a single sub-agent to execute its task. For multi-agent orchestration patterns, settype_id and type_config to use a built-in node type:
See Node Types for configuration details and examples.
Dependencies
Nodes declare their dependencies usingdepends_on arrays. The graph coordinator validates the dependency structure at define time — it detects cycles, missing references, duplicate node IDs, and self-dependencies. Nodes with no dependencies are root nodes and start immediately.
Barrier modes
Barrier modes control when a fan-in node (a node with multiple dependencies) should proceed:Failure policies
The graph-levelon_failure setting controls what happens when a node fails:
Data flow
Nodes consume outputs from upstream nodes using{{nodeId.result}} templates directly in the task text. The nodeId in the template must appear in the consuming node’s depends_on array.
analyze completes, its output text replaces {{analyze.result}} in the summarize node’s task description.
User-provided variables: Use ${VARIABLE_NAME} syntax for values the user provides before execution. Variables are resolved at graph.execute time via the variables parameter. See the Developer Guide for details.
Shared data folder
Each graph execution gets a temporary shared directory at~/.comis/graph-runs/{graphId}/. All nodes in the graph can read and write files in this folder, making it useful for exchanging large payloads (reports, data files, images) that do not fit in text-based template passing. The folder persists after graph completion so output files remain accessible.
Budget and timeouts
Graphs support resource limits at both the node and graph level:- Per-node timeout (
timeout_mson the node) — kills the node’s sub-agent if it runs too long - Graph-level timeout (
timeout_mson the graph) — cancels all remaining nodes if the entire graph exceeds the time limit - Budget limits (
budget.max_tokens,budget.max_cost) — cancels the graph if cumulative token usage or cost across all nodes exceeds the limit
Token budgets
There are two distinct token guardrails, and they apply at different scopes:- Per-node token budget — a
tokenBudgetcap on a single node’s sub-agent. It is enforced two ways: as a live mid-run hard stop (the sub-agent’s tool calls are blocked once it has spent its cap) and as a post-completion accounting check. A node that exceeds its budget fails — it is not retried, even whenretriesis set, because a retry would re-burn the budget. The graph’son_failurepolicy then decides the cascade: underfail-fastthe failure aborts downstream dependents, undercontinuesiblings whose barrier is still satisfiable keep running. - Cumulative graph budget (
budget.max_tokens/budget.max_cost) — bounds the total spend summed across every node, and cancels the whole graph when the total is exceeded.
- The node’s own
tokenBudget, when set. - The operator default
security.agentToAgent.tokenBudget(a positive integer applies the same cap to every node; see Configuration). - The inherited graph share —
budget.max_tokensdivided by the total node count — but only when the graph sets a token budget. The share is floored at 1 token, so an under-provisioned budget (max_tokenssmaller than the node count) yields a tight-but-usable per-node cap rather than a 0 cap that would brick every node. - Otherwise unbounded — a graph with no budget set anywhere behaves exactly as before.
The per-node
tokenBudget field is present on the graph node schema and is honored by the coordinator. Today it is reached through the operator default and the inherited graph share (above); a dedicated per-node authoring key on the pipeline tool is a planned follow-up. To bound an individual node now, set a graph budget.max_tokens (each node inherits its share) or the operator default.The per-node
tokenBudget (and the operator default / inherited share that feed it) applies to regular graph nodes. Driver-typed nodes (a node with a typeId, e.g. a debate or iterate driver that spawns multiple sub-agent rounds) are not bounded by the per-node token budget today — they are governed instead by the cumulative graph budget (budget.max_tokens / budget.max_cost), which sums every driver round’s spend and cancels the graph when the total is exceeded. Per-node budgeting for driver nodes (a cumulative-across-rounds cap with a mid-round hard stop) is a planned follow-up; to bound a driver node today, set the cumulative graph budget.Graph lifecycle
Every graph follows the same lifecycle:- Define — validate the graph structure (DAG check, dependency resolution) without executing
- Execute — start the graph; root nodes run immediately, others wait for dependencies
- Monitor — check status of running and completed nodes
- Complete or cancel — the graph reaches a terminal state when all nodes finish, or it can be manually cancelled
pending -> ready -> running -> completed / failed / skipped
Graph status values: running, completed, failed, cancelled
Worked example: four-analyst NVDA research team
A common request: “Have four analysts research NVDA in parallel, then have a trader read every analysis and give a final verdict.” This is a classic fan-out / fan-in pattern. Here is the complete graph:barrier_mode: all), the verdict node fires with their
outputs templated into its task.
If you set barrier_mode: majority on verdict, it would fire when any
three of the four analysts succeed — useful when you want resilience to a
single flaky tool. With best-effort, it fires as long as one succeeds.
The graph-level on_failure: continue means a single analyst failing does
not cancel the others — the verdict node decides what to do with whichever
analyses completed.
You can build this same graph in the Visual Builder
by dragging four nodes, connecting them all to a fifth node, and pasting the
task templates.
The pipeline tool
Agents create and manage execution graphs using thepipeline built-in tool. It supports 10 actions: define, execute, status, outputs, cancel, save, load, list, delete, and from_intent (the one-line-intent synthesizer, on by default).
See the Pipeline Tool Guide for the complete action reference with examples.
Visual builder
The web dashboard includes a visual graph builder where you can design execution graphs by dragging and connecting nodes, then save and execute them directly. See the Visual Builder Guide for details.Configuration
Execution graphs require agent-to-agent communication to be enabled:pipeline tool will not be available to agents.
See Configuration Reference for all security settings.
Small-model authoring
Frontier models write valid execution graphs directly. Weaker models sometimes emit a graph that is almost right — the correct shape but a schema slip — or would benefit from describing the workflow in one line rather than hand-writing every node. The small-model authoring layer helps them, and it is on by default (full capability out of the box): every flag underorchestration.authoring defaults to true, so the authoring aids below are available without operator action. An operator sets a flag false to opt it out (e.g. if obs.fleet.health telemetry from the pipeline:authored event shows an aid is not helping).
Governance is preserved end to end. None of the paths below execute a graph directly: the repair producer and the intent synthesizer return a graph, which is then dispatched through the same graph.execute path a hand-authored graph takes. A synthesized or repaired graph runs the identical validation, tool denylist, and child⊆parent sandbox-intersection checks as one you wrote by hand. The authoring layer can never produce a graph that bypasses governance.
Conservative repair
When a weak-tier model emits a schema-invalid graph andorchestration.authoring.repairProducer is on, the daemon attempts a deterministic, conservative match of the raw graph to one of the four canonical templates (research-fanout, debate, vote, map-reduce) by shape — node count, the fan-in topology, and disambiguating keywords. It repairs the graph only on a single unambiguous match; it never guesses. If the shape fits more than one template, the daemon returns a structured “did you mean this template?” response rather than synthesizing a graph the model did not intend. A no-match (or a repaired graph that still fails validation) returns the unchanged fail-closed validation error. The calling model’s tier is resolved server-side from the authoring agent — a tool-supplied capabilityClass is never trusted — and only weak tiers take the repair path (frontier authoring is left untouched). A successful repair emits the graph:repaired audit event (counts/ids only).
Synthesis from a one-line intent
Whenorchestration.authoring.intentAction is on, the pipeline tool exposes a from_intent action: instead of hand-writing the node list, an agent expresses a one-line intent — a canonical pattern plus a few agent or task names — and the daemon deterministically expands it into a validated graph. For example, the bull-vs-bear debate above is authorable from one line:
pattern to its canonical template, fills the agent/task slots, and runs the same parse + validation a hand-authored graph runs before dispatching through graph.execute. An invalid intent (for example debate with fewer than two agents) is rejected before any graph runs; gated off, the daemon refuses the from_intent call entirely. A governed synthesis emits the graph:synthesized_from_intent audit event. See Pipelines: from_intent for the full pattern reference.
from_intent produces template-shaped graphs — plain agent nodes in the named fan-out → fan-in shape — not the typed orchestration drivers. A synthesized debate is a one-shot pro/con fan-in into a moderator, not the multi-round type_id: debate driver; for the typed multi-round drivers (with type_config.rounds / synthesizer), author the graph with define/execute and per-node type_id + type_config. Accordingly, from_intent takes no rounds parameter.
Grammar-constrained schema (best-effort)
Whenorchestration.authoring.gbnfConstrain is on, the daemon grammar-constrains the raw pipeline tool schema for GBNF-eligible local providers (the local/default family — never a cloud provider inferred by name), nudging a local model toward emitting structurally-valid graph JSON. This is best-effort and removal/relaxation-only: it never widens field value validation, and the daemon-side schema validation remains the single source of truth for what a graph may contain. GBNF makes a valid emission more likely; it does not replace — and cannot weaken — the daemon’s governance.
Events
The graph coordinator emits three lifecycle events during execution, plus two audit events for the (default-on) small-model authoring layer:
Both authoring events are counts/ids/enums only — never a graph body, a node config value, a task/label string, or the intent text — and fire only after the graph passes the same validation a hand-authored graph runs. See Event Bus for the full event reference.
Related
Pipeline Tool Guide
Complete reference for the pipeline tool’s 10 actions
Visual Builder
Design and run graphs from the web dashboard
Developer API
API reference for building graph integrations
Sub-Agent Sessions
How each graph node runs as a sub-agent
