Graph Engineering with Opus 5: A 14-Step Roadmap for AI Agents

@angeldot_
ESPANHOLhá 1 dia · 25 de jul. de 2026
184K
128
21
6
288

TL;DR

This article provides a comprehensive 14-step roadmap for transitioning from simple linear AI prompts to complex graph-based agent workflows, focusing on parallelization, verification, and cost efficiency.

The 14-step roadmap to move from prompts to a fleet of agents working for you

Most people who build a multi-step agent end up with a straight line.

Step one, step two, step three. Each waiting politely for the previous one to finish before starting.

And almost no one realizes that half of those steps never had to wait for anything.

They don't route. They don't branch. They don't parallelize. They just queue up. One head, one context, one thing at a time, until the window fills up and the agent forgets what it was doing.

This is the 14-step roadmap that turns that single-file line into a graph. One that fans out over an entire fleet, verifies its own findings, and converges on a result that a single agent could never sustain.

By the end, you will know three things:

→ where your current system is waiting for no reason → how to distribute work without losing trust in the output → how to lower the bill without touching quality

THE FRAMEWORK SHIFT NO ONE EXPLAINS

A prompt is a sentence. A loop is a cycle. A harness is the ground the agent stands on.

But the shape of the work itself—what runs before what, what can run at the same time, what has to wait for everything else—that shape is a graph.

Nodes think. Edges transport results.

And Claude Code already brings the tooling to build them directly: dynamic workflows.

Claude writes an orchestration script in plain JavaScript and then launches a coordinated fleet of sub-agents to execute it. The coordination itself costs zero model tokens because it is code, not a conversation.

angel - inline image

The roadmap is divided into four blocks:

01 to 04, seeing the graph you already have → 05 to 08, moving the fleet → 09 to 11, trusting what comes out → 12 to 14, making sure it doesn't ruin you

BLOQUE 1 · SEEING THE GRAPH YOU ALREADY HAVE

01. NODES ARE TASKS, EDGES ARE WHAT FLOWS

A graph has exactly two things, and being clear about them fixes almost all confusion.

Node: a unit of work. An agent, a bounded task, an input, an output. → Edge: a dependency. It says the output of this node feeds the input of that one. Nothing more.

The error is treating "and then" as if it were an edge.

"Summarize this file and then tell me the weather" has no edge between the two parts. The weather report does not consume the summary. They are two disconnected nodes that a linear script chains together without any necessity.

The edge only exists when data actually crosses.

angel - inline image

Draw it as boxes and arrows. A box is a call to agent(). An arrow is a variable that comes out of the return of one call and enters the prompt of another.

If you can't draw the arrow, if no variable crosses, those two boxes are independent.

And that independence is what you are going to exploit during the next 13 steps.

→ The rule: for every "and then" in your agent, ask if the next step reads the output of the previous one. If not, the wait is wasted time.

02. YOUR LINEAR SCRIPT IS ALREADY A GRAPH, JUST A DEGENERATE ONE

When you write an agent as "do A, then B, then C, then D," you have already drawn a graph. A chain without branches. Each node with exactly one input edge and one output edge.

It works. It also runs slowly and fragilly because a chain has no redundancy: if C gets stuck, D never happens, and A's work gets trapped upstream with nowhere to go.

The first real skill of graph engineering is redrawing the chain.

Take your linear agent and, for each arrow, ask the question from step 01.

Most chains have two or three arrows that don't transport data. They are only there because that's the order in which you typed them.

Cut those arrows and the chain collapses into something wider: a few independent nodes that could all run at once, feeding into a single node that actually needs them all.

This costs no money, requires no new tools, and usually eliminates more waiting than anything you can buy.

→ The rule: before adding anything, delete the edges that don't transport data.

03. GIVE EACH NODE A CONTRACT

A node you can't reason about is a node you can't parallelize.

The fix is a contract: bounded input, bounded output, a single job.

→ the input is what the node reads, passed explicitly, never assumed from a shared window → the output is a defined shape, ideally validated, so the next node consumes it without guessing

angel - inline image

In a workflow, that contract is enforced with a schema. When you pass Claude an agent() call with a JSON schema, the sub-agent is forced to return valid structured data. Validation happens at the tool call layer, so there is a retry when it doesn't fit, instead of returning free text that you have to parse and pray it turns out well.

text
1// a node with a real contract: bounded input, validated output, one single job
2const ITEM = {
3 type: 'object',
4 additionalProperties: false,
5 properties: {
6 title: { type: 'string' },
7 url: { type: 'string' },
8 impact: { type: 'string', enum: ['high', 'medium', 'low'] },
9 },
10 required: ['title', 'url', 'impact'],
11};
12
13const output = await agent(source.prompt, {
14 label: `research:${source.key}`,
15 schema: ITEM,
16 agentType: 'general-purpose',
17});

That is the difference between a node Claude can wire into a graph and a node that only works when a human reads it.

→ The rule: if a node's output has no shape, it's not a node. It's a conversation.

04. THE EDGE IS ALSO A CONTRACT, AND IT'S FREE

An edge is not "B goes after A." It's a promise about what crosses: A produces this shape, B is built to consume this shape.

When you name the edge by its data instead of its order, two things become easy:

→ you see instantly if the edge is real, because you can ask if something moves through it → you can change the node at either end without breaking the graph, as long as the shape is maintained

In practice, the edge lives in plain JavaScript. The reduction step between fan out and synthesis—flattening, deduplicating, filtering—is just code operating on the shapes your nodes returned.

No agent is needed there.

And this is one of the silent victories of thinking in graphs: a brutal amount of what people pay for in tokens is actually an edge, and edges are free.

The temptation is to launch an agent to "combine the results." Resist it.

If combining means flattening and deduplicating, that's a flatMap and a Set. Deterministic, instantaneous, zero tokens.

→ The rule: agents are for judgment, not for plumbing. A graph where every edge is an agent pays rent for its own wiring.

BLOQUE 2 · MOVING THE FLEET

05. FAN OUT WITH parallel()

This is the move that pays for everything else.

When you have N independent nodes, N sources to consult, N files to review, N routes to audit, you don't chain them. You tell Claude to fan them out and run them at the same time.

In a workflow, that's parallel(): it takes an array of thunks, launches one sub-agent per thunk, all executing concurrently, and returns the array of results.

angel - inline image

Two details make it robust:

→ parallel() is a barrier. It waits for all thunks before returning, so the next stage sees the complete set. → a thunk that throws an exception resolves to null instead of bringing down the whole batch, so an unstable agent can't sink the execution.

That's why you always .filter(Boolean) the output.

Concurrency is capped roughly by your number of cores and the excess is queued, so you can pass a hundred thunks and they will all finish, just in handfuls.

text
1phase('Research');
2
3const raw = await parallel(
4 SOURCES.map((f) => () =>
5 agent(f.prompt, {
6 label: `research:${f.key}`,
7 phase: 'Research',
8 schema: ITEM,
9 agentType: 'general-purpose',
10 }),
11 ),
12);
13
14const collected = raw.filter(Boolean); // remove nulls from failed agents

And here is the important part: the fan out lives in code Claude wrote, not in a conversation with the model.

Claude's own context never holds nine sources at once. Each sub-agent loads its own, and only the final response returns.

That is what allows scaling to tens or hundreds of sub-agents without drowning the session. The orchestration layer costs zero tokens because it's not another turn of Claude thinking.

→ The rule: if N things don't read each other, don't queue them. Fan them out.

06. CLOSE THE FAN AT A BARRIER

A fan out only works if something collects it.

The fan in is the node where edges converge. Where an agent, or a piece of code, sees all the upstream results at once and does something that requires the entire set: deduplicating across sources, sorting by impact, exiting early if absolutely nothing came back.

That is the only place where a barrier earns its cost in clock time.

Deduplicating across all sources? Barrier, correct.

Just flattening a list? That's an edge, do it inline.

text
1// the edge: plain JS, no agent, zero tokens
2const flat = collected.flatMap((c) => c.items);
3log(`Collected ${flat.length} elements`);
4
5phase('Curate');
6
7// the barrier node: needs the ENTIRE set to deduplicate and sort
8const curated = await agent(
9 `Deduplicate and sort these by impact:
10${JSON.stringify(flat)}`,
11 { phase: 'Curate', schema: CURATED },
12);

The test is simple: if you wrote parallel → transform → parallel, and that middle transformation has no dependency between elements, you should have used a pipeline and skipped the entire barrier.

→ The rule: barrier only when a stage truly needs all previous results together.

07. THE DIAMOND: SPLIT, WORK, MERGE

Combine fan out and fan in and you have the work topology of any serious agent graph: the diamond.

One node splits the task. Many nodes do the work in parallel. One node merges it.

angel - inline image

The canonical form has a name worth memorizing: fan out → reduce → synthesize.

→ fan out to gain breadth → reduce with plain code to compress it → synthesize with a final agent that writes the response

It is the skeleton behind a market scan, a dependency audit, a code review, and a research report. You change the sources and the prompts and the same skeleton adapts.

When you see the diamond, you stop asking "how do I make my agent take more steps" and start asking "where is the split and where is the merge." Which is the question that truly scales.

→ The rule: don't design steps. Design where it splits and where it joins.

08. ROUTE THE EDGE AT RUNTIME

Not all graphs are fixed. Sometimes the edge taken depends on what a node found.

A router node inspects a result and decides which path is triggered. It classifies the ticket and branches to the correct handler. It looks at the size of the diff and chooses between a quick review or launching a full audit.

angel - inline image

In a workflow, this is a simple JavaScript if or switch over the validated output of a node, because flow control lives in code.

text
1// router node: an agent classifies, code chooses the edge
2const { severity } = await agent(
3 `Classify the risk of this diff:
4${diff}`,
5 { schema: {
6 type: 'object',
7 properties: { severity: { enum: ['low', 'high'] } },
8 required: ['severity'],
9 }},
10);
11
12let review;
13if (severity === 'high') {
14 review = await parallel(FILES.map((a) => () => agent(`Audit ${a}`)));
15} else {
16 review = await agent(`Quick review of ${diff}`);
17}

Here, determinism is a feature, not a limitation.

The router's decision can come from Claude, but the routing is code. It runs the same way every time for the same classification.

Model judgment in the node, script reliability in the edge. No emerging surprises like "the agent decided to skip the audit," because that skip would have to be written in the graph. And it isn't.

→ The rule: let the model decide what this is, and let the code decide what is done with it.

THE COUNTER-RULE (read before continuing) A graph buys breadth.

It does not buy better judgment.

If every step of your work needs the full picture of the previous one, distributing it among agents doesn't give you a better answer. It gives you the same answer, more expensively and later. The graph starts paying off at the exact moment the work splits into tasks that never read each other's results. Before adding a single agent, the only question that decides your bill is:

where does my work split?

If it doesn't split, stick with one agent and save yourself the remaining 6 steps.

BLOQUE 3 · TRUSTING WHAT COMES OUT

09. PUT A VERIFIER ON THE EDGE

The real leverage of a graph is not having more agents. It's the structure you can build around them to produce trust.

A verifier node sits on the edge before a result is allowed to go down. Its only job is to try to kill the finding. If it survives, it passes. If not, it never reaches the answer.

And there is a hard rule beneath all this: never let the same agent grade its own exam. A model reviewing its own output misses most of its own errors because it is evaluating from the same place it made the mistake.

angel - inline image

Three patterns worth having on hand:

Adversarial verification: for every finding, launch N independent skeptics with the order to refute it. It stays only if it survives the majority.

Diverse lens verification: give each verifier a different angle. Correct, secure, reproducible. Diversity catches failure modes that N identical checks never find.

Panel of judges: generate N attempts from different angles, score them with parallel judges, synthesize from the winner by grafting the best from those that came close.

This is the pattern behind the most ambitious projects done with agents, like porting an entire runtime with adversarial review embedded within the loop itself instead of at the end.

→ The rule: no finding travels without verification, and two verifiers never ask the same question.

10. ISOLATE NODES SO A FAILURE DOESN'T POISON THE GRAPH

In a chain, a failure cascades. C dies, D never runs, everything stops.

In a graph, the failure should stay contained in its node.

That is already partially true: a thunk that blows up inside parallel() resolves to null, so eight good agents return while the bad one falls alone. Your .filter(Boolean) is the containment.

Design every fan in to tolerate missing inputs instead of assuming the complete set.

The most subtle failure is nodes stepping on each other. When several agents write files in parallel, they collide.

The fix is isolation: each agent runs in its own git worktree, does its work in a sandbox, and then merges cleanly.

Resort to this only when nodes truly write in parallel. It is the seatbelt for the only topology that needs it, not a default tax on every execution.

→ The rule: one single writer per file. And every fan in tolerates gaps.

11. ADD A CYCLE, BUT MAKE IT CONVERGE

Sometimes you don't know how big the job is until you're inside. Discovery of unknown size. A bug sweep where finding one reveals three others.

That calls for a cycle: a controlled edge back to a previous node.

The danger is obvious. A cycle that doesn't converge is an infinite loop launching agents until it melts your budget.

The pattern that does converge is loop until dry: keep launching searchers until K consecutive rounds yield nothing new, then stop.

angel - inline image

And the detail that makes or breaks it, the error almost everyone makes the first time, is what you deduplicate against.

Deduplicate against everything seen, not just what was confirmed.

Otherwise, rejected findings reappear every round, the loop never dries up, and you've built a machine that pays to rediscover the same dead ends forever.

text
1const seen = new Set();
2const confirmed = [];
3let dryRounds = 0;
4
5while (dryRounds < 2) { // stop after 2 empty rounds
6 const found = (await parallel(
7 SEARCHERS.map((b) => () => agent(b.prompt, { schema: BUGS }))
8 )).filter(Boolean).flatMap((r) => r.bugs);
9
10 const newItems = found.filter((b) => !seen.has(key(b)));
11 if (!newItems.length) { dryRounds++; continue; } // nothing new → towards dry
12
13 dryRounds = 0;
14 newItems.forEach((b) => seen.add(key(b))); // dedupe vs SEEN, not confirmed
15
16 const judged = await parallel(newItems.map((b) => () =>
17 parallel(['correct', 'security', 'repro'].map((lens) => () =>
18 agent(`Judge "${b.desc}" from ${lens}. Is it real?`, { schema: VERDICT })))
19 .then((v) => ({ b, real: v.filter(Boolean).filter((x) => x.real).length >= 2 }))
20 ));
21
22 confirmed.push(...judged.filter((v) => v.real).map((v) => v.b));
23}

→ The rule: every loop has a round limit and deduplicates against everything seen.

BLOQUE 4 · MAKING SURE IT DOESN'T RUIN YOU

12. STAGGER MODELS ACROSS NODES

Not every node needs your best model.

A graph makes this obvious in a way a single agent never does. There are bounded and repetitive nodes—extract this field, classify this ticket. And there are nodes where real judgment lives—synthesize the report, adjudicate the finding.

Run the boring ones on a cheap model and spend the expensive tokens where judgment matters.

In a workflow, each sub-agent inherits the model from your session unless the script overrides it. By default, a large execution bills entirely at your session level.

The model option in a specific agent() call routes only that node elsewhere.

Review /model before a large execution, and then downgrade the repetitive fan-out nodes while keeping the fusion node high.

This is the lever that turns a token-hungry graph into something economical without touching its shape.

→ The rule: expensive model only where judgment is at stake.

13. TOPOLOGY IS YOUR COST AND YOUR LATENCY

The shape of the graph is not cosmetic. It is the biggest lever on clock time that exists.

The decision that trips everyone up: parallel() vs pipeline().

→ a parallel() barrier makes everything wait for the slowest node before the next stage starts → a pipeline() lets each element flow through all stages independently, without a barrier. Element A can be in stage 3 while B is still in stage 1

angel - inline image

Fast elements finish early instead of getting stuck behind slow ones.

By default, pipeline. Resort to a barrier only when a stage truly needs all previous results at once: a dedupe against the set, an early exit based on the total, a prompt that compares against "the other findings."

"It looks cleaner" and "the stages feel separate" are not reasons. Barrier latency is real, measurable, and wasted time.

Separate is not the same as synchronized.

→ The rule: pipeline by default, barrier by justified exception.

14. LET CLAUDE DRAW THE GRAPH

The final move is to stop drawing the graph by hand for jobs you can't plan in advance.

With dynamic workflows, you describe the goal and Claude writes the orchestration script itself: decomposes the task, chooses the fan out, launches a coordinated fleet of sub-agents, and synthesizes the result.

You get a graph tailored to that specific execution instead of a fixed one you hoped would fit.

angel - inline image

There are three entry points:

→ say the word "workflow" in your prompt and Claude writes one for the task → execute a saved one or a standard one. /deep-research is a real graph running in production: bound → parallel search → fetch → adversarial verification → synthesis. Exactly the skeleton of this roadmap. → activate the mode that plans a workflow for every substantial task in the session

When an execution goes well, save its script in .claude/workflows/. Versioned, re-executable by name, and launchable by anyone who clones the repo.

› Launch a workflow that audits all routes in src/routes/ looking for

missing auth. One agent per route file, and verify each finding

before reporting it.

● Claude wrote an orchestration script · launching in background…

/workflows — auth-audit · running

✓ Bound 1/1 2.1k tok · 4s

✓ Fan-out 18/18 one agent per route file

◯ Verify 11/18 skeptics at 3 votes per finding…

○ Synthesize 0/1 waiting to verify

the session remains responsive, you can keep working while the fleet runs

→ The rule: if the work changes shape in every execution, don't draw the graph. Describe it.

SIX GRAPHS TO BUILD THIS WEEK

Security sweep over all routes. One sub-agent per route file, each hunting for missing auth checks, followed by a verification pass that confirms each finding before it reaches the report. Breadth that no single context could sustain.

Report with sources via /deep-research. A graph that already comes inside Claude Code. It decomposes your question into different angles, runs searches in parallel, deduplicates sources, and adversarially verifies every claim with skeptics at three votes before writing.

Porting a module, file by file. Fan out the translation over the files, the test suite as a gate for each, and failures go back into the loop. Adversarial review catches what a single pass would have delivered broken.

Adversarial review of a diff. Route based on size: a small change gets a quick pass, a large one triggers a full parallel audit with reviewers using different lenses—correct, secure, fast—and then a panel of judges synthesizes.

Scheduled ecosystem scan. Saved once and re-executed forever. Consults many sources in parallel—releases, blogs, forums—sorts by impact at a barrier, and writes the summary. Versioned in .claude/workflows/, launchable by name.

Discovery of unknown size. You don't know how many bugs there are. Parallel searchers, dedupe each new finding against everything seen, verification of survivors, and the loop continues until two rounds yield nothing. Then stop.

CHECKLIST BEFORE LAUNCHING YOUR FIRST GRAPH

→ have I deleted edges that don't transport data? → does the work truly split, or does each step need the previous one? → does each node have bounded input, shaped output, and a single task? → am I paying an agent to do something that is a flatMap? → is there any barrier that doesn't need the entire set? → does any finding reach the result without anyone trying to kill it? → do two verifiers ask the same question? → do all loops have a round limit? → is there more than one node writing to the same file? → are repetitive nodes running on the expensive model?

If you fail more than three, you don't have a graph. You have a chain with more steps.

CONCLUSION

The one who prompts asks a question. The one who architects draws a graph.

The linear agent was never the ceiling. It was just the first form, the one everyone grabs because it matches the way we write. One line, one head, one thing at a time.

When you start seeing nodes and edges, you stop asking the agent to take more steps and start asking the graph to make it wider.

Fan out where work is independent. Gates on edges where trust matters. Cheaper models where judgment isn't at stake.

Most will keep queuing steps in a single-file line.

Those who learn to draw the graph will move an entire fleet. And they will never notice the low ceiling under which the rest are stuck.

Draw your current system tonight. Just the tasks and the arrows between them. Count the false edges and delete them.

It is the first move of the entire craft, it costs zero, and it usually eliminates more waiting than any tool you can buy.

Recriar no YouMind

Turn one viral article into a full content workflow

Collect the source, decode the pattern, create assets, draft the story, and distribute from one AI workspace.

Explore YouMind
Para criadores

Transforme seu Markdown em um artigo 𝕏 impecável

Quando você publica seus próprios textos longos, formatar imagens, tabelas e blocos de código para o 𝕏 é uma dor de cabeça. O YouMind transforma um rascunho completo em Markdown em um artigo 𝕏 impecável e pronto para publicar.

Experimente Markdown para 𝕏

Mais padrões para decifrar

Artigos virais recentes

Explorar mais artigos virais