Graph Engineering in 12 Steps: From a Straight Line to a Fleet That Checks Its Own Work

Most people who build a multi-step agent build a line. Step one, step two, step three, each one waiting for the last to finish. It runs. It also runs at the speed of everything added together, and it breaks the moment one step in the middle returns something unusable.
Anthropic shipped Dynamic Workflows in Claude Code in May 2026, which lets Claude write its own JavaScript orchestration script and spawn a coordinated fleet of subagents to run it. That release turned graph engineering from a whiteboard idea into a thing you can run tonight on a repo you already have. The shape of the work stopped being something you describe in a prompt and became something you draw.
This guide covers what a graph actually is, the five-minute test that finds the waits you are paying for and do not need, the one topology worth memorizing, the verifier rule that separates a real graph from an expensive one, and the three ways graphs fail without telling you.
Bookmark this. The fake-edge test in Step 4 is the part you will want in front of you when you draw your own.
The whole method in seven moves
DRAW → every job is a box, every dependency is an arrow
CUT → delete the arrows that carry no data
CONTRACT → bounded input, validated output, one job per node
FAN OUT → run the independent nodes at once
REDUCE → merge in plain code, not in a model
VERIFY → separate node, fresh context, real signal
ANCHOR → at least one node that cannot be argued withEverything below expands one of those seven.
Part 1: The vocabulary that fixes most of the confusion
A graph has two parts. Getting them straight removes most of the mystery.
A node is one unit of work. One agent, one bounded job, one input in, one output out. Researching a single competitor. Reviewing a single file. Checking a single claim against a single source. Not "research the market and write a summary and check the sources." That is three nodes wearing one prompt.
An edge is a dependency. It connects two nodes when the second one reads what the first one produced. Not when the second one happens afterward. Only when data moves.
Nodes do the thinking. Edges carry the results. Every other term in graph engineering applies those two ideas at a different scale.
02. Two different things are called a graph. Know which one you are building.
This trips up beginners inside a week, because both meanings show up in the same feed.
A knowledge graph is a data structure. Entities as nodes, relationships as edges, stored in something like Neo4j and queried by an agent that needs to traverse relationships instead of matching text. That is the GraphRAG line of work: a retrieval strategy that beats plain vector search when the answer depends on how facts connect rather than on how a passage is worded.
An orchestration graph is a plan for work. Nodes are agents doing jobs, edges are the order those jobs must run in. Nothing is stored. The graph exists only for the duration of the run.
This guide is about the second one. The two combine well, an orchestration graph can have a node that queries a knowledge graph, but they solve unrelated problems. If your issue is "the agent cannot find the right fact," you want a knowledge graph. If your issue is "the agent takes eleven minutes to do eleven things that could have taken one," you want an orchestration graph.
03. Your linear agent is already a graph. Just the worst one.
Write an agent as "do A, then B, then C, then D" and you have drawn a graph. Every node has one arrow in and one arrow out. A single chain.
It runs correctly. It also runs at the sum of all four latencies, and it has four points of sequential failure. If C stalls, D never fires, and A's output sits upstream with nowhere to go.
The size of the problem scales badly. Forty steps in a line means forty sequential waits and forty ways to halt. The same forty jobs drawn as a graph usually have three to five real dependencies, and the run finishes at the speed of the slowest layer instead of the sum of everything. Same work, same model, same prompts.
A loop is the other shape people already run: one agent improving one thing on repeat, try, check, adjust, go again. A loop is a cycle, and a cycle is a legitimate graph. The distinction that matters is width. A loop buys you iteration on one thing. A graph buys you many things at once. Neither one buys judgment.
04. The fake-edge test
This is the highest-value five minutes in the whole discipline, and it needs no tools.
Take the workflow you run today. Write every step as a box. Draw an arrow between each pair of consecutive steps. Then walk the arrows one at a time and ask a single question:
Does this step read the output of the step before it?
Yes, the edge is real. Keep the order. No, there is no edge, and the wait between those two boxes is time you are paying for and getting nothing back.
Take "review file A for bugs, then review file B for bugs." It reads like a sequence. The review of file B never looks at what the review of file A returned. Those two steps run one after another because that is the order someone typed them, not because data moves between them. Run them side by side and the pair finishes in the time of the slower single file.
Two or three fake edges hide in almost any workflow you draw. The tell is the phrase "and then." Every time you catch yourself writing it, check whether you meant "and then, using that result" or just "and then, next."
When you finish the pass, the boxes with no incoming arrow can all start immediately. The boxes with no outgoing arrow are your outputs. What sits between them is your actual graph.
05. Every node needs a contract
A node you cannot reason about is a node you cannot parallelize. The fix is a contract: one bounded job, a defined input, a defined output shape.
The input is what the node reads, passed to it explicitly, never assumed from a shared window. The output is a fixed shape, validated, so the next node consumes it without guessing. A node whose output is a wall of free text is a node only a human can read, which means a human sits in the middle of your graph forever.
NODE CONTRACT
JOB: research one competitor's pricing. one job, nothing else.
IN: { competitor: "name", url: "https://..." } passed in, never assumed
OUT: { price: number, plan: string, source: url, date: "YYYY-MM-DD" }
SCHEMA: enforced. free text gets rejected and the node retries.
WHY: a defined output is what lets the next node read this one with
no human in between. that is what makes a node wire-able.In a Claude Code workflow the contract is a JSON schema passed to the agent() call. Validation happens at the tool-call layer, so a mismatch triggers a retry instead of handing you prose you have to parse and hope about.
Part 2: The shapes
When you have N independent nodes, N sources to check, N files to audit, N routes to review, you do not chain them. You run them at once.
In a Claude Code workflow this is parallel(). You hand it an array of jobs, Claude spawns one subagent per job, and they execute concurrently. Two details make it survivable in production. First, parallel() acts as a barrier: it waits for every job before returning, so the next stage sees a complete set. Second, a job that throws resolves to null rather than rejecting the whole batch, so one flaky agent cannot sink a run of forty. Filter the nulls out before you use the results.
The part that matters for cost: the fan-out lives in code Claude wrote, not in a model conversation. Your session's context never holds nine sources at once. Each subagent carries its own window, and only the final answer comes back. That is what lets one run scale to dozens of agents without drowning the session.
07. Fan in, and the barrier tax
A fan-out is useless without something that gathers it. The fan-in is where edges converge and one node sees every upstream result together.
Use a barrier only when a stage genuinely needs the whole set at once. Deduping across all sources needs the whole set. Ranking by impact against the other findings needs the whole set. Early-exit when the total came back empty needs the whole set.
Flattening a list does not. Neither does formatting, filtering, or counting. Those are edges, and edges run in plain code for zero tokens.
The smell test: if you wrote fan-out, then a transform, then another fan-out, and that middle transform has no cross-item dependency, you paid barrier latency for nothing. Every item waited for the slowest one before any of them moved. A streaming pipeline lets item A reach stage three while item B is still in stage one, and fast items finish instead of idling.
The temptation most people give in to is spawning an agent to "combine the results." Resist it. If combining means flatten and dedupe, that is a few lines of JavaScript, deterministic and instant. Save agents for judgment. A graph where every edge is an agent pays rent on its own wiring.
08. The diamond: fan out, reduce, synthesize
You do not need a hundred topologies. Watch any serious agent system and the same picture keeps appearing.
One node splits the job. Several nodes work in parallel. Something compresses what they found. One node writes the answer.
That is the diamond, and its formal name is worth memorizing: fan out, reduce, synthesize. Fan out to gather breadth. Reduce with plain code to compress. Synthesize with one agent that writes from what survived.
It is the same skeleton behind a market scan, a dependency audit, a code review, and a research report. Claude Code's own /deep-research runs this shape in production: one node scopes the question into angles, workers search in parallel, findings get verified, and one report reaches you.
Once you can see the diamond you stop asking "how do I make my agent do more steps" and start asking "where is the split, where is the merge." The second question is the one that scales.
09. Router nodes: judgment at the node, determinism at the edge
Not every graph is fixed at design time. Sometimes which edge fires depends on what a node found.
A router node inspects a validated result and picks the downstream path. Classify the ticket, then branch to the right handler. Check the diff size, then either run one quick pass or spin up a full parallel audit. Estimate the module's complexity, then send the explanation to a cheap model or an expensive one.
The router's decision comes from a model. The routing itself is code. That combination is the point: you get judgment where judgment belongs and repeatability everywhere else. The same classification always takes the same branch, because the branch was written into the script rather than decided fresh each run.
This is also where model tiering lives. Some nodes are bounded and repetitive: extract this field, classify this ticket, check this link resolves. Some carry the real judgment: adjudicate this finding, write this report. Run the boring nodes on a cheap model and keep your expensive tokens where judgment actually happens. In a workflow, every subagent inherits your session model unless the script says otherwise, so a large run bills entirely at your top tier by default. Routing the fan-out down a tier is the single lever that turns a token-hungry graph into an affordable one without changing its shape.
Part 3: The trust layer
10. The verifier, and the clean-context rule
Now the part almost everyone skips, and it decides whether you built a system or an expensive toy.
Models are weak graders of their own output. A model reviewing its own work sees its own reasoning trail and prefers conclusions consistent with what it already wrote. It is not laziness in the model. It is structural, and no amount of "be critical" in the prompt fixes it.
So the agent that did the work never checks the work. You put a separate node on the edge, and its only job is to try to kill the finding before it moves downstream. Survives, it passes. Fails, it dies there.
Here is the catch nobody names loudly enough: the verifier needs a clean context.
Hand it the same conversation the worker had and it is not verifying anything. It has already read the reasoning that produced the claim, and it will agree with that reasoning in a different font. A graph of agents sharing one context is a single loop in a costume. It fails the same way, later and more expensively, with more green lights on the way down.
So the verifier gets its own window. It sees the artifact and the rubric. It does not see who produced it or how. And it checks a real signal, not "did the agent say it was done" but "does the test actually pass, does the link actually resolve, does the number actually appear in the source."
VERIFIER NODE
INPUT: one finding from one worker. the finding only, never the worker's chat.
CONTEXT: fresh and empty. it has not seen the work it is judging.
SIGNAL: objective. a test result, a resolving URL, a matching number.
PASS: the finding moves downstream.
FAIL: the finding is dropped before it can reach the final answer.11. Three lenses beat ten identical checks
One verifier catches the obvious failures. Three verifiers asking the same question catch the same obvious failures three times.
Split the checking by lens instead. For a research finding: is it correct, is it current, is the source real. For a code change: does it work, is it safe, does it break anything adjacent. Three different questions catch failure modes that ten identical questions never surface, because identical checks share identical blind spots.
Then decide by majority rather than unanimity. A single strict verifier that rejects everything is as useless as none at all, and you will notice the problem later than you think, because a graph that ships nothing looks a lot like a graph that found nothing.
12. Anchors: the nodes that cannot be argued with
There is a deeper failure here, and it is the real lesson of the whole shift.
Build the full graph. Paired checkers, audit nodes, meta-nodes tuning the other nodes. Every node watches another node, and every one of them reads a report produced by the system itself. The audit checks the numbers against a source that came from the same pipeline in the first place.
Everything agrees. Nothing has been verified.
That graph fails exactly like the single loop did, just later, more expensively, and with far more green lights on the way down. This is Goodhart's law arriving with a bigger bill: once a measure becomes the target, the system optimizes the measure instead of the thing the measure stood for.
Topology alone does not buy truth. A graph needs anchors, meaning nodes that touch something outside the system. Tests that actually ran, not "should pass," did pass. A URL that resolves to the claim it is cited for. A number that came from the bank instead of from a summary of the bank.
And some rules have to be frozen, specifically the ones an optimizer would be tempted to weaken. Those are the rules it will bend to win.
A graph is only as honest as the nodes inside it that refuse to move.
Where graphs break without telling you
Three failure modes account for most bad runs.
Context collapse. You fan out to a thousand nodes, then try to feed a thousand outputs into one synthesis step and blow past the window before synthesis starts. The fix is layered fan-in: batch the results, summarize each batch, then combine the summaries. The final node reads twenty-five summaries instead of a thousand raw outputs.
False independence. Two nodes look independent because their prompts never mention each other, and then both write to the same file or hammer the same rate-limited API. That is a hidden edge. The fix is isolation, giving each worker its own git worktree or its own scratch space, plus an audit for shared resources rather than shared data. Any two nodes writing the same file need an edge, not parallelism.
Silent node failure. In a chain, one failure halts everything, which is annoying and obvious. In a graph, one dead node among two hundred slips into a report that looks complete. The fix is a fan-in guard: every merge step counts its inputs against the number it expected and flags the gap instead of quietly synthesizing on half the data.
When a graph is the wrong tool
A graph buys width. It does not buy judgment. When the work is not wide, the line was never your problem.
Skip it when the task is small or isolated. Adding one function, fixing one bug. Coordination is pure overhead and one agent is faster and cheaper.
Skip it when you want to approve every step. The whole point is running wide without you in the chair, so a tight leash works against the design.
Skip it when you do not yet know what you are looking for. Exploratory work wants one agent you can steer, not a fleet committed to a plan you wrote before you understood the problem.
Skip it when the steps genuinely depend on each other. Forcing a graph onto sequential work adds coordination cost for zero speedup.
The tell is the fake-edge test from Step 4. If you cannot find two boxes with no arrow between them, there is no graph to build. It is a loop, and a loop is fine.
Build your first one this week
Open a repository you know, so the result means something to you. Then paste a prompt with the four parts every graph spec needs: the goal, the fan-out, the verification, and a cap.
GRAPH SPEC
GOAL: audit every route file under src/routes/ for missing auth checks
FAN OUT: one agent per file, running in parallel
VERIFY: an independent checker on each finding, with a fresh context
CAP: 20 files on this first run
ON FAIL: flag any file that returns nothing. never skip it silently.
REPORT: one merged list of the routes missing auth
(start the prompt with the word "workflow" so Claude builds a graph
instead of working through your steps in a line)Claude shows you the orchestration plan before running anything. Read the phases, approve, and watch the fleet work while your session stays free. What lands at the end is one report rather than twenty separate chats, because the intermediate results lived in the script's variables instead of your context window.
The cap matters more than it looks. It keeps the first run cheap, and it points at the thing demos leave out.
The cost, stated plainly
A graph costs more than a normal chat. The coordination gets cheaper, not the work. Passing results between agents through code instead of conversation avoids re-spending context, but every agent still burns its own tokens, and a fleet of them burns a pile.
The public ceiling is instructive. Bun's Zig-to-Rust port ran on this exact machinery: roughly fifty workflows, a peak of sixty-four agents in parallel, around 535,000 lines of Zig turned into over a million lines of Rust in about eleven days, work that would have taken close to a year by hand. It also cost roughly $165,000 in usage, needed a human designing and monitoring the whole run, and drew real criticism over whether that volume of AI-written code can be reviewed safely.
That is the honest shape of the technique. Genuine scale, genuine price, genuine supervision requirement. Start scoped, watch what one run costs, widen only after a run has earned it.
The mistakes that turn graphs into money pits
Treating "and then" as an edge. Most chains have two or three arrows carrying no data. Every one is latency you are buying for nothing.
Free text between nodes. Without a schema, the next node guesses, and a human ends up in the middle of the graph permanently.
An agent on every edge. Flatten and dedupe are code. A graph that spawns a model to combine two lists pays rent on its own wiring.
A barrier where a pipeline belongs. Every item waits for the slowest one. "It felt cleaner" is not a reason.
The worker verifying its own work. Self-preference is structural. The verifier must be a separate node.
A verifier sharing the worker's context. It reads the reasoning, agrees with it, and reports a pass. That is a single loop with extra steps and a bigger invoice.
No anchor. Every node confirming another node, none of them touching a test that ran or a link that resolves. Consistent and unverified.
No cap. An ambitious graph will spend your budget in the background while you are doing something else.
Fanning out onto shared state. Two agents writing one file race. Isolate the workers before you widen the fan.
Building a graph for a task that was never wide. The most expensive mistake, because it fails slowly and looks sophisticated the whole time.
Conclusion
Graph engineering is not a new capability in the model. It is the recognition that the shape of the work has been the constraint the entire time, and that most people draw a line because a line matches the order they type in. The model was never the bottleneck.
Learn the fake-edge test first. Draw the workflow you already run, walk the arrows, and delete the ones that carry no data. That single pass makes you faster than most people before you touch a new tool. Everything else in this guide, contracts, diamonds, routers, verifiers, anchors, is what keeps the width honest once you have it.
Run the fake-edge test on one workflow this week.
Bookmark this so the twelve steps are in front of you when you draw the graph that replaces it 👀

















