Most people are still using Claude Code like a very expensive intern.
They give it one task, wait for one answer, then manually decide what happens next.
But the teams getting the most leverage from AI are building something closer to a small distributed system.

One agent scopes the problem.
Five cheaper agents search in parallel.
A deterministic script removes duplicates.
Three skeptical agents try to break the findings.
One top-tier model makes the final judgment.
That is graph engineering.
Before you keep reading:
Bookmark this guide so you can return to the graph patterns when you start building your own Claude workflows.
And follow
@Gyome1_ -
I break down Claude Code, AI agents, and the systems that turn one model into a reliable engineering workflow.
I spent weeks dissecting real agent architectures, workflow diagrams, and production patterns to rebuild Graph Engineering into one practical playbook.
Instead of writing a longer prompt, you design the path information takes through the system:
linear → fan-out → reduce → verify → synthesize
Each agent becomes a node with a bounded job. Each edge carries structured data. Routers decide which branch runs. Verifiers reject weak outputs. Loops continue until the graph stops finding anything new.
The important shift is that Claude Code no longer has to behave like one intelligence working through a giant checklist.
It can generate the orchestration code, spawn a fleet of specialized subagents, route their outputs through different models, and assemble the final result only after the evidence survives verification.

The basic patterns are not new. Software engineers have used DAGs, pipelines, barriers, MapReduce, and distributed workers for decades.
What changed is what now sits inside each node.
A node can search a repository, audit a migration, challenge an architectural decision, inspect test failures, or synthesize fifty independent findings into one cited report.
This guide breaks the entire system down from the simplest linear agent to diamond graphs, router nodes, adversarial verifier panels, converging loops, model tiering, and dynamic workflows generated directly inside Claude Code.
By the end, you will be able to look at a large task and stop asking:
"What prompt should I write?"
1. GRAPH ENGINEERING STARTS WITH THE BILL
Graph engineering is often presented as a way to run more agents.
That framing misses the expensive part.
You can launch twenty Claude agents against the same repository and receive twenty overlapping reports, repeated context, conflicting conclusions, and a much larger API bill.
A useful graph controls where computation happens, which model handles each decision, and how uncertain findings move through the workflow.
Imagine asking Claude Code to prepare a production migration:

Inspect the repository, find every dependency, propose the migration, identify risks, verify the plan, and write the final brief.
Inside one prompt, this becomes a long opaque process. Claude searches the codebase, stores findings in context, designs the migration, reviews its own plan, and produces the final report.
When the report fails, the source of the failure is difficult to locate. Claude may have missed a file, misunderstood a dependency, lost an earlier detail, or accepted a weak assumption during verification.
Every stage may also run on the same expensive model, even when parts of the task involve simple extraction or sorting.
Graph engineering opens that workflow and gives every decision a visible place.
The inspection branches run at the same time because they use the same scoped task and do not depend on each other’s output.
Their findings meet at a reduce stage, where duplicates disappear and evidence is compressed into a smaller dataset.
A router then reads the severity. Routine changes move through a lightweight review. High-risk findings receive deeper analysis from several independent reviewers before reaching the final model.
The result is a workflow where latency, model cost, context size, and verification depth are controlled through the graph’s structure.
A node should make one decision
A useful node has a bounded responsibility.
Find every call to the deprecated API. Classify each migration risk as low, medium, or high. Test the rollback plan for failure cases.
Each node needs a clear input, a defined output, and a limited decision surface.
A node that searches the repository, estimates business impact, designs the fix, and writes the recommendation still contains several hidden stages. Debugging remains difficult because the intermediate reasoning is buried inside one model call.
Smaller boundaries reveal where evidence entered the system and where its meaning changed.
An edge should carry evidence
An edge represents data required by the next node.
The scanner can return a predictable object:

1{2 "file": "src/auth/session.ts",3 "lines": [84, 119],4 "dependency": "legacySessionClient",5 "confidence": 0.94,6 "evidence": "Both call sites depend on the deprecated refresh method."7}
The risk classifier now receives the same fields for every finding. It can reject incomplete results, group related files, and route uncertain evidence into another review.
Schemas reduce interpretation drift between nodes. Free-form paragraphs force every downstream agent to reconstruct the previous agent’s meaning. Over several stages, small ambiguities can alter the final conclusion.
Structured output keeps the evidence stable while it moves through the graph.
Some nodes are ordinary code
Suppose eight search agents return eighty findings.
The workflow needs to combine arrays, discard empty responses, remove duplicates, and sort the remaining items.
These operations have deterministic answers:
1const uniqueFindings = [2 ...new Map(3 results4 .flatMap(batch => batch ?? [])5 .map(item => [`${item.file}:${item.lines.join("-")}`, item])6 ).values()7];
A JavaScript transform handles this instantly and produces the same output on every run. Sending the same task to another model adds token cost and creates another place where evidence can disappear.
Model nodes belong around search, classification, comparison, review, and synthesis. Code can handle validation, deduplication, sorting, explicit routing rules, and other predictable transformations.
This division becomes the foundation of the graph.
Every model call should correspond to a decision that genuinely requires judgment.
2. THE DIAMOND: HOW REAL AGENT GRAPHS MOVE WORK
Most serious agent graphs eventually take the same shape.
A task begins with one shared scope, splits across several independent workers, waits for their outputs, compresses the evidence, and passes the result into a final decision.
That shape is the diamond.

The left side is fan-out.
The middle point where all branches meet is the barrier.
The right side is fan-in.
This pattern appears everywhere once a task becomes too large for one context window.
A repository audit can split by subsystem. A market report can split by source. A research task can split by hypothesis. A migration review can split across API usage, database changes, deployment risk, and test coverage.
Each worker receives the same scope with a narrower assignment.
The graph then waits until enough useful evidence has returned.
Fan-out should create independent work
A branch belongs in the fan-out when it can begin from the shared input and produce a useful result without reading the output of another branch.
For a security audit, the split might look like this:

Claude Code can launch these calls concurrently with a barrier primitive such as parallel()
1const findings = await parallel(2 checks.map(check => async () => {3 return agent({4 task: check.task,5 context: auditScope,6 schema: FINDING_SCHEMA7 });8 })9);
The orchestration stays in ordinary JavaScript. Each branch receives a bounded task and returns a validated object.
The result arrives as a collection of outputs that can be filtered, inspected, and passed into the next stage.
A large fan-out still needs a reason behind every branch.
Splitting one vague assignment into twelve nearly identical agents often produces repeated findings with slightly different wording. Useful parallelism comes from distinct sources, perspectives, code regions, or hypotheses.
The barrier creates a decision point
A barrier pauses the next stage until the required branches have completed.
That pause matters because some decisions depend on the full set.
A ranking node cannot identify the most important vulnerability while half of the repository is still being inspected. A synthesis model cannot write a complete migration plan while the deployment review is still running.
At the barrier, the graph has a chance to inspect the state of the run:
1const completed = findings.filter(Boolean);23if (completed.length < MIN_REQUIRED_RESULTS) {4 throw new Error("Insufficient audit coverage");5}
This is where partial failures become visible.
A worker may time out, return malformed data, or produce no findings. Filtering null values keeps the run moving, but production workflows usually need a clearer policy:
- how many successful branches are required;
- which branches are mandatory;
- whether a failed node should retry;
- whether the final result should be marked incomplete.
The barrier is therefore part of the reliability model, not just a synchronization mechanism.
Reduce before you synthesize
After fan-out, the graph may hold dozens of overlapping findings.
Sending all of them directly into a top-tier model creates a large context, repeats the same evidence, and makes important details harder to distinguish.
The reduce stage prepares the evidence.
Some reduction can happen in code:
1const unique = deduplicateByKey(2 completed.flatMap(result => result.findings),3 finding => `${finding.file}:${finding.line}:${finding.type}`4);
The next layer may require judgment:
1const curated = await agent({2 task: `3 Group related findings.4 Preserve all file and line references.5 Rank each group by operational impact.6 Return the strongest evidence for every conclusion.7 `,8 input: unique,9 schema: CURATED_FINDINGS_SCHEMA10});
Reduction controls what reaches the final model.
A good reducer removes repetition while preserving evidence. An aggressive reducer may compress several distinct risks into one vague summary and erase the details needed for verification.
The safest pattern keeps a link between every reduced claim and its source items.
1{2 "risk": "Session refresh may fail after migration",3 "severity": "high",4 "sourceFindingIds": ["AUTH-04", "API-11", "TEST-07"],5 "evidence": [6 "Three services call the deprecated refresh method",7 "No fallback path exists",8 "Integration coverage is missing"9 ]10}
Now the synthesis node receives a smaller dataset without losing traceability.
3. RELIABILITY IS PART OF THE GRAPH
A graph can finish quickly and still produce a bad answer.
Once several agents begin searching, classifying, and reviewing the same task, the main problem becomes control.
The system needs rules for deciding which findings deserve deeper work, which outputs should be rejected, and when the workflow has searched enough.
Route by risk
A router node reads structured output and chooses the next branch.

The classification can come from a model, while the branch itself stays explicit in code.
1const route =2 finding.severity === "high"3 ? runFullAudit(finding)4 : runQuickReview(finding);
This keeps expensive review concentrated around findings with meaningful impact.
A useful router relies on fields the graph can inspect: severity, confidence, affected systems, financial exposure, or the presence of missing evidence.
Add independent verification
One agent reviewing its own conclusion carries the same assumptions into both stages.
A stronger graph sends important findings to several reviewers with different assignments.

The reviewers should not receive instructions to improve the original answer. Their task is to search for reasons it may be incomplete or wrong.
The graph can require agreement before a finding moves forward:
1const accepted = votes.filter(vote => vote.approve).length >= 2;
Isolate agents that change code
Parallel coding agents can interfere with each other when they edit the same working directory.
One agent may overwrite a file while another is still reading it. Tests may run against a mixture of unrelated changes.
Git worktrees give each branch its own copy of the repository.
1main repository2 │3 ├→ worktree/auth-fix4 ├→ worktree/db-migration5 └→ worktree/test-repair
Each agent can modify files and run tests inside its own environment. A later node compares the patches, checks conflicts, and selects what should be merged.
This turns isolation into part of the graph rather than a manual cleanup step.
Let discovery converge
Some tasks cannot be completed in one pass.
A repository audit may uncover a dependency that points toward another package. That package may reveal another call site. The graph needs a controlled way to continue searching without repeating everything it has already seen.
1const seen = new Set();2let dryRounds = 0;34while (dryRounds < 2) {5 const findings = await discoverNext([...seen]);6 const fresh = findings.filter(item => !seen.has(item.id));78 fresh.forEach(item => seen.add(item.id));9 dryRounds = fresh.length === 0 ? dryRounds + 1 : 0;10}
The important detail is deduplicating against every previously seen item.
Deduplicating only against confirmed findings allows rejected or uncertain items to return on the next pass and consume the same work again.
The loop stops after several dry rounds, a fixed budget, or a maximum number of iterations. Production graphs usually need all three.
Match the model to the node
Every node does not need the strongest available model.
Extraction, basic classification, and narrow searches can often run on a faster tier. Architecture review, adversarial verification, and final synthesis may justify a stronger model.

Model tiering becomes another property of the graph.
The budget is determined by how many nodes run, how often loops repeat, how much context crosses each edge, and which model handles each stage.
A graph with twenty cheap search calls can still cost more than one strong call. The architecture needs a token budget before it needs another branch.
Know when to stop drawing
Small tasks rarely need routers, voting panels, worktrees, and convergence loops.
Graph overhead includes orchestration code, schemas, retries, logging, intermediate storage, and more failure states to debug.
A linear workflow is usually sufficient when one model can hold the relevant context, the task has few independent branches, and the cost of a wrong answer is low.
Graph engineering becomes useful as the task gains parallel work, expensive decisions, large evidence sets, or meaningful verification requirements.
The complete workflow may eventually look like this:

The value comes from making the movement of work visible.
Every node has a limited responsibility. Every edge carries structured evidence. Every branch has a reason to exist. Every loop has a stopping condition.
At that point, Claude Code is no longer working through one long instruction.
It is executing an engineered system.





