Found something good?

Save it before you doomscroll past it.

How to master graph engineering (Full Course)

How to master graph engineering (Full Course)

A loop hides one decision inside a black box: what runs next.

Every time an agent loop decides whether to retry, escalate, or move on, that decision happens inside the model's own reasoning, invisible to you, unauditable after the fact, and impossible to inspect without re-reading the model's raw output and hoping it explained itself honestly. A graph makes that same decision explicit. Written down. Inspectable before the run even starts.

This is not a small distinction. It is the actual argument behind a real arXiv paper published in April 2026 that reframed how agentic systems should be built, and it is worth being upfront about something before this course goes any further. The paper's own author includes a fairness disclaimer stating plainly that this is an unimplemented design, and whether it delivers its promised benefits in practice remains an open empirical question. This course teaches the framework honestly, including that caveat, because understanding a real, rigorously argued proposal that has not yet been proven at scale is more useful than pretending it is settled fact.

By the end of this course you will understand what graph engineering actually is, why it exists as the layer above loops, the three commitments every graph in this framework rests on, and how to build your first one, along with an honest account of where the evidence currently stands and does not stand.

Why Loops Have A Ceiling

To understand why graphs exist, you need to understand precisely where loops stop being enough.

A loop, in the agentic sense that matters here, is a cycle where an agent attempts a task, observes the result, and decides what to do next, repeated until some condition is met. This works remarkably well for a huge range of tasks. It is also, structurally, a black box at the exact moment that matters most: the decision of what happens next.

When a loop's agent decides to retry a failed step, that decision came from the model reasoning over its own context and producing a choice. You cannot inspect the decision before it happens. You can only observe the outcome after. If the agent retries the same failing approach five times in a row, burning cost each time, nothing in the loop's structure prevented that, because the decision to retry lived entirely inside the model's own judgment, not in any external, checkable rule.

This is fine for low-stakes, cheap tasks where an occasional wasted retry costs nothing meaningful. It becomes a real liability for long-horizon, expensive, or high-stakes work, exactly the category of task agentic systems are increasingly being trusted with. The paper's core argument is that as agentic systems take on more consequential work, the opacity of "what runs next" stops being an acceptable black box and starts being the actual point of failure worth engineering around directly.

What A Graph Actually Is

A graph, in this framework, replaces the model's implicit next-step decision with an explicit structure defined before the run starts.

Instead of an agent reasoning its way to "I should retry" or "I should escalate" inside an opaque context window, the graph defines, in advance, exactly which states exist, which transitions between states are valid, and which specific conditions trigger each transition. The agent still does real work inside each state. What it no longer does is invisibly decide the shape of the overall process as it goes.

The five-move structure that describes any single turn through a graph like this: Plan, Execute, Recover, Escalate, Repeat. Plan is where the task gets decomposed into a defined sequence. Execute is where the agent actually does the work for the current step. Recover is what happens when execution fails, following a defined protocol rather than an improvised retry. Escalate is the explicit, defined point where the graph hands control to a human rather than continuing to attempt automated recovery. Repeat closes the cycle, moving to the next step in the plan.

Notice what changed from a loop. Every one of these five moves is now a named, inspectable state in a graph, with defined transitions between them, rather than a decision happening silently inside a single model call.

The Three Commitments

Every graph in this framework rests on three specific commitments. Understanding these three deeply is the actual core of graph engineering as a discipline, more so than any specific implementation detail.

Commitment One: Immutable Plan

The execution plan cannot shift mid-run. Once a plan is generated and locked, it exists as one fixed version for the duration of that run. The agent cannot silently revise its own plan halfway through execution based on something it noticed, the way an agent inside a loop often does without any external record of the revision happening.

This sounds restrictive, and it is meant to. The restriction is the entire point. An agent that can freely revise its own plan mid-run is exactly the agent whose behavior becomes impossible to audit after the fact, because the plan you would review afterward is not the plan that was actually followed, it is whatever the plan drifted into by the end. Locking the plan trades real flexibility for real inspectability. That tradeoff is not free, and it is worth sitting with honestly rather than treating it as a strict improvement in every case. A genuinely novel situation that the original plan did not anticipate is handled worse by an immutable plan than by a loop that can adapt freely. The commitment is a deliberate bet that, for the category of task this framework targets, predictable and auditable beats maximally adaptive.

Commitment Two: Separated Layers

Planning, execution, and recovery live in three independent layers instead of one tangled loop where all three happen inside the same continuous reasoning process.

The planning layer produces the immutable plan from commitment one and does nothing else, it does not execute steps and does not handle failures. The execution layer runs the defined steps and reports results, it does not decide what happens on failure, only what happened. The recovery layer receives failure reports and applies a defined protocol, it does not execute new work directly, only decides how to respond to what already happened.

This separation mirrors, deliberately, the same principle behind separating a Builder from a Judge in a verification loop, a role that produces work should not be the same role that evaluates or decides on that work, because collapsing the two erodes the independence that makes the check meaningful in the first place. Here the separation is threefold instead of twofold, but the underlying reasoning is identical: a system that plans, executes, and recovers all inside one undifferentiated process cannot meaningfully audit any single one of those functions independently, because they are never actually distinct in the trace you would review afterward.

Commitment Three: Strict Escalation

Recovery follows a fixed protocol instead of retrying indefinitely and hoping something eventually works.

This is the commitment that most directly addresses the token-blowout failure mode that plagues loops without real stop conditions. A strict escalation protocol defines, in advance, exactly how many recovery attempts are permitted, exactly what counts as a recovery attempt succeeding or failing, and exactly what happens the moment the defined limit is reached, handing control to a human, not attempting one more creative variation on the same failed approach.

The paper's analysis across 70 real-world systems found that a large share of Agent Loop implementations had no formal bounds on recovery attempts at all, meaning the actual behavior when something went wrong was determined by whatever the model happened to decide in the moment, not by any rule a human had actually reviewed and approved in advance. Strict escalation closes that specific gap directly.

Building Your First Graph

Here is the practical path to actually building one of these, translating the three commitments into something you can implement rather than just understand conceptually.

Start by defining your states explicitly, on paper, before writing any code or prompts. For a typical task, this usually looks like at minimum: Planning, Executing Step N, Recovering From Failure, Escalated, Complete. Write down, for each state, exactly what happens while the system is in that state and exactly what conditions cause a transition out of it.

Write the plan-generation step so that its output is a fixed, versioned artifact, not a living document the rest of the system can silently edit. A simple, practical version of this is generating the plan as a numbered list of discrete steps, each with an explicit success criterion, and treating that list as read-only for the remainder of the run. Any genuine need to deviate from it should trigger an explicit escalation to a human, not a silent internal revision.

Build the execution layer so it only ever reports outcomes, pass, fail, with specific detail, never makes a decision about what happens next itself. This mirrors exactly the Builder role from a verification loop, producing work and reporting on it honestly, without also being the role that decides whether to retry.

Build the recovery layer with an explicit, numbered protocol. Attempt one specific alternate approach. If that fails, attempt a second, different specific approach. If that fails, escalate. The protocol should be concrete enough that a human reading it in advance can predict exactly what the system will do at each stage, rather than a vague instruction like "try to fix it a reasonable number of times."

Wire the escalation state so that reaching it is a real, visible event, not something quietly logged and forgotten. A human should be notified, with the full history of what was attempted and why each attempt failed, the same discipline recommended for stop conditions in verification loops generally.

Where This Framework Genuinely Helps, And Where It Does Not

Being honest about the limits of graph engineering is more useful than treating it as a universal upgrade over loops in every situation, and the paper itself supports this more measured framing.

Graphs genuinely help on tasks where the space of things that can go wrong is reasonably well understood in advance, where auditability matters more than maximal adaptiveness, and where the cost of a runaway, unbounded retry cycle would be genuinely expensive, either in compute cost or in the consequence of a bad outcome reaching a real user or a real system.

Graphs are a worse fit for genuinely open-ended, exploratory tasks where you cannot meaningfully predict the shape of failure in advance, and where the value of the system comes precisely from its ability to improvise a response to something nobody anticipated. Locking a plan immutable, for a task that fundamentally requires adaptive replanning as new information emerges, trades away the exact capability that made the task worth automating with an agent in the first place.

The honest, defensible position, and the one the paper's own author takes, is that this is a real tradeoff worth understanding deeply, not a strictly superior replacement for loops in every case. Use a loop where adaptiveness matters more than auditability. Use a graph where the reverse is true. Most real systems benefit from having both patterns available and choosing deliberately between them per task, rather than adopting either one as a permanent default.

A Worked Example: Graph-Structured Code Migration

To make the five-move structure and three commitments concrete, here is how they apply to a real, common task, migrating a legacy module to a new framework version across a codebase.

The Planning state runs once, at the start. It analyzes the module, identifies every file that needs to change, and produces a fixed, numbered list of migration steps, each with an explicit success criterion, for instance, step 4 succeeds when the updated file compiles and the existing test suite for that file passes without modification. This plan gets locked. It is commitment one, immutable, in practice.

The Executing state works through the plan's steps in order. For each step, it applies the specific change defined in the plan and reports the outcome, pass or fail, with the actual compiler output or test result attached as evidence, never a self-assessed "looks correct." This is the execution layer from commitment two, strictly separated from the decision about what happens if it fails.

When a step fails, the graph transitions to Recovering, which follows a defined protocol rather than an improvised retry. Attempt one: reapply the same change with a narrower scope, isolating exactly which part of the file caused the compile failure. Attempt two, if the first fails: fall back to a documented alternate migration pattern for this specific kind of failure, drawn from a small library of known fixes rather than invented fresh each time. If both defined attempts fail, the graph transitions to Escalated, this is commitment three, strict escalation, not a third improvised attempt.

The Escalated state notifies a human directly, with the complete history attached: which step failed, what both recovery attempts tried, and the specific error output from each. A human reviews this specific failure with full context, rather than discovering days later that an agent had been silently retrying the same broken approach in a loop the whole time, burning cost with no record of why.

Repeat closes the cycle for successful steps, moving the graph to the next item in the locked plan until the list is exhausted, at which point the run reaches Complete.

Notice what this buys you over the equivalent task run as an unstructured loop. Every decision, whether to retry, how, and when to give up, is visible in the graph's defined structure before the run even starts, not discoverable only by reading through a transcript afterward and inferring what the model must have been thinking. A code reviewer, or a compliance auditor, can look at the graph's definition alone and know exactly what the system is capable of doing in every failure scenario, without ever having watched it run.

Graph Engineering Versus Loop Engineering: When To Reach For Which

Given that both patterns are real, documented, and each has genuine strengths, here is a practical decision framework for choosing between them for a specific task, rather than treating either as a permanent default.

Reach for a loop when the task is genuinely exploratory, when you cannot predict in advance the shape of what might go wrong, and when the model's ability to improvise a response to something unanticipated is exactly the capability you are relying on. Research tasks, open-ended debugging where the root cause is genuinely unknown at the start, and creative work where rigid structure would actively hurt the output, all favor a loop's adaptiveness over a graph's auditability.

Reach for a graph when the task is well-enough understood in advance that you can actually enumerate the likely failure modes, when the cost of an unbounded, unaudited retry cycle would be genuinely expensive, and when a human reviewer, whether that is a compliance team, a security auditor, or simply your own future self debugging a production incident, will need to inspect exactly what the system was capable of doing without re-reading a full execution transcript. Migrations, financial transactions, anything touching regulated data, and long-running unattended agent work where a silent failure could compound for hours before anyone notices, all favor a graph's structure over a loop's flexibility.

The two patterns are not mutually exclusive within a single larger system either. A common, pragmatic design uses a graph at the outer level, for the overall task structure and its stop conditions, while allowing a loop to run inside a single Execute state for the genuinely exploratory sub-task of figuring out how to implement one specific step. This gets you the auditability of a graph at the level where it matters most, the overall shape of what the system can do, while preserving a loop's adaptiveness at the level where genuine improvisation is actually valuable, the details of one bounded piece of work.

Testing A Graph Before You Trust It

Before relying on a graph-structured system for anything real, run it through stress tests specifically designed around the three commitments, since each commitment has its own way of quietly failing if implemented sloppily.

To test the immutable plan commitment, deliberately construct a scenario partway through a run where the "obviously correct" next step, if the system were reasoning freely, would deviate from the locked plan. Confirm the system actually escalates to a human rather than silently adapting the plan on its own. If it adapts silently, the plan was never actually immutable in practice, regardless of how the code is structured.

To test the separated layers commitment, check whether the execution layer's failure reports contain any trace of a decision about what should happen next, phrases like "this probably needs a different approach" embedded in what should be a neutral pass or fail report. If the execution layer is already forming opinions about recovery, the separation from the recovery layer is not real, it has just been relabeled.

To test strict escalation, deliberately feed the system a failure that neither defined recovery attempt can fix, and confirm it escalates cleanly at the defined limit rather than attempting an undefined third approach. This is the graph-engineering equivalent of testing a loop's stop condition against a genuinely unsolvable task, and it catches the exact same class of quietly expensive failure.

Beyond these three targeted tests, track one specific metric over real usage that the loop-based alternative typically cannot give you cleanly: the rate at which runs reach the Escalated state, broken down by which specific recovery attempt failed each time. A graph escalating constantly at the same specific recovery step is telling you that step's defined protocol is miscalibrated, not that the underlying task is uniformly hard, the same diagnostic value that tracking stop-condition triggers provides for loops, just available here with more granularity because the failure point is a named, inspectable state rather than an inferred moment inside an opaque transcript.

Common Mistakes When First Building A Graph

A handful of specific mistakes show up repeatedly for people building their first graph-structured system, and knowing them in advance saves real debugging time later.

Treating the plan as immutable in name only. Locking the plan on paper while still allowing the execution layer to quietly deviate from it in practice produces the worst of both worlds, no real adaptiveness and no real auditability either, since the trace no longer matches the locked plan you would review.

Collapsing the three layers back into one because it feels faster to build. The temptation to let the execution layer also decide on recovery, skipping the separation from commitment two, defeats the actual purpose of the framework. If planning, execution, and recovery are not genuinely independent, you have built a loop wearing a graph's vocabulary, not an actual graph.

Writing a recovery protocol vague enough that it is not really a protocol. "Try a reasonable number of alternate approaches" is not a strict escalation protocol, it is a soft instruction with the same failure mode as an unbounded loop, just described using graph-engineering language. A real protocol names the specific number of attempts and the specific conditions for each one.

Skipping the honest evaluation of fit. Building a graph for a genuinely open-ended, exploratory task because graph engineering is the newer, more rigorous-sounding framework, rather than because the task actually benefits from the tradeoff, produces a system that is harder to build than a loop and worse at the actual job than a loop would have been.

The Honest State Of The Evidence

Closing on the caveat this course opened with, because it matters more here than in most technical writeups. The three commitments described above are a real, carefully reasoned proposal, analyzed against 70 real systems to identify exactly where loops fail silently. They are not yet validated as delivering their promised benefits at scale in production, by the author's own explicit statement.

This does not make the framework worthless. It makes it a genuinely promising design worth understanding and experimenting with deliberately, tracking your own results honestly rather than assuming the theoretical argument automatically translates into practice. If you build a graph-structured system using this course, the single most valuable thing you can do is measure whether it actually reduces the specific failure modes it targets, unbounded retries, undetected mid-run plan drift, unaudited recovery decisions, against your own real usage, rather than assuming the improvement because the argument for it is compelling on paper.

That discipline, treating a well-reasoned framework as a hypothesis to test rather than a settled fact to adopt uncritically, is itself the actual meta-skill underneath everything in this course. Graph engineering, loop engineering, any named practice in this fast-moving field, is worth learning properly and worth testing honestly against your own results, rather than adopted purely because it has a name and a paper behind it.

Follow @cyrilXBT for updates on this framework as real-world implementations and results actually start to appear.

X Article
122212390.1K
Reading tools
Keep it forever

Create a free account to save everything you preview — private to you.

Preview another link

Works with X, Instagram, TikTok & YouTube.

One place for everything
Tweets, TikToks, Reels, Shorts & articles in one searchable home.
Media at your fingertips
Full-screen viewer for photos and video — save any post to your collection.
Actually find it later
Full-text search across everything you save.

More to discover

More from @cyrilXBT