EN Submit a tool
Guide

Graph Engineering in Fourteen Steps: From Linear Agents to Recoverable Task Graphs

About 19 min read

Most attempts to build multi-step agents end up as a straight line. Step one, step two, step three — each step politely waits for the previous one to finish before starting. In many linear workflows, a substantial share of steps do not depend on the previous one.

Most attempts to build multi-step agents end up as a straight line. Step one, step two, step three — each step politely waits for the previous one to finish before starting.

In many linear workflows, a substantial share of steps do not depend on the previous one. Measure the actual ratio in your own task graph instead of assuming it.

They don’t route. They don’t branch. They don’t process in parallel. They just queue — one head, one context, handling one thing at a time until the window fills up and the agent forgets what it was doing.

Practice on one real linear workflow. Draw an edge only when data truly moves between steps, then decide which remaining steps can run in parallel.

The next 14 steps turn a linear agent into a task graph: fan out independent work, add validation nodes, and route failures back to an explicit point.

The easy part to miss is the shape of the work: what must happen first, what can run together, and what must wait for every branch to converge.

But the shape of the work itself—what comes first, what can run concurrently, what must wait for everything else to finish—this shape is a graph. Nodes are responsible for thinking. Edges are responsible for passing results.

Claude Code directly delivers the tools for building these charts: dynamic workflows.

Claude writes an orchestration script in pure JavaScript, then generates a coordinated sub-agent queue to execute it — and the orchestration itself does not consume model tokens because it is code, not conversation.

01 Nodes are tasks. Edges are flowing content.

A graph has just two things; figuring them out can resolve most confusion. A node is a unit of work — an agent, a finite task, one input, and one output.

An edge is a dependency: it indicates that the output of this node is the input of another node. That’s all.

The mistake is treating "then" as an edge. There is no edge between the two actions "summarize the document and then tell me the weather"—the weather information does not depend on the summary.

Those are two unconnected nodes, yet a linear script unnecessarily links them. An edge only exists when data actually moves between them.

Learn to ask for every "then" in your agent: Does the next step read the output of the previous step? If not, there is no edge; waiting is a waste.

02 Your linear script is a degenerate graph

When you write an agent as "first do A, then do B, then do C, then do D," you have drawn a graph—a single, branchless chain. Each node has exactly one incoming edge and one outgoing edge.

It runs correctly. But it runs slowly and is fragile because the chain has no redundancy: if C stalls, D will never happen, and A’s work is stuck upstream with nowhere to go.

The first real skill of graph engineering is to redraw the chain. Take your linear agent and, for each arrow, ask the step 1 question.

Most chains have two or three arrows that don’t transmit data—they’re just the order in which you happened to input things.

Cut those arrows, and the chains will collapse into a wider structure: several independent nodes that can run simultaneously, feeding a single node that requires them all.

03 Give each node a contract

A node you cannot reason about is a node you cannot parallelize. The solution is a contract: bounded input, bounded output, exactly one task.

The input is what the node reads—explicitly passed in, never assumed from a shared window. The output is a defined shape, preferably validated, so the next node can use it directly without guessing.

In the workflow, this contract is enforced through a schema. When you pass an agent() call with a JSON schema to Claude, the generated sub-agent is forced to return validated structured data—the validation occurs at the tool call layer, so if there is a mismatch, Claude retries instead of handing you free text that you have to parse and hope for the best.

This is the distinction between nodes to which Claude can connect in the graph and nodes that only work when a human reads their output.

04 Treat edges as data contracts

An edge is not just "B comes after A." It’s a commitment about the flow of data: A produces this shape, and B is built to consume this shape. When you name edges with data—rather than order—two things become easier.

You can immediately see whether an edge is real (is data actually moving?), and as long as the shape remains the same, you can swap nodes at either end without breaking the graph.

In practice, the edge part exists in plain JavaScript. The reduce step between fan-out and composition—flattening, deduplication, filtering—is just code that manipulates the shapes returned by nodes.

No need for a proxy. A quiet victory for graph thinking: a lot of content that people waste on model tokens is actually just an edge, and edges are free.

05 . Use parallel() to expand in parallel

This is an act that can pay for everything. When you have N independent nodes—N sources to check, N documents to review, N routes to audit—you don’t chain them together.

You tell Claude to run them separately and execute immediately. In a parallel() workflow: Claude accepts an array of thunks, generates a sub-agent for each thunk, all sub-agents execute simultaneously, and then returns the array of results to you.

There are two details that make it very robust. First, parallel() acts as a barrier—it waits for each thunk before it to complete before returning, so the next stage can see the full collection. Next, a thunk that throws an exception will resolve to null rather than rejecting the entire batch, so an unstable proxy cannot cause the whole run to fail.

Always use .filter(Boolean) on the results. The concurrency is limited based on the number of your cores, with the excess queued, so you can pass in a hundred thunks, and they will all complete—only a small number are processed at a time.

Fan-out exists in the code written by Claude, not in the model’s conversation. Claude itself never simultaneously retains nine sources of context—each sub-agent has its own context, and only the final answer is returned.

This is why Claude can scale a workflow to dozens or hundreds of sub-agents without overloading the conversation. The orchestration layer consumes no tokens, because it is not another thinking round of Claude.

06 . Converge at the barrier

Fan-out is only useful when something collects it. Fan-in is the convergence of edges at a node—a proxy (or a piece of code) that sees all upstream results at once and performs operations that require the entire set: deduplication across sources, ranking by impact, or early exit if the total results are empty. This is the only place where a barrier is worth its actual clock cost.

Rule for keeping the graph fast: only use a barrier when a stage truly needs to use all previous results together. Deduplicate across all sources? Use a barrier—correct.

Just flattening a list? That’s an extreme case; just handle it inline. The taste test is very simple and strict: if you write parallel → transform → parallel, and the intermediate transform has no cross-element dependencies, you should be using a pipeline and completely skip this barrier.

07 Diamond: split → work → merge

Put fan-out and fan-in together, and you get the main topology of every serious agent graph: the diamond.

A single node splits tasks, multiple nodes work in parallel, and one node merges them. This is the pattern behind market scanning, dependency auditing, code review, and research reports—by changing sources and prompts, the same framework can adapt.

The standard form has a name worth remembering: Expand → Reduce → Integrate. Expand to collect breadth, reduce with simple code to compress it, and finally use an agent to integrate and produce the answer.

Once you see the diamond, you stop asking ‘How can I make my agent take more steps?’ and start asking ‘Where are the branches and where does the merge happen?’—this is the question that can actually scale.

08 Route edges at runtime using conditions

Not every diagram is fixed. Sometimes which edge to take depends on what the node discovers. Routing nodes check the results and decide the downstream path — first classify the tickets, then branch to the correct handler; check the size of differences, then either do a quick audit or initiate a full audit.

In a workflow, this is just a JavaScript if or switch on the node’s output, because the control flow exists in the code.

This is where determinism becomes a feature rather than a limitation. The router’s decisions can be supported by Claude (with sub-agents doing the classification), but the routing is code written by Claude — so for the same classification, it behaves the same way every time it runs.

You get Claude’s judgment at the nodes and the script’s reliability on the edges. There won’t be unexpected situations like ‘Claude decides to skip the audit’—because skipping must be written into the graph, and it isn’t.

09 Place a validator on the edge

The real leverage of the diagram is not in having more agents, but in the structures you can build around them to generate confidence.

A validation node is placed before the downstream of the result, and its only task is to try to terminate that discovery. If it survives, it passes. If not, it can never reach the answer.

There are three patterns worth mastering.

  • Adversarial verification: For each finding, generate N independent skeptics and prompt them to refute it; only retain the finding if the majority survive.

  • Multi-angle verification: Provide each verifier with different perspectives—correctness, security, reproducibility—because diversity can uncover failure patterns that N identical checks can never find.

  • Panel of judges: Generate N attempts from different angles, score them in parallel review, synthesize from the winners while also drawing the best parts from the runners-up.

This is precisely the pattern of porting the Bun runtime when a real team incorporates adversarial code review in cycles.

10 – Isolate nodes so that a single failure cannot break the entire graph.

In a chained structure, failures cascade—if C dies, D will not run at all, and the whole system stops. In a graph structure, failures should be limited to their node.

This is partially correct to some extent: a thunk that throws an error inside parallel() will resolve to null, so the eight good agents will still return, while the one bad agent will drop out. Your .filter(Boolean) is this constraint.

Design each fan-in to tolerate missing inputs instead of assuming the inputs are complete.

Subtler failures are when nodes interfere with each other. When agents write to a file in parallel, they may conflict.

The solution is isolation: a "working tree" — each agent runs in its own Git working tree, completes its work in a sandbox, and merges cleanly.

Only use it when nodes are actually writing in parallel. It is a safety belt designed for the specific topology that needs it, not a default burden for every run.

11 Add a loop — but let it converge.

Sometimes you only realize the scope of the work once you are in it: discoveries of unknown size, a debugging session, finding one bug and then discovering three more. This requires a cycle — a controlled fallback back to a previous node.

The danger is obvious: a loop that does not converge is an infinite loop, and it will keep generating proxies until your budget runs out.

A convergent pattern is a loop until exhaustion: keep generating finders until K consecutive rounds find nothing new, then stop. One detail that determines success or failure—an error almost everyone makes the first time—is what objects you deduplicate.

Deduplicate all seen content, not just confirmed results. Otherwise, rejected discoveries will reappear every round, the loop will never end, and you have built a machine that will forever pay to rediscover the same dead ends.

12 Layer the model across nodes

Not every node needs to use your best model. The graph makes this obvious in a way that a single agent could never achieve: some nodes are limited and repetitive (extracting this field, classifying this work order), while others carry real judgment (synthesizing reports, adjudicating findings).

Run boring nodes on cheaper models and use your expensive tokens where real judgment is needed.

In a workflow, each sub-agent generated by Claude inherits your session model unless the script overrides it — so by default, a large run is fully billed according to your session layer. Model options in a single agent() call tell Claude to route only that node elsewhere.

Check /model before running at large scale, then have Claude guide the duplicate nodes of a branch to a cheaper model while keeping the merged nodes. This is the leverage for turning a graph that consumes a lot of tokens from expensive to economical without changing its structure.

13 . Topology is your cost and latency

The shape of the graph is not decorative—it is the biggest leverage on wall-clock time. The choice that trips everyone up is: parallel() vs pipeline(). The parallel() barrier will make all nodes wait for the slowest node before starting the next stage.

pipeline() allows each project to go through all stages independently, without obstacles—Project A can be at stage 3 while Project B is still at stage 1 . Faster projects will finish ahead instead of waiting behind slower ones.

Pipeline() is used by default. Only use a barrier when a certain stage truly needs to acquire all preceding results at once—for example, deduplication across collections, early exit based on total count, or hints for comparison with "other findings." "Cleaner code" and "stage feels independent" are not reasons; the delay from a barrier is real, measurable, and wasted time. Independent does not mean synchronous.

14 Have Claude draw the chart — self-routing

The final step is to stop manually drawing charts for tasks you cannot plan in advance.

With dynamic workflows, you describe the goal, and Claude will write the orchestration script itself — breaking down tasks, choosing routing methods, generating a coordinated group of sub-agents, and synthesizing the results. What you get is a chart tailored for this run, not a fixed chart you hoped would fit.

There are three ways to enter. When you mention the word ‘workflow’ in your prompt, Claude will generate a workflow for that task. Running a saved or bundled workflow — /deep-research is a graph that runs in production: Scope → Parallel Search → Fetch → Adversarial Validation → Synthesis, which is exactly the skeleton of this course.

Alternatively, enable ultracode, and Claude will plan workflows for each important task in the session. When a run works well, press the s key to save its script to .claude/workflows/ — using version control, it can be rerun by name, and anyone who clones that repository can start this graph.

Six charts built with Claude this week

  • Perform a security scan on each path. Claude generates a sub-agent for each path file, each of which looks for missing authorization checks, and then the validator confirms each finding before it goes into the report. There is no single context that can cover the breadth.

  • Referenced a report with /deep-research. A chart already provided in Claude Code. Claude breaks down your question into different angles, performs parallel searches, deduplicates sources, then uses a three-voter skeptic system for adversarial verification of each statement, and then drafts it.

  • Migrate modules one by one according to the files. The upper limit of Bun is scaled according to your repository. Claude distributes the translations across files, runs the test suite as a threshold for each file, and feeds back any failures—adversarial reviews capture parts that might fail even if they pass once.

  • Adversarial review of differences. Claude adopts different strategies for changes of different sizes: small changes undergo a quick review once, while large changes trigger a full parallel review, evaluated by reviewers from different perspectives (correctness, security, performance), and then synthesized by a panel of judges.

  • Conduct an ecosystem scan as planned. Save it once, and then it can be rerun forever. Claude checks multiple sources in parallel—publications, blogs, discussions—ranks them on a threshold by influence, and writes a summary. Version control is done in .claude/workflows/, and it can be launched by name.

  • Discover unknown scale. You don’t know how many errors exist. Claude runs finders in parallel, deduplicates each new discovery against everything known, verifies living objects, and continues to loop until two consecutive rounds find nothing new—then stop.

Conclusion:

The prompter asks a question. The architect draws a diagram.

Linear agents are never the limit—they are just the first shape, which everyone will use because it fits the way we type. One line, one heading, one thing at a time.

Once you can see nodes and edges, you stop asking agents to do more things and start asking graphs to do broader things: expand where work is independent, control edges where confidence matters, and layer models where judgment does not matter.

Most people queue up to take steps. Those who learn to draw graphs will operate a fleet—and will never notice others stuck under the ceiling below.

Lay the roadmap onto a minimally verifiable graph

Don’t rush to build an "all-in-one multi-agent platform". Pick a task with real branching: research can be done in parallel, writing must wait for materials, fact-checking failures require revisions, and final publication must be manually confirmed.

Routing workflows are suitable for first classifying inputs, then sending tasks to the corresponding processing paths.Independent sub-tasks can run in parallel, and the same output can be reviewed by different checkers from multiple perspectives.When sub-tasks cannot be enumerated in advance, then consider an orchestrator-worker setup, allowing the orchestrator to dynamically split and aggregate results.

Regardless of the structure used, each node must have clearly defined input, output, and failure states. The agent loop of Claude Code itself still consists of collecting context, taking action, and verifying results; the graph merely organizes multiple such loops according to their dependencies.Configure tests, screenshots, or expected outputs for each node, and in complex tasks, explore and plan first, then implement and verify.

Minimum acceptance checklist:

  • Each edge can be explained as to why it exists;
  • There are no hidden write conflicts between parallel nodes;
  • Retries have budgets and stopping conditions;
  • States can be persisted and support restoration from checkpoints;
  • Human approval is retained before high-risk actions;
  • In case of failure, it can point out the specific node and evidence, rather than just returning "agent failed."