Workflows
Graph Engineering for AI Agents: How to Set It Up with Skills
Agent loops hide the decisions that matter: what runs, what waits, which evidence counts, and what happens after a failure. Graph engineering makes them inspectable, and this guide ships eight reusable Skill templates for the core topologies.
By Brandon W. Lee · Published · Updated
The agent loop is a good runtime and a bad operating model.
Observe the environment, decide the next action, use a tool, inspect the result, repeat. ReAct made that cycle explicit enough to study, and modern coding agents turned it into a practical interface for reading files, editing code, running tests, and recovering from errors. It works. It is also where most teams stop.
The problem starts when the entire workflow hides inside the loop.
One agent loop makes scheduling, dependency, context, and recovery decisions inside the same expanding transcript. The agent decides what runs, what waits, which evidence matters, when to retry, when to replan, and when to stop. For a small task, that is fine. For work a team has to review, the hidden control flow becomes an operational risk.
Ask an agent to audit eighteen route files for auth gaps and it will hand back a report. The report may be correct. The run is not reviewable. Nobody can see which files it actually opened, whether the third one timed out and got quietly dropped, whether an ordering choice was a real dependency or just a sentence that said "then," or whether the final summary inherited a claim no verifier ever checked.
Graph engineering is the discipline of turning that hidden control flow into an execution system the team can inspect. The graph is not a diagram for the slide deck. It is the runtime contract:
- Nodes perform bounded work.
- Edges carry actual data or control dependencies.
- A scheduler dispatches nodes whose dependencies are satisfied.
- State and contracts govern what crosses node boundaries.
- Gates, verifiers, recovery policies, and convergence rules decide whether results can move downstream.
- A trace records what ran, what failed, what was skipped, what was retried, and which evidence justified the final output.
The payoff is not "more agents." More calls add cost, latency, parsing failures, and correlated mistakes. The payoff is explicit structure around agent judgment. Independent work runs concurrently. Context stays local. A failure is contained to the smallest affected node. Verification sits at the boundaries where a bad output is expensive. Cost and latency come from a topology the team chose, not from a number discovered on the invoice.
The simplest adequate graph should win. A linear chain is already a graph, and it is often the right graph for a small task with real serial dependencies.
Which Graph This Is
"Graph" is an overloaded word in this space. The subject here is the agent execution, control, and dataflow graph.
Several adjacent things also get called graphs:
- A knowledge graph represents entities and relationships in a domain.
- GraphRAG uses graph structure to organize retrieval over knowledge.
- An internal reasoning graph represents intermediate reasoning paths or thoughts.
- A multi-agent communication graph represents which agents can talk to which other agents.
Those graphs can interact with an execution graph, but they are not the same thing. In graph engineering for agents, the primary object is the workflow that runs: nodes, edges, state, contracts, scheduling, joins, gates, loops, recovery, and trace.
Frameworks are implementation options, not the definition. Claude dynamic workflows, LangGraph, the OpenAI Agents SDK, Semantic Kernel, CrewAI flows, Airflow-style DAGs, and custom code can all express parts of this pattern. The engineering discipline is deciding what should be a node, what should be an edge, which work is ready, what context moves, what code validates, where LLM judgment belongs, and how the system proves it is done.
The Graph Is The Control Plane
AI Systems Engineering starts from one operating assumption: the model is a runtime component, and performance depends on the system around it.
For agent workflows, that system includes identity, routing, stage contracts, references, working artifacts, review gates, verification evidence, and operational memory. Geist Labs calls it Agent Context Architecture. A graph is where that architecture stops being a folder convention and starts being executable.
- Identity defines the mission, standards, risk posture, and operating rules.
- Routing decides which context each node receives.
- Stage contracts define node inputs, process, outputs, and proof.
- References supply stable standards and examples.
- Working artifacts preserve plans, intermediate outputs, traces, and review notes.
- Review gates decide whether high-impact results can move forward.
- Operational memory stores reusable graph plans, node contracts, and failure patterns.
The agent is still the runtime. The graph is the control plane.
Route minimum sufficient context along explicit edges. Do not broadcast the whole history to every worker. If a security reviewer needs the diff, the threat model, and one changed route file, sending it the entire repository transcript is waste, and waste is the smaller problem. The extra material is failure surface: irrelevant instructions the node might follow, stale assumptions it might inherit, and tool output that pulls it away from the contract it was given.
Graph plans, node contracts, traces, and verification artifacts should be inspectable, versionable, and reusable. A team should be able to review a plan before execution, compare plan versions after a replan, read the trace after a failure, and fix the source contract instead of patching every future prompt by hand.
Draw The Real Dependencies First
"Then" is not an edge. If a step does not consume the prior step's output, the edge is artificial, and artificial sequencing costs you latency, context coupling, and a blast radius that grows every time an upstream step fails and blocks work that never needed it.
So start by drawing what actually depends on what. The vocabulary for that drawing is small.
- Node: one bounded job.
- Edge: the data or control condition that allows one node to affect another.
- State: the durable object that stores node status, inputs, outputs, errors, and checkpoints.
- Contract: the schema and behavioral rule for a node's input and output.
- Ready set: nodes whose dependencies are satisfied and whose policies allow dispatch.
- Scheduler: the runtime that dispatches ready work, usually with concurrency and rate limits.
- Join: a rule for when downstream nodes can run, such as all predecessors complete or one alternative succeeds.
- Gate: a validation or review boundary.
- Termination: the condition that ends a node, loop, subgraph, or run.
- Trace: the ordered record of plan version, state transitions, outputs, validation evidence, recovery actions, and final disposition.
Each node should have one job, bounded input, structured output, allowed tools, side-effect level, timeout, retry budget, and verifier. Each edge should declare what data moves and the condition for traversal.
That contract lets the runtime keep deterministic plumbing out of the model. Use code for routing on validated labels, schema checks, flattening, filtering, deduplication, merge/reduce logic, rate limiting, cancellation policy, and checkpoint persistence. Reserve LLM calls for interpretation, decomposition, prioritization, adjudication, synthesis, and other work where judgment matters.
Execution then follows a repeating cycle:
- Validate the graph plan before execution.
- Compute the ready set from node states and dependencies.
- Dispatch ready nodes within concurrency and side-effect constraints.
- Validate each node output against its contract.
- Run deterministic edge operations.
- Apply join rules and update downstream readiness.
- Trigger local recovery when a node fails.
- Create a new plan version only when local recovery cannot repair the affected graph.
- Stop when the graph output contract passes, a gate blocks, or a budget expires.
The Structured Graph Harness paper frames all of this as a scheduler problem. A single agent loop has at most one ready unit at any moment. A graph runtime can have several, whenever the dependencies permit it. The framing is useful, and so is the vocabulary it supplies for ready sets, immutable plan versions, bounded recovery, and join semantics. Its predictions are another matter. It is a position and design document with no completed empirical validation, so treat what it forecasts as a hypothesis until someone measures a working implementation against real task sets.
What The Structure Actually Buys
Seven things change once the control flow is explicit.
The scheduler runs independent work at the same time. If four modules can be reviewed without reading each other's output, four bounded reviewers dispatch together, and the graph waits only where downstream logic needs the complete set. The gain comes from deleting ordering that was never real.
Each node gets a smaller window to be wrong in. Predecessor outputs and local traces are routed to the node that needs them instead of poured into one global transcript. Task-Decoupled Planning reports that node-scoped context reduced token consumption across several long-horizon benchmarks. Treat that as bounded to its tasks, models, and implementation. The durable part is the mechanism, not the percentage.
Verification stops being an instruction and becomes a node. A graph can put a schema check, a test command, a source-evidence check, an adversarial reviewer, or a human gate on the edge before synthesis. "Double-check your work" is a suggestion. A gate with its own contract is a control.
Recovery stays where the failure happened. A failed extractor in a fan-out should not poison the sibling outputs that succeeded. A local retry should not rewrite the plan. A missing dependency should produce a new plan version instead of a silent edit to the graph that is currently running.
A reviewer gets artifacts instead of a summary. The run leaves a graph plan, node contracts, state transitions, verifier output, recovery actions, and final evidence. Someone can now ask what governed the run, not only what the model said at the end.
Nodes can run on different model tiers. Bounded extraction, classification, formatting, and deduplication do not need the tier that synthesis and adjudication need. The graph makes that choice explicit and reviewable instead of leaving it as one model setting for the whole task.
Cost and latency become topology questions. A barrier waits for the slowest branch. A pipeline streams items forward as they finish. A verifier panel adds calls. A spurious edge lengthens the critical path, and a missing one makes downstream work invalid. Topology does not guarantee a cheaper run. It gives the team something to reason about before the run and something to measure after it.
A Field Guide To Agent Graph Categories
Anthropic's agent pattern catalog names several useful workflows: prompt chaining, routing, parallelization, orchestrator-workers, and evaluator-optimizer. Those names are a good starting vocabulary. What they do not give you is the part a team argues about at review time: which edges are real, what each node owes the next one, and what has to be true before the work moves forward.
The eight categories below add that layer. Each one names a topology, where it fits, how it fails, the node and edge contract, the verification method, and the stop condition. Each ends with a reusable Skill template you can paste into Claude Code, Codex, or any coding agent and adapt.
Treat those as Skills rather than one-off prompts. A Skill carries a trigger that says when to reach for it, a bounded procedure the agent runs the same way every time, and an output contract a reviewer can check. Keep them in the repository next to the work they serve, and the topology stops being something every engineer rediscovers in chat.
Read them as a parts bin, not a ranking. Most production workflows end up as hybrids, and that is fine as long as the hybrid is assembled from small shapes a reviewer can still recognize.
Category 1: Dependency Chain Or Prompt Chain
Topology sketch:
A -> B -> C
Best fit: fixed transformations with real serial dependencies. Use it when each step consumes the prior output, such as outline -> draft -> edit, parse -> normalize -> validate, or plan -> implementation -> test summary.
Anti-pattern: fake sequencing. If B does not read A, the edge adds latency and fragility. A linear chain with unrelated steps is just a queue.
Node and edge contract:
- Each node has one transformation.
- Each output is structured enough for the next node to consume.
- Each edge names the exact payload, not just execution order.
- Gates can sit between nodes when intermediate quality matters.
Verification method: schema validation after each node, deterministic checks where possible, and a downstream consistency check that confirms each node actually used its predecessor output.
Stop condition: C satisfies the graph output contract, or a gate fails and returns a bounded revision request.
Reusable Skill template:
You are designing a dependency-chain graph for this task.
Task:
<describe the task>
Required serial dependency:
<explain why each step must consume the previous output>
Create a graph with this topology:
A -> B -> C
For each node, provide:
- node_id
- one job
- input payload
- output schema
- allowed tools
- side-effect class
- verifier
- timeout/retry budget
Rules:
- Do not add an edge unless the downstream node consumes the upstream output.
- Put deterministic formatting, validation, and parsing in code.
- Add a gate after any node whose output can make downstream work invalid.
- Stop when the final output satisfies the graph contract.
Return:
- graph plan
- edge payloads
- verification plan
- expected trace fields
Category 2: Conditional Router
Topology sketch:
Classifier/router -> one specialized branch -> merge/response
Best fit: inputs that belong to distinct categories with different handlers, risk levels, model tiers, permissions, or review paths. The router may use model judgment when the classification requires interpretation, but branch selection should be deterministic code against validated labels.
Anti-pattern: letting the model freely choose tools or skip branches after classification. The router node can judge. The edge should route.
Node and edge contract:
- Router output uses a closed label set.
- Each label maps to one allowed branch in code.
- Confidence is required.
- Low confidence triggers escalation, human review, or a conservative default.
- Each branch receives only the context needed for that category.
Verification method: validate the label, confidence, and rationale against the schema, test representative inputs for each label, audit the low-confidence and misrouted cases by hand, and watch the branch distribution over time. A router that suddenly sends 80% of traffic down one branch has usually stopped classifying.
Stop condition: one branch completes and the merge/response node satisfies the output contract, or routing confidence falls below threshold and escalates.
Reusable Skill template:
You are designing a conditional-router graph.
Input:
<describe the input>
Allowed labels:
- <label_1>: <handler>
- <label_2>: <handler>
- <label_3>: <handler>
Confidence threshold:
<number or rule>
Create this topology:
Router -> selected branch -> response
Router contract:
- Return exactly one label from the allowed labels.
- Return confidence from 0.0 to 1.0.
- Return evidence from the input that supports the label.
- Return "escalate" when confidence is below threshold or labels do not fit.
Routing rules:
- Use deterministic code to select the branch from the validated label.
- Do not let the branch override the router decision.
- Send each branch only the minimum context required for its handler.
Verification:
- Validate the label against the allowed set.
- Check threshold before dispatch.
- Log routed label, confidence, branch, and escalation reason.
Return:
- graph plan
- router schema
- branch contracts
- fallback/escalation path
Category 3: Fan-Out/Fan-In Diamond
Topology sketch:
Scope/split -> parallel workers -> deterministic reduce -> synthesis
Best fit: sources, files, modules, routes, datasets, customers, issues, or independent perspectives. Use it when the split units can be processed without reading each other's outputs.
Anti-pattern: adding a barrier because it looks tidy. Synchronize only when downstream logic needs the full set, such as global deduplication, ranking, cross-source contradiction checks, or final synthesis. If each item can move independently to the next stage, use a streaming pipeline. The tell is a barrier followed immediately by a flatten, a map, or a filter. If the code after the join only reshapes data, the join was there for the diagram, and every fast worker sat idle waiting for the slowest one.
Node and edge contract:
- Scope node produces a bounded worklist.
- Worker nodes receive one item and shared minimal instructions.
- Workers return structured item-level outputs.
- Reduce runs in deterministic code: flatten, filter, dedupe, sort, group, count.
- Synthesis receives the reduced set, not every raw transcript.
Verification method: validate worker output schemas, dedupe by stable keys, sample worker results against the source evidence they cite, and run a final source-evidence check on anything synthesis claims.
Stop condition: all required workers finish or hit their timeout, reduce tolerates the missing results according to a stated policy, and synthesis passes the evidence gate.
Reusable Skill template:
You are designing a fan-out/fan-in graph.
Objective:
<describe the output>
Split units:
<sources/files/modules/items to process independently>
Create this topology:
Scope -> Worker[*] in parallel -> Reduce in code -> Synthesis
Scope node:
- Produce a worklist with stable IDs.
- Exclude items outside scope.
- State the concurrency limit.
Worker node contract:
- Input: one work item plus minimum shared context.
- Job: inspect only this item.
- Output schema: <define fields>
- Evidence: include source path, line, URL, command output, or artifact ID.
- Side effects: read-only unless explicitly allowed.
Reduce edge:
- Implement flatten/filter/dedupe/sort/group in deterministic code.
- Do not use an LLM for mechanical merge logic.
- Decide whether the graph uses a full barrier or streaming pipeline and explain why.
Synthesis node:
- Consume only reduced outputs and evidence.
- Preserve uncertainty and missing-worker notes.
Return:
- graph plan
- worker schema
- reduce logic
- barrier or streaming decision
- verification and stop condition
Category 4: Parallel Voting, Adversarial Verification, Or Judge Panel
Topology sketch:
independent attempts/lenses -> evidence check -> vote/judge -> synthesis
Best fit: high-stakes claims, false-positive-sensitive review, security analysis, correctness review, migration plans, incident hypotheses, or domains where one agent's blind spot is expensive.
Anti-pattern: running the same prompt several times and calling it independent evidence. Three copies of the same reviewer agreeing is one opinion with a bigger bill, and they share every blind spot the original had. Independence has to come from somewhere real: a different lens, a different evidence path, a different prompt, a different model tier, or a different verification method.
Node and edge contract:
- Each worker receives a distinct lens or attempt strategy.
- Each output includes evidence and confidence.
- The evidence check rejects unsupported claims before voting.
- The judge preserves disagreement, abstentions, and minority concerns.
- The synthesis node cannot erase unresolved risk.
Verification method: source-evidence validation, deterministic tests, schema checks, independent reproduction, and a judge rubric. Add an abstain/escalate path when evidence is insufficient.
Stop condition: the judge reaches threshold with evidence, abstains and escalates, or returns a bounded follow-up plan.
Reusable Skill template:
You are designing a verifier-panel graph.
Claim or artifact to verify:
<claim, code change, plan, report, or finding>
Consequence of false positive/false negative:
<risk statement>
Create this topology:
Independent lenses -> Evidence check -> Judge -> Synthesis
Lens design:
- Lens A: <correctness/security/reproducibility/etc.>
- Lens B: <different lens>
- Lens C: <different lens>
Worker contract:
- Assess only from assigned lens.
- Cite evidence for every accepted or rejected claim.
- Return: verdict, confidence, evidence, counterevidence, uncertainty.
- Abstain when evidence is insufficient.
Judge contract:
- Check whether evidence supports each verdict.
- Preserve disagreement.
- Require threshold: <majority/unanimity/rubric score>
- Escalate if the panel lacks independent evidence.
Rules:
- Do not treat repeated identical outputs as independent evidence.
- Do not let synthesis hide unresolved disagreement.
- Use deterministic tests and schemas before LLM judgment where possible.
Return:
- panel graph plan
- lens prompts
- judge rubric
- abstain/escalation path
- final evidence requirements
Category 5: Orchestrator-Workers Or Dynamic Decomposition
Topology sketch:
Planner/orchestrator -> task-specific worker graph -> synthesis
Best fit: tasks where subtasks cannot be known before inspecting the input. Coding changes are the common example: the number of files, risk boundaries, tests, and reviewers often depend on initial discovery.
Anti-pattern: giving the orchestrator unbounded authority to spawn workers, rewrite scope, and synthesize without a recorded plan. Dynamic decomposition still needs plan validation, worker limits, scoped contexts, output schemas, and trace recording.
Node and edge contract:
- The reusable template defines how planning happens.
- The realized run graph records the actual nodes chosen for this input.
- The execution trace records what ran.
- Worker count and concurrency are bounded.
- Each worker receives only its local context.
- Write-heavy workers are isolated with worktrees, sandboxes, locks, or serial write gates.
Verification method: validate the plan before execution. Check it for missing dependencies, spurious dependencies, unsafe parallel writes, unnecessary barriers, and missing output contracts. Then verify the high-impact outputs independently.
Stop condition: synthesized output passes the graph output contract, or the orchestrator creates a new plan version with a recorded reason.
Reusable Skill template:
You are designing an orchestrator-workers graph.
Objective:
<describe the task>
Available context:
<files, sources, systems, constraints>
Create three artifacts:
1. Reusable template: the general orchestration method.
2. Realized run graph: the nodes and edges selected for this input.
3. Execution trace schema: the fields recorded during execution.
Planner/orchestrator contract:
- Inspect the input before selecting workers.
- Classify subtasks by dependency, side effect, and risk.
- Propose the smallest adequate graph.
- Enforce maximum worker count: <N>.
- Enforce concurrency limit: <N>.
- Define output schema for every worker.
- Route minimum sufficient context to each worker.
- Record why each worker exists.
Validation before dispatch:
- No missing dependencies.
- No spurious dependencies that serialize independent work.
- No cycles unless bounded convergence is defined.
- No unsafe parallel writes.
- No unnecessary barriers.
Execution:
- Dispatch ready independent workers concurrently.
- Use deterministic code for routing and merge logic.
- Verify high-impact outputs independently.
- Recover locally before replanning.
Return:
- reusable template
- realized graph plan
- execution trace
- verification evidence
- unresolved risks
Category 6: Evaluator-Optimizer Loop Inside A Graph
Topology sketch:
Generate -> evaluate against explicit rubric/tests -> revise -> exit gate
Best fit: artifacts that measurably improve with feedback, such as drafts, prompts, code patches, data transformations, test fixes, extraction schemas, or migration plans. The criteria have to be clear enough that an evaluator can say what changed and whether the next attempt is better.
Anti-pattern: looping when feedback cannot change the next attempt or progress cannot be measured. That loop repeats cost.
Node and edge contract:
- Generator returns an artifact and self-reported assumptions.
- Evaluator uses explicit rubric, tests, or checks.
- Revise node receives only the artifact, evaluation result, and relevant context.
- The loop stores best-so-far output.
- Iteration, time, and token budgets are hard limits.
- Stagnation detection exits when improvement stalls.
Verification method: rubric score deltas, deterministic tests, schema validation, human review for subjective criteria, and best-so-far comparison.
Stop condition: tests pass, rubric score crosses threshold, delta falls below threshold for K rounds, or budget expires with best-so-far preserved.
Reusable Skill template:
You are designing an evaluator-optimizer loop inside a larger graph.
Artifact:
<what is being generated or improved>
Evaluation criteria:
<rubric, tests, schema, or acceptance checks>
Create this local topology:
Generate -> Evaluate -> Revise -> Evaluate ... -> Exit gate
Loop contract:
- Max iterations: <N>
- Max time: <duration>
- Max token/cost budget: <budget>
- Improvement measure: <score, tests passed, defects removed, etc.>
- Stagnation rule: <delta threshold and rounds>
- Best-so-far preservation: always keep the strongest passing or highest-scoring artifact.
Node contracts:
- Generate: produce artifact and assumptions.
- Evaluate: score against explicit criteria and cite evidence.
- Revise: change only issues identified by evaluation unless a new blocker is found.
- Exit gate: accept, return best-so-far with caveats, or escalate.
Rules:
- Do not continue if feedback cannot change the next attempt.
- Do not silently expand scope.
- Record every iteration in the trace.
Return:
- loop plan
- rubric/test contract
- convergence rule
- best-so-far storage format
- escalation path
Category 7: Discovery-Until-Dry Or Bounded Exploration Graph
Topology sketch:
parallel finders -> dedupe against all seen -> verify -> accumulate -> repeat until K dry rounds
Best fit: unknown-size discovery, such as bug sweeps, source research, policy gap analysis, duplicate detection, migration risk discovery, security findings, or inventory work where nobody knows the number of findings at the start.
Anti-pattern: deduping only against accepted findings. Rejected findings must enter the seen set too, or workers will rediscover the same dead ends every round.
Node and edge contract:
- Finder nodes search from distinct strategies or scopes.
- Dedupe compares against every seen finding, including rejected ones.
- Verify checks fresh candidates before accumulation.
- Accumulate stores confirmed findings and full seen-state.
- Loop repeats only while fresh unique candidates continue to appear.
Verification method: stable dedupe keys, source-evidence checks, rejection reasons, independent confirmation, and dry-round tracking.
Stop condition: K consecutive dry rounds, maximum rounds, maximum budget, or a risk threshold requiring escalation.
Reusable Skill template:
You are designing a discovery-until-dry graph.
Discovery target:
<unknown-size finding class>
Finder strategies:
- <strategy A>
- <strategy B>
- <strategy C>
Create this topology:
Finders in parallel -> Dedupe all seen -> Verify fresh -> Accumulate -> Repeat
State:
- seen_all: every candidate ever found, including rejected and duplicate items.
- confirmed: verified findings.
- rejected: rejected findings with reason.
- dry_rounds: consecutive rounds with no fresh unique candidates.
Loop contract:
- Stop after <K> dry rounds.
- Hard max rounds: <N>.
- Hard budget: <time/tokens/cost>.
- Dedupe key: <stable key rule>.
Finder contract:
- Search only assigned strategy/scope.
- Return candidate, evidence, and dedupe key.
- Do not drop low-confidence candidates. Return them with a confidence label.
Verifier contract:
- Check only fresh candidates.
- Record accepted/rejected/needs-human.
- Add every candidate to seen_all before the next round.
Return:
- graph plan
- state schema
- finder prompts
- dedupe logic
- verification method
- stop condition
Category 8: Recovery And Escalation Graph For Engineering Work
Topology sketch:
Execute node -> deterministic validation -> local retry -> local config/prompt patch -> new plan version/replan -> human escalation
Best fit: engineering workflows with checkable outputs and known side effects, such as code changes, migrations, deployments, data jobs, tests, release notes, incident response, and operational automation.
Anti-pattern: blindly retrying side-effecting actions. A retry loop wrapped around an unguarded POST is how one flaky timeout becomes three charges on a customer card. Writes, deletes, payments, notifications, credential operations, production mutations, and external communications need an explicit idempotency key, a compensation path, or a human.
Node and edge contract:
- Every executable node declares side-effect class.
- Validation separates transient failure from contract failure from unsafe action.
- Local retry handles transient failures only.
- Local patch changes node configuration, prompt, input format, or tool parameters without changing graph topology.
- Replan creates a new graph version with a recorded reason.
- Human escalation records state and waits for a decision.
Verification method: deterministic validation first, side-effect audit, retry-idempotency check, plan-diff review before replan, and human gate for high-impact mutations.
Stop condition: validation passes, local recovery budget is exhausted and a new plan version is created, or human escalation blocks execution.
Reusable Skill template:
You are designing a recovery/escalation graph for engineering work.
Node or subgraph:
<what executes>
Side-effect classification:
- read_only
- local_write
- external_write
- destructive
- production_mutation
- notification/payment/credential
Create this recovery ladder:
Execute -> Validate -> Retry transient -> Patch local config -> Replan new version -> Human escalation
Validation contract:
- Use deterministic checks first: schemas, tests, static analysis, command exit codes, diff checks.
- Classify failure as transient, contract violation, missing dependency, unsafe side effect, or unknown.
- Do not retry non-idempotent side effects without an idempotency key or compensation plan.
Recovery policy:
- Local retry: current node only, max <N>.
- Local patch: prompt/tool/config/input formatting only, max <N>.
- Replan: create graph version <v+1>, record reason, preserve prior trace.
- Escalation: record blocked node, evidence, attempted recovery, and needed human decision.
Rules:
- Keep recovery local to the smallest causally affected node or subgraph.
- Do not silently mutate the current graph.
- Do not skip recovery levels unless policy explicitly marks the action unsafe.
Return:
- recovery graph
- failure taxonomy
- side-effect policy
- validation checks
- trace fields
Loops Within Graphs
Loops get their own section because they are where a graph quietly turns back into the loop it replaced.
Keep two objects separate in your head:
- The outer execution graph controls which node or subgraph runs, what context enters it, which tools are allowed, what output contract it must satisfy, and what gate decides completion.
- A node's inner agent loop performs bounded local work, such as observe -> act -> inspect, generate -> evaluate -> revise, inspect -> edit -> test -> fix, or find -> dedupe -> verify -> repeat.
The outer graph should make the loop's boundary explicit. A loop is a local execution policy inside a node or subgraph. It is not a license for the whole system to wander.
Useful local loops include:
- ReAct-style observe -> act -> inspect cycles when a node must use tools and respond to observations.
- Evaluator-optimizer cycles when criteria are explicit and feedback can improve the artifact.
- Test-fix cycles when a failing command gives actionable diagnostics.
- Discovery-until-dry cycles when the number of findings is unknown.
The graph controls entry conditions, supplied context, tools, permissions, output contract, time budget, token budget, iteration budget, checkpointing, and exit gate. The node owns the local loop state. The graph owns the boundary.
Define convergence before execution:
- Tests pass.
- Rubric score crosses a threshold.
- Rubric delta falls below a threshold for K rounds.
- No new unique findings appear for K rounds.
- The budget expires and best-so-far is returned with evidence.
Preserve best-so-far output and full seen-state. If iteration 4 breaks what iteration 2 had working, the node should not lose the stronger artifact. If discovery rejects a false lead in round 1, the seen-state should prevent round 3 from rediscovering it.
On failure, escalate in order:
- Retry transient failure.
- Patch node configuration, prompt, input format, or tool parameters.
- Create a new versioned graph plan with a recorded reason.
- Escalate to a human when the system cannot safely decide.
Do not silently mutate the current graph. A controlled replan is a new graph version, not an edit hidden inside the transcript.
Cycles are appropriate only when feedback can change the next attempt and progress can be measured. If a node runs the same prompt against the same evidence with no new signal, the loop is just a cost multiplier.
Compact topology:
Plan -> [Implement node: inspect -> edit -> test -> revise, max N] -> independent review -> release gate
Dynamic graphs are valid when the task is exploratory. Research work, incident investigation, and open-ended discovery often reveal their own structure as they run. For those tasks, do not force a static DAG to fit. Use a controlled replan that generates a new graph version, records what changed, preserves the prior trace, and revalidates dependencies before dispatch.
Universal Graph-Architect Meta-Prompt
The following template is intentionally framework-neutral. Adapt the subagent-spawn syntax, tool names, sandbox mechanism, and trace format to the coding agent or orchestration framework you use.
You are my graph architect and execution lead.
Ask me only for these inputs if they are missing:
1. Problem
2. Desired outcome
3. Constraints/context
4. Evidence of success
Problem:
<user fills this in>
Desired outcome:
<user fills this in>
Constraints/context:
<user fills this in>
Evidence of success:
<user fills this in>
Your responsibilities:
1. Decide whether a graph is warranted.
- Use a single agent or a linear chain if that is the simplest adequate design.
- Do not add agents, branches, loops, or verifiers without a stated reason.
2. Classify the task before planning.
- Fixed or exploratory.
- Read-only or side-effecting.
- Low consequence or high consequence.
- Known-size or unknown-size.
- Known dependencies or dependencies that must be discovered.
3. Select the simplest suitable category or hybrid.
Choose from:
- dependency chain / prompt chain
- conditional router
- fan-out/fan-in diamond
- parallel voting / adversarial verification / judge panel
- orchestrator-workers / dynamic decomposition
- evaluator-optimizer loop inside a graph
- discovery-until-dry / bounded exploration graph
- recovery/escalation graph
Explain the choice in 2-4 sentences.
4. Create a graph plan before execution.
For every node, define:
- node_id
- one job
- inputs
- outputs/schema
- tools
- model/capability tier
- side-effect class
- timeout/retry budget
- verifier
- dependencies
- join mode
5. Validate the graph before dispatch.
Check for:
- missing dependencies
- spurious dependencies that serialize independent work
- cycles without convergence rules
- unsafe parallel writes
- unnecessary barriers
- missing output contracts
- missing verification for high-impact outputs
6. Route minimum sufficient context.
- Do not broadcast the full history to every worker.
- Send each worker only its task, local context, relevant references, input payload, output schema, tool permissions, and verifier.
- Preserve bulky artifacts by reference when possible.
7. Dispatch ready independent nodes concurrently.
- Use an explicit concurrency limit: <state limit>.
- Isolate write-heavy workers with worktrees, sandboxes, locks, or serial write gates.
- Do not parallelize unsafe side effects without an idempotency and compensation plan.
8. Use deterministic code for edge operations.
- Routing from validated labels.
- Schema validation.
- Filtering, sorting, grouping, deduplication, and reduce logic.
- Rate limiting and retry counters.
- Trace persistence.
Reserve agent calls for interpretation, decomposition, prioritization, adjudication, and synthesis.
9. Put bounded loops inside nodes only when feedback can improve the next attempt.
For every loop, state:
- max iterations
- max time/tokens/cost
- convergence rule
- stagnation rule
- best-so-far storage
- seen-state storage
- exit gate
10. Verify high-impact outputs independently.
- Prefer tests, schemas, static analysis, source evidence, deterministic checks, and human review.
- Use LLM judges only with a rubric, evidence, disagreement preservation, and an abstain/escalate path.
11. Recover locally first.
- Retry transient failures inside the smallest affected node.
- Patch node configuration before replanning.
- Replan only by creating a new graph version.
- Record the reason for every recovery action and plan version.
12. Return the final report with:
- chosen topology
- graph plan
- execution trace
- successful, failed, skipped, retried, and blocked nodes
- verification evidence
- disagreements and unresolved risks
- resource/cost notes
- final outcome
Begin by restating the four user inputs, then produce the graph plan. Do not execute until the plan passes validation unless the task is low-risk and explicitly allows immediate execution.
Example Execution Trace
The trace is not a transcript dump. It is a structured operational artifact that a reviewer can inspect.
$ graph-run "audit checkout routes for auth gaps"
plan: graph_id=auth-audit version=1 topology=scope -> route_workers[*] -> reduce -> verify -> synthesize
classify: fixed-ish, read-only, high consequence, known-size after scope
validate: ok no_cycles=true no_missing_contracts=true unsafe_parallel_writes=false
ready[0]: scope_routes
run: scope_routes status=executed outputs=18 route_files
ready[1]: route_worker[01..18] concurrency=6 side_effect=read_only
run: route_worker[01] status=executed findings=0
run: route_worker[02] status=executed findings=1 evidence=src/routes/billing.ts:44
run: route_worker[03] status=failed_retryable error=tool_timeout
recover: route_worker[03] local_retry attempt=1 reason=transient_timeout
run: route_worker[03] status=executed findings=0
...
edge: reduce deterministic flatten=7 dedupe=5 sort=severity
ready[2]: verifier_panel[5] lenses=correctness, exploitability, reproducibility
run: verifier_panel status=executed accepted=3 rejected=2 abstain=0
ready[3]: synthesize
run: synthesize status=executed report=auth-audit.md
final:
successful_nodes=23
failed_nodes=0
skipped_nodes=0
retried_nodes=1
evidence=3 verified findings with file/line references
unresolved_risks="route glob excludes generated routes"
cost_notes="parallel fan-out bounded at 6; verifier panel added 15 calls"
Failure Modes And Limits
None of this makes the failure modes disappear. It moves them somewhere a team can see, and it introduces a few new ones. The new ones are predictable enough to list.
Graph overhead can exceed its value on simple or mostly linear tasks. A three-step workflow with real serial dependencies may be better as a chain or a single agent with a clear checklist. Anthropic's guidance to start simple and add complexity only when it improves outcomes applies directly here.
More agents can increase failure surface. Every extra node adds prompt, parsing, schema, tool, and merge risk. Parallel execution can amplify a bad plan. If the planner misses a dependency, several workers can run on incomplete inputs. If the planner adds spurious edges, the graph becomes slower without becoming safer.
Structural validity does not guarantee strategic correctness. A graph can be acyclic, typed, and fully validated while still decomposing the problem poorly. Qiao et al.'s workflow-generation benchmark separates node selection, sequential validity, and graph structure for this reason: generating a correct graph is harder than writing a plausible sequence.
Parallel execution can create contention. Rate limits, file locks, merge conflicts, shared temporary directories, external API quotas, and duplicate work can erase latency gains. Write-heavy parallel workers need isolation or serialization.
Static DAGs fit known, verifiable work. Exploratory, creative, and dynamically evolving tasks may require a dynamic graph, an orchestrator-workers topology, or controlled replanning. Claude dynamic workflows are a current vendor implementation example: Anthropic describes Claude planning work, running many parallel subagents, verifying outputs, and reporting back. That is useful evidence that the pattern is shipping, not a universal benchmark for graph engineering.
Verifiers have a validation gap. A schema can prove a field exists. It cannot prove the field is true. A test suite can catch covered regressions. It cannot prove the absence of uncovered bugs. LLM judges can share blind spots with the workers they judge. Use deterministic tests, schemas, static analysis, source evidence, and human review where possible.
Any-of and speculative execution need careful semantics. Alternative-path execution is not the same as unsafe speculative side effects. If two branches can mutate production state, "try both and keep the first winner" is not a graph design. It is an incident plan unless cancellation, idempotency, and compensation are explicit.
One last note on the Structured Graph Harness paper, since this article leans on it. Its strongest contribution is vocabulary: ready-set cardinality, plan-version immutability, bounded recovery, side-effect classification, join semantics, the validation gap, and attributable evaluation design. Borrow the words. Do not borrow performance claims. The paper states plainly that it has no completed empirical validation, and a citation that quietly promotes a design hypothesis into a result is exactly the kind of unverified claim the rest of this article is arguing against.
A Practical Adoption Path
Do not begin by installing a graph framework. Begin by tracing the workflow you already run.
- Write the current path as a linear chain.
- Mark which downstream steps actually consume upstream outputs.
- Remove fake edges.
- Identify independent work that can run concurrently.
- Add contracts to the highest-risk nodes first.
- Move deterministic edge operations into code.
- Add verifiers at boundaries where false positives or unsafe actions are expensive.
- Add loops only where feedback can improve the next attempt.
- Record the graph plan and execution trace.
- Measure cost, latency, quality, and failure categories against the simple baseline.
The first useful graph may be boring:
intake -> plan -> implement -> test -> review
That is fine. If the task is small, the chain is the graph. Structure becomes valuable where there is repeated work, independent breadth, high-risk claims, side effects, unknown-size discovery, or repeated failures that need local recovery instead of global improvisation.
What Teams Should Standardize
Teams that use agents for serious engineering work should standardize the artifacts around the agent, not only the prompt that invokes it.
Standardize graph plans. A plan should declare node IDs, jobs, inputs, outputs, tools, model tiers, side-effect classes, dependencies, join modes, verifiers, budgets, and stop conditions.
Standardize node contracts. A worker without a contract is just another conversation. Contracts make results parseable, replaceable, reviewable, and testable.
Standardize context routing. Each node should receive minimum sufficient context: identity, local instructions, references, input payload, output schema, and verification criteria. Do not make every worker re-read the full history.
Standardize verification gates. Put schemas, tests, static analysis, source-evidence checks, independent review, and human gates at the boundaries where bad outputs create downstream cost.
Standardize recovery ladders. Retry transient failures, patch local configuration, create a new plan version when structure must change, and escalate when the system cannot safely decide.
Standardize traces. A trace should show plan version, ready sets, dispatch order, node status, edge operations, verifier results, recovery actions, skipped nodes, final evidence, unresolved risks, and resource notes.
Standardize evals. Measure the graph against the simplest baseline that could work. Track success rate, quality, latency, token use, tool calls, verifier false positives, recovery frequency, and human review outcomes. Do not attribute gains to graph structure until the baseline and measurement make that claim credible.
Graph engineering is an operating-system pattern for AI-enabled engineering. It turns agent judgment into bounded work with local context, explicit dependencies, deterministic plumbing, verification at the boundaries that matter, and a trace that outlives the run.
The point is not to make every workflow wide. Most of them should stay narrow. The point is that a team should be able to look at a finished run and answer four questions: what ran, what waited, what got skipped, and what evidence justified the answer.
A loop cannot answer those questions. A graph can.
keep going
This article covers one part of a larger system. The AI Systems Engineering Handbook is the whole operating model — fourteen chapters on context, stage contracts, validation, evaluation, cost, and governance.