On July 18, 2026, Peter Steinberger, the creator of OpenClaw, asked a question on Twitter that went viral: "Are we still talking loops or did we shift to graphs yet?" While Steinberger’s tweet was a joke poking fun at how fast we rename things, by the end of the day it had 2.6 million views and the term "graph engineering" was everywhere.

What Steinberger is flagging is another shift in how engineers are using agents to code. Before loop engineering, developers were actively engaging with their agent all day. You’d tell Claude Code about a failing test. It patched it. You’d run tests but the lint would break. So, you’d paste the lint output for your agent and it would fix that. You’d push only to see that CI fails on Node 18 only. You’d then paste that log for your coding agent. And repeat.
Loop engineering was about removing the repetitive human parts of the example above. In loop engineering, you give the agent access to what it needs to achieve its goal, let it loop until it does, and step out of it. The agent runs the tests. It reads the output. It patches. It runs them again. The lint breaks, so the loop pipes the lint output back in and the agent fixes it. It pushes. CI fails on Node 18, so the loop feeds that log back too. The cycle repeats on its own until the build goes green or the agent stalls. The human stops being the link between tools. Graph engineering is the set of tactics to ensure Loop engineering succeeds.
It involves looking at where loop engineering can fail (ex. by ending early, doing things out of order, or getting stuck in an infinite loop) and designing a system that prevents that. It involves designing the process that AI agents follow with nodes mapped out and routing between them.
It’s particularly useful when the work decomposes into steps with distinct contexts, tool requirements, or failure boundaries. It can include sequential handoffs, concurrent branches that join, conditional paths, and retry cycles.
Agent graph patterns are the recurring shapes systems take within graph engineering. Nodes do the work. Edges route between them. State is what flows along the edges. Five composable shapes can be put together to explain almost everything anyone is building.
Those five patterns did not appear in July 2026 though. Anthropic published them in Building Effective Agents in 2024.
We look at each of those composable patterns, what they’re for, and what circumstances require that level of complexity so you can decide how and whether to use them. Then, we’ll share some common agent graph architectures that use multiple patterns.
What graph engineering actually is
Before we look at the patterns, let’s quickly recap what graph engineering is. There are three crucial components of graph engineering: nodes, edges, and state.
Nodes do the work. Nodes are agents or steps. They can be a deterministic function, a single model call, or a full agent running its own loop. Nodes represent one job each within the graph.
Edges decide what runs next. This is the routing between the nodes. Some are fixed: A then B. Some are conditional and branch on a node's output or the current state or loop back if the output doesn’t pass a review. Some fan out to several nodes at once or fan in to a single join.
Shared state is the object traveling along the edges. That can include the task, the artifacts produced so far, which checks passed. It's what every node reads from and writes to, and it's the difference between a system and a sequence of disconnected calls.
The five core graph engineering patterns at a glance
These five patterns cover the graph engineering patterns that are most commonly seen. Important to note: the patterns compose. Real systems aren't one shape and some of these patterns aren’t graphs on their own but are common building blocks of agent graphs.
For example, a code review graph might fan out to several audit nodes that join their findings at a verifier, which routes confirmed problems to a fixer, and cycles the fixer against a unit test suite until it passes. That's parallelization, routing, and evaluator-optimizer in one graph.

None of these patterns are new to ML engineers or anyone who has designed complex agentic systems. The reason graph engineering is trendy right now is because more engineers are working with long running coding agents and grappling with how to improve their uneven outputs.
Graph engineering like prompt engineering, harness engineering, and loop engineering before it is just another strategy developers are using to get better quality for their token costs. Rather than let an LLM or the coding agent decide itself how to approach a complex problem, creating a graph gives the engineer more control over how a single agent or multiple agents work, what they do in what sequence, what states are shared between nodes, what models are called, what is solved via a call or a deterministic check, how many tokens to budget, and more.
Drawing the graph makes the decisions explicit, once, rather than improvised by a coding agent or LLM on every run. Its goal is to improve the quality of the output by controlling the process.
Pattern 1: Prompt chaining

While not itself a graph, prompt chaining serves as a building block for graphs when expanded into non-linear or cyclical workflows. In loop engineering, a prompt chain acts as the ‘inner loop’ or the series of processes the orchestrator agent takes to get at the desired output. Prompt chaining works best for situations where a task can be decomposed cleanly into subtasks.
In prompt chaining, each node's output becomes the next node's input. Most explanations frame this as specialization: a researcher node feeds a writer node feeds an editor node, each with its own job. That framing though misses one of its core benefits.
One key reason to split a chain is context isolation. Step one accumulates tokens: search results, discarded drafts, tool output, or its own reasoning. Step two doesn't need any of it and including it measurably degrades the result. The node boundary exists in many graphs so that step two starts from a clean window containing only the context it requires.
For example, take a graph that turns a bug report into a reproduction script. Node one investigates: it greps the repo, reads a dozen files, tails logs, opens three that turn out to be irrelevant, and forms a hypothesis about where the failure originates. By the time it finishes, its context holds thousands of tokens of file contents and several abandoned theories.

Node two writes the script. It only needs the hypothesis, the file path, and the reproduction steps. It does not need the two dead ends. If they're in the context window, they compete with the conclusion and could lead to degraded outputs or hallucinations from too much context. It also increases the token costs to pass those along.
Split the nodes and node two receives a short structured handoff: the target file, the trigger condition, and the expected failure. That’s a clean window with one hypothesis and nothing to disambiguate.
Best used: When the steps can be decomposed cleanly and have genuinely different context requirements. For example, an extraction node produces structured data; the formatting step needs that data and not everything that produced it.
Skip when: The steps are coupled enough that you forward the entire state anyway. If every node reads the full artifacts of the previous node, you have one node with three prompts and the extra hops cost you latency for nothing. The tell is when you have a state object that only grows from one hop to the next.
In practice: Whitelist what each node receives instead of passing the shared state wholesale. Type the handoff so a schema change breaks at the boundary rather than three nodes downstream. And summarize at the edge when the upstream output is large — the summary is usually what the next node needs, and it's an order of magnitude cheaper to prompt the next node with.
Pattern 2: Routing

Routing is also a familiar pattern. In routing, one node classifies the input and a conditional edge sends the work down one of several paths.
Routing is the cheapest structural win in a graph because it lets you match cost to difficulty. For example, a support graph can classify a ticket and send the simple ones to a small model with cheap token costs and the ambiguous ones to a larger model with more reasoning capabilities.
With PR reviews, for example, a code change can get routed by blast radius. In both, the paths can differ in model, toolset, or the amount of verification applied downstream.

Best when: The paths are meaningfully different. That can include a different model, different tools, different approach to the task, different follow up tasks, different spend, or different approval requirements. If two branches run the same node with a slightly different prompt, that's a parameter, not a path.
Fails when: The router is the weakest node in the graph. If everything downstream is conditioned by the router’s classification and nothing validates that the router got that classification right to make sure it’s routing things accurately, it leads to degraded output. A misrouted item doesn't fail loudly — it completes successfully down the wrong path.
In practice: Be sure to validate the router against labeled examples before you ship it, and keep measuring it after. Lack of routing accuracy explains many failure patterns in router-based graphs.
Give unrecognized and low-confidence classifications the same destination: the most conservative path available. That usually means the expensive branch but sending the wrong work to the cheap default is how misrouted work becomes bad output.
Pattern 3: Parallelization

In parallelization, the graph fans out to several nodes at once and then later fans in to a join. This can happen once or multiple times within the entire graph.
Concurrency is one of the core benefits of agent graphs. Things like specialization, auditability, and failure isolation can be achieved from ordinary functions in a single loop but running independent work at the same time is one of the things a single loop structurally cannot do.
Parallelization makes sense for many use cases. You can use it to achieve lower latency, when the operations are genuinely independent, or in scenarios where it’s critical to have multiple options generated, checked, or ranked.
Using parallelization to achieve low latency makes sense when someone is waiting on the output. Parallelism is a critical pattern for real-time applications. An AI phone agent is the strongest example of this since voice conversations have a latency budget that other agential operations don’t.

On a call, response time is measured in milliseconds. The system needs to quickly process the voice input via a speech to text model, send that to an agent that determines the intent and then route that to separate agents who look up account, policy, and other details in parallel. Then, the context would join back in a node that drafts the reply and runs a policy gate against it before sending it to a text-to-speech model. That graph would include prompt chaining, routing, parallelism and multiple models.
Parallelism also makes sense when the operations are genuinely independent and don’t require the same context to be prompted to both nodes to be completed since in those cases you’d be spending the same amount of tokens for the output whether completed by one model or several.
If multiple perspectives or attempts are needed for higher confidence results, parallelism can be very useful. For example, a security product reviewing code for vulnerabilities might want two or more separate agents to review it concurrently to try to find a problem.
Some cautions about parallelism:
- It might buy latency with money. In situations where parallel workers would require the same context in order to complete a task, you would be paying more for lower latency since you'd be processing the context multiple times across each parallel worker. some implementations, parallel workers would duplicate whatever setup they share. For example, if you research five sources sequentially at 40 seconds each the full time is 200 seconds. But run in parallel it's about 45 seconds — the slowest branch plus the join. However, in those cases, since the original context would be the same, you would pay five times to process the context behind those searches for the privilege of saving that time. That's the right trade for anything a person is waiting on and the wrong one for a nightly batch job where nobody cares whether it finishes in three minutes or twelve.
- The speedup is capped by your slowest branch. One 90-second node beside four 10-second nodes saves you far less. The latency wins scale with how even your branches are, not how many there are. Profile per-node latency before you fan out, because the profile tells you whether the pattern is worth using for latency at all.
Best for: When branches are genuinely independent and roughly comparable in duration, and a person is waiting on the result. Or when you need multiple independent perspectives or attempts.
Fails when: Branches write to the shared state concurrently. Two nodes updating the same field is a race, and the outcome could depend on which finishes first. Give every field one writer, have branches return results rather than mutate state, and do the merging at the join where the ordering is explicit.
In practice: Decide what happens when a branch fails. Three of five sources returned — do you proceed, retry the two, or fail the run? The join needs an explicit policy and "wait for all of them" is a policy that could turn one hung branch into a hung graph. You should also set per-branch timeouts, make the join tolerant of partial results where the work allows it, and record which branches contributed to the final output.
Pattern 4: Orchestrator-workers

With orchestrator-workers, a node is an agent that dynamically breaks down a task and decides at runtime how many workers to spawn, what each one does, and then synthesizes its results.
In this pattern, you don't know the fan-out width, the worker identities, or the shape of the agent graph until the run is already underway.
For example, a coding agent given the task to "migrate this API surface" determines which files need changing by looking, not by being told and then spawns various sub-agents to help. You couldn't express that as a static graph, because the graph doesn't exist until the orchestrator runs.

It's also the pattern most likely to surprise you in production, for a few related reasons.
- Fan-out width is unbounded by default. An orchestrator that decides to spawn forty workers will spawn forty workers. You can, however, cap the width before it spawns workers. This is especially important if you have network capacity issues as a graph that suddenly has forty workers hitting one rate-limited API means most of them would fail on 429s, retry, and fail again. The orchestrator has no visibility into downstream capacity, so concurrency limits have to be explicit in the prompt.
- The topology is non-deterministic. Two runs on identical input can produce different graphs. That breaks the most useful debugging technique you have, which is diffing a failed run against a working one. Record the realized topology of each run so you have something to compare.
- Aggregation is harder than it looks. Results arrive out of order, some workers fail, and the orchestrator's plan may not match what came back. Decide in advance whether partial results are acceptable and how the join reconciles them.
Best for: When the work list can't be enumerated before the run starts because the task is broad. The orchestrator has to discover the scope by inspecting something — which files reference this API, which sub-questions the research actually raises, which of 200 tickets match a pattern.
Fails when: The orchestrator is unbounded. Width, depth, and spend all need explicit ceilings, because the component deciding how much work to create is the same kind of component that can misjudge scope. It also fails when the aggregation step assumes the plan and the results match — workers drop out, return partial outputs, or answer a slightly different question than the one they were assigned, and a join that doesn't reconcile against the original plan will silently produce a confident summary of four-fifths of the work. Also, this pattern could be too complex for many applications. A good rule is that if you can write the task list yourself or derive it with a query, use parallelization instead and keep the topology static.
In practice: Create bounds for the width, depth, and spend. Workers that can spawn workers need a recursion limit or your costs could balloon. Set a token budget for the whole subtree rather than per worker, since the risk is the aggregate. And keep the orchestrator's plan as a durable artifact — when a run goes wrong, the question is almost always whether the plan was bad or the execution was and you can't answer that without the plan.
Pattern 5: Evaluator-optimizer

The evaluator-optimizer is a loop. In this pattern, you generate, evaluate, loop back on failure, and exit on success or on a bound.
This is the pattern where the design work is almost entirely about who evaluates and when it stops. This pattern is particularly useful in applications with clear evaluation criteria where iterative refinement is valuable.

For example, optimizing a slow query against a latency target. In this case, the generator rewrites the query. The evaluator then runs it against a representative dataset and returns the execution time and plan. The pass condition is stated up front: under 200ms at p95. Each iteration has evidence about whether the last change helped and by how much in order to keep improving it.
Best for: When you can state the pass condition before the run and check it mechanically. "Type checker exits clean." "Output matches schema." "All assertions pass." That's when the loop does real work — each iteration has ground truth to move toward.
Fails when: The exit conditions are underspecified. Most implementations have two: success, and a hard iteration cap. Those are the easy ones. The useful ones are the four nobody writes:
- No progress. Same diff or same error message twice running. The loop isn't converging, it's resampling.
- Oscillation. A, then B, then A. Two failing states the generator alternates between, each fixing what the other broke.
- Token budget, tracked separately from iteration count. Attempts get more expensive as context accumulates; ten iterations is not ten times the first one's cost.
- Cost per attempt rising while the evaluator's score is flat. The clearest signal that continuing is throwing money at a problem the generator can't solve.
In practice: Log the evaluator's verdict and its reason on every iteration, not just the last. A loop that failed nine times before passing tells you something a loop that passed on the first try doesn't. Keep prior failed attempts out of the next attempt's context unless the generator specifically needs them — usually the error is what helps, not the discarded output. And when the loop exits on a bound rather than on success, that's a distinct outcome from failure. Surface it as its own state, because "we stopped trying" and "it doesn't work" need different responses downstream.
The evaluator should also be external to the generator, if possible. Preferably a deterministic check whose verdict comes from outside the model's judgment. Some examples include a test suite that passed or didn't, a schema that validated, a build that compiled, a numeric threshold.
Some common graph engineering architectures
Here are three coding tasks genuinely benefit from a graph and the shape each one could take.
1. Migrate a deprecated API across a large codebase

Patterns: Orchestrator-workers into evaluator-optimizer.
The broad scope of this task is the reason a graph is effective. You don't know which files reference the old surface until something inspects the repo. So, the orchestrator discovers the work list, then fans out one worker per file or module.
Each worker gets a narrow context: these files, this old signature, this new signature. Then the whole thing joins and runs the test suite, and failures cycle back to the workers that produced them.
2. Translate a service from one language or framework to another

Patterns: Parallelization into an external verifier.
Fan out per module, since modules translate independently and each wants only its own source in context.
In this, the verifier should be the original system's actual behavior — same inputs through both implementations with outputs compared via checks and tests
3. Triage and fix a batch of open issues

Patterns: Routing plus a prompt chain.
The router earns its place because the issues aren't equally risky. Typos, dependency bumps, and doc fixes go down a cheap path with a small model. Anything touching auth, payments, or data migrations goes down an expensive path — better model, more verification, and human approval before merge.
The router needs a closed label set and a conservative fallback: unrecognized or low-confidence classifications route to the expensive path, never the cheap default.
Where to start
Wondering whether you should rearchitect your agentic loops into agentic graphs? It depends on what you plan to use them for since not everything is better as a graph.
Google Research, DeepMind, and MIT tested 260 agent configurations across six benchmarks and found that tasks where single-agent performance already exceeds ~45% accuracy see negative returns from additional agents since coordination costs exceed the remaining upside.
Multi-agent collaboration boosted performance by up to 80.8% on decomposable, parallelizable tasks like financial analysis, whereas on strict step-by-step planning tasks, multi-agent architectures degraded performance by 39% to 70% due to communication overhead and context fragmentation.
For those working with long-running agents, most of what you build this quarter is likely to be one loop with a good verifier and a hard stop. That’s because a loop is the right shape for many tasks. But graphs can also be useful patterns to build for the right use cases.
Using E2E tests to verify your agent output? Try our AI platform for E2E tests built with learnings from 100 million test runs for clients like Figma, Doordash, and Drata.