# Loop vs graph engineering: we built a graph, then deleted it

Source: https://dev.definable.ai/blog/loop-vs-graph-engineering
Published: 2026-11-05 · Definable team

We built a graph engine for our agents and deleted it 19 days later. What loop and graph engineering mean, what each cost us, and when a graph earns its place.

On 2026-09-28 we started building a graph engine for our agents. On 2026-10-17 we merged the pull request that deleted it: 13,689 lines gone across 271 files. The odd part: in our own tests, the graph's runs came out cheaper.

So, loop engineering or graph engineering? Start with one loop. Give it the limits a graph would have given you: a step cap, a cost cap, a pause for a person. Draw a graph only for a path your traces already show again and again. Whichever shape you pick, the part that fails is the check, not the shape.

We read 48 sources closely and set them next to our own numbers: test journeys for loop versus graph (a simulated developer, fixtures standing in for real tool results, one run each), and dev, our development server, for the loop in daily use.

## What do loop engineering and graph engineering mean?

Both names are months old. On 2026-06-07 Peter Steinberger, creator of OpenClaw, posted ["You should be designing loops that prompt your agents."](https://x.com/steipete/status/2063697162748260627) When we read it on 2026-11-05 it had about 8.7 million views. The post never says "loop engineering". Dan McAteer [named it in a post on X](https://x.com/daniel_mac8/status/2063721956034195785) within two hours: "It’s called Loop Engineering."

Boris Cherny, who created Claude Code, said it in one line, which Armin Ronacher put at the top of an essay: ["My job is to write loops."](https://lucumr.pocoo.org/2026/6/23/the-coming-loop/) Addy Osmani's post, dated 2026-06-07 like Steinberger's, is the first long definition we found: ["Loop engineering is replacing yourself as the person who prompts the agent. You design the system that does it instead."](https://addyosmani.com/blog/loop-engineering/) By 2026-06-26 Andrew Ng's newsletter was calling it [a hot buzzphrase](https://www.deeplearning.ai/the-batch/three-key-loops-for-building-great-software).

Then the graph. On 2026-07-18 Steinberger asked [whether we'd "shift to graphs yet"](https://x.com/steipete/status/2078277297791189132), and that post passed 3 million views. Two days later LangChain's Harrison Chase [posted on X about graph engineering](https://x.com/hwchase17/status/2079219804951683380): "So i didn’t really know what graph engineering is, and i still don’t really… but it’s basically just langgraph?" Mike Piccolo of iii counted it up: ["Four namings in three years."](https://iii.dev/blog/loops-graphs-and-the-layer-that-matters/) Prompt, context, loop, graph.

Strip the names and the choice is old. In a loop, the model (or a check) picks the next step until a stop condition. In a graph, you drew the steps and the edges in advance, like a choose-your-own-adventure book where the pages are fixed. Anthropic drew this line in 2024: [workflows are "orchestrated through predefined code paths"](https://www.anthropic.com/research/building-effective-agents), while agents "dynamically direct their own processes". Piccolo, whose company builds its own answer to all this, puts it shortest: [a loop is just a graph with one node](https://iii.dev/blog/loops-graphs-and-the-layer-that-matters/).

**Fig 1 · Same job, two shapes**

1. **A loop.** The model asks for a tool, reads the result and decides what comes next, until it says it's done or a limit stops it.
2. **A graph.** Check, hold, confirm, reply: the same job with the path written down. The model fills in text, not the route.
3. **Both.** Same job, same tools. The difference is who chooses the next step: the model, or the diagram.

*An example job, not a measurement. The loop decides its next step each turn. The graph's steps were decided before the run.*

## Why did we build a graph?

Here's the best case for it, and it's a good one. Our plan for the graph, dated 2026-09-28, started from one complaint: "A classic agent lets the model choose every step: which tool, which arguments, when to stop." That, it went on, makes the agent unpredictable and its cost unbounded. The fix was to move control flow out of the model and into a versioned graph, where the model writes text and makes bounded choices and everything else is code.

We built nine kinds of step (action, generation, condition, transform, decision, loop, wait, subgraph and explore), and every graph carried a budget: a maximum number of nodes and a maximum cost per turn. A run's path and its cost had a ceiling. The first real cases were a LinkedIn commenter and a clinic that books appointments over WhatsApp. One early receipt for the design: a pull-request reviewer's file picker read every patch, 192,633 tokens, to choose six file names. That's why the graph got a transform step, so each model call read only what it needed.

We weren't alone. LangChain, which has spent three years on graphs, says [real-world agent workflows often have "predictable structure"](https://www.langchain.com/blog/3-years-of-graph-engineering-with-langgraph).

And in our tests, it paid. This is a live journey with a simulated developer: a badminton court booker, agent on Haiku, 6.8 minutes, one run of each. The graph's eval suite (six cases) cost less per run, and the graph survived a rough crash test.

| Measure | Loop | Graph |
| --- | --- | --- |
| Suite cost | $0.056 | $0.032 |
| Cost to build | $0.58 | +$0.56 |
| Builder turns | 3 | +1 |
| Final eval pass rate | 1.0 | 1.0 |

The suite ran 43% cheaper ($0.032 against $0.056). The graph came after the loop, too: our Builder agent (the one that builds agents) spent 3 turns and $0.58 on the loop, then read the loop's good run and drew the graph from it in one more turn, for about $0.56 more.

In a separate journey we killed every worker with SIGKILL mid-run, cut the model provider for 20 seconds and made a tool fail. Every crashed run recovered, and nothing was posted or held twice. In those LinkedIn and clinic journeys we also compiled the graphs to plain code, which cut replayed traffic cost by about 4% (3.5% for the clinic).

## Why did we delete it?

In the first week of October we decided on one executor, open loop only. A graph agent's run now ends as failed with a clear error code. Three reasons, each with a receipt.

**We were running three engines.** Our plan for the change says the code split at one `if` into three engines: the open loop, the interpreted graph and compiled graph code. Below that line they duplicated run start and end, the model call and cancel, the budget, usage and checkpoint writes, and two unrelated ideas of "resume". There were three ways to queue a run. The goal we wrote down was that "an interface can be added without touching the executor." With three engines it couldn't be.

**The graph needed a loop anyway.** We decided on 2026-09-28 that the runtime never lets a model choose control flow outside a bounded Explore node, and Explore was a bounded classic agent loop for unknown territory. So even our design kept a loop for the part nobody could draw. Gao Dalie, who argues for graphs, says the same: [each important node may still contain a loop](https://medium.com/@GaoDalie_AI/forget-loop-engineering-graph-engineering-is-about-this-713a9cf2e985). And look at the table again: the graph was drawn from a loop run that already worked. The loop came first either way.

**A predictable path is predictably wrong.** The clinic graph never completed a booking in any version. It passed the patient's whole message to the hold-slot tool, which refused it. The graph routed that refusal to an apology. Our evals couldn't see the problem, because the fixtures matched any arguments.

**Fig 2 · Every case passed**

1. **Route.** The graph hands the patient's whole message to hold_slot as its argument.
2. **Refuse.** The tool refuses it. The graph sends the refusal to an apology.
3. **Pass.** The run exits ok, every eval case passes, and no booking ever happened.

*The clinic graph in our test journey. The path ran exactly as drawn, and exactly wrong.*

A graph is a map you drew before you walked the ground, and our checks were a map of the map. No signal counted the refusal. The clinic's satisfaction signal read 100% from the first version, because no simulated patient turned an answer down. None of them got a booking either.

We weren't first to turn back. LangChain, the graph vendor, wrote that it [built early deep research on predefined LangGraph workflows, then moved to a more agentic core loop](https://www.langchain.com/blog/3-years-of-graph-engineering-with-langgraph). A Claude article on folding subagents into one loop describes proposed designs with an intent classifier, a fixed pipeline and an orchestrator on top, and says [feedback is often that "most of this structure was doing work the model no longer needed done for it"](https://claude.com/resources/articles/building-agents-when-to-fold-subagents-into-your-main-agent-loop). The graph saved 2.4 cents per suite run. In exchange, run start, cancel, budgets and checkpoints lived in duplicate, and the graph package alone was 3,384 lines in 19 files.

## What does a loop look like in real use?

Our dev server ran 2,935 runs from 2026-10-12 to 2026-11-04 (IST): 2,053 chats, 854 evals and 28 tasks. That's a development server, not production. Dev's database starts after we switched the graph off, so it has no graph runs, and we can't compare the two on the same traffic.

| Per run | Median | p90 | p99 |
| --- | --- | --- | --- |
| Model calls | 2 | 13 | 26 |
| Tool calls | 1 | 17 | 61 |
| Cost | $0.026 | $0.79 | $5.60 |

Most runs are tiny. The median run makes 2 model calls, and 1,042 of the 2,415 successful runs (43%) called no tool at all. Then the tail. The p99 run costs $5.60, about 215 times the median. The most expensive run cost $18.91. The longest, at 61 model calls, were runs of our Builder agent, which has its own cap of 60 calls plus a last answer. All 2,935 runs together recorded $1,026.65 of model cost.

The tail is where graph people are right. A fixed path has a ceiling by construction, and a loop only has the ceiling you give it. But a graph isn't safe from it either. A developer on r/LangChain wrote: ["I just accidentally let a LangGraph agent loop on a broken tool over the weekend and woke up to a massive API token burn."](https://old.reddit.com/r/LangChain/comments/1unl0j7/woke_up_to_a_massive_api_bill_my_langgraph_agent/) LangChain itself says production agents need cycles, to retry failed tool calls, ask users for missing information and revise answers.

## How do you keep a graph's promises inside a loop?

A graph promised three things: a ceiling on path and cost, a person at the right step, and a run that survives a crash. A loop keeps the first with caps and the second with a pause. The third comes from the executor around it.

On Definable, agents run on this loop. A run stops at 25 model calls by default, then gets one last answer with its tool calls dropped. A run can carry a cost cap (our Builder agent's is $5), and no model call starts once it's spent. A run can pause for a person, with a question (`ask_user`) or an approval (`needs_approval`). And a run keeps at most 10 tool calls in flight.

Claude's own advice lands in the same place: [one model and one context window "running an open-ended tool loop, with limits (turn and cost budgets, write gates) set in the harness"](https://claude.com/resources/articles/building-agents-when-to-fold-subagents-into-your-main-agent-loop).

**Fig 3 · Four limits**

1. **Step cap.** The default is 25 model calls, then one last answer with tool calls dropped. On dev, 95 runs were halted by it.
2. **Cost cap.** No model call starts once a run's cap is spent. On dev, 8 runs were stopped by a $5 cap.
3. **Pause.** A run can stop and wait for a person's answer or approval.
4. **Parallel cap.** At most 10 tool calls in flight at once.
5. **All four.** The graph's ceiling on path and cost, kept inside one loop.

*The graph's ceiling, kept in the loop. Halt counts are from dev, 2026-10-12 to 2026-11-04.*

The caps fire. Of 188 halted runs on dev, 95 hit the step cap and 8 hit the $5 cost cap. People stopped 68 chats, and our eval grader stopped 17 eval runs, most of them waiting on a question nobody would answer. Crash recovery lives one level up: the run's row is the queue, a worker holds it on a lease, and a run whose lease runs out is claimed again. We haven't rerun the SIGKILL test on it for this post.

Here's what we still miss. We don't detect repeated identical calls. Of 802 dev runs with 5 or more tool calls, 119 (15%) made one exact call three or more times, and 68 made one five or more times. The most was 24 identical calls in a single run. Not all of those are stuck: a browser snapshot with the same arguments can read a page that changed. But of the 95 runs the step cap halted, 50 had made one exact call three or more times. The cap stops them, late.

A commenter on that LangChain thread describes the fix as [hashing the tool name and arguments on each call and breaking when they repeat](https://old.reddit.com/r/LangChain/comments/1unl0j7/woke_up_to_a_massive_api_bill_my_langgraph_agent/), with the recursion limit as the quick brake. We'd add that next. It isn't built yet.

## When should you draw the graph?

Six rules, in the order we'd apply them.

1. **Start with one loop and its limits.** A step cap, a cost cap and a pause for a person. Anthropic's advice is [to find the simplest solution possible](https://www.anthropic.com/research/building-effective-agents), and Gao Dalie warns that adding a graph too early only increases complexity.
2. **Draw a graph for a path your traces show again and again.** [Otium's example](https://getotium.ai/blog/graph-engineering) is a nightly job: "a pipeline with a fixed shape and a lot of items." If you can't point at the traces, you're guessing the shape.
3. **Freeze only what a check can verify without a model.** Fluxtion puts it well: [where the graph is closed, stable and operationally important, coordination can become compiler output](https://fluxtion-playground.dev/blog/2026-07-29-graph-engineering-needs-a-compiler). Our compiled versions were cheaper than the interpreted ones, but the shape was the same.
4. **Leave a loop inside for the part nobody can draw.** Our own design kept Explore, and Fluxtion says the same: [where topology is genuinely dynamic, runtime orchestration is appropriate](https://fluxtion-playground.dev/blog/2026-07-29-graph-engineering-needs-a-compiler).
5. **Give every edge a check that can fail, and keep it out of the agent's reach.** Gábor Mészáros argues the axis that decides whether a check survives is [editable versus read-only](https://dev.to/reporails/loop-engineering-how-to-stop-your-agent-reward-hacking-its-own-checks-4fpn). Our clinic evals couldn't see the bad argument because the fixtures matched any arguments.
6. **Run one engine.** A graph should be data the same runtime walks, not a second runtime. That one is our opinion, from the three engines we ran.

The skeptics are half right. Fabio Akita says a verifier checking objective evidence has [a fifty-year-old name: "tests and code review"](https://akitaonrails.com/en/2026/08/18/hot-take-harness-loop-engineering-graph-engineering-are-bullshit/). A Reddit commenter says loop engineering is just [scheduled jobs and event triggers](https://old.reddit.com/r/AI_Agents/comments/1uvq0nh/can_anyone_explain_me_loop_engineering_like_im_5/) that make an agent go "brrrr". The new part is only that a model now picks the steps, which makes the checks matter more.

LoopGain's README, a vendor testing its own tool, reports that [4.5% of converged runs (16 of 355) passed every check it ran](https://github.com/loopgain-ai/loopgain) and still failed the full held-out test suite. In its words, LoopGain "is only as right as your verifier". Our clinic was the same failure, smaller.

## So: loop or graph?

Let the loop find the path. Draw the graph once you've watched it walk it. Either way, spend the real effort on the check, because the shape was never the part that failed. If you build agents on Definable, that's the loop they run on, with the step cap on by default.
