{"slug": "loop-engineering-is-a-pattern-not-a-feature", "title": "Loop Engineering Is a Pattern, Not a Feature", "summary": "Loop engineering, a technique where an AI model is called repeatedly in a loop to decide whether to continue, is being marketed as a product category by AI infrastructure vendors, but it is actually a basic programming pattern that can be implemented with simple functions, according to a post from the iii project. The post argues that using an LLM as a turn orchestrator for deterministic tasks like file list comparison is wasteful and error-prone, and that most orchestration should be handled by deterministic functions instead.", "body_md": "# Loop Engineering Is a Pattern, Not a Feature\n\nYesterday everyone was doing agentic map-reduce. Today everyone is doing loop engineering. Tomorrow someone will be selling you the next big thing, and the price of admission will once again be your money and your architecture.\n\nHere’s the cycle in the AI infrastructure world in 2026, in case you’ve\nmanaged to miss it: a useful technique emerges from practice, gets a name,\nand within a few weeks there are a dozen products where that technique is\n*the* feature. Each product is a walled garden with its own way of doing\nthings, its own configuration structure, its own opinions about what you can\nand cannot do. And to get the technique, you adopt the garden.\n\nDoing this around *loops* is especially bold, because a loop is about as\nbasic as programming constructs get. An agentic loop is: call a model, look\nat what came back, decide whether to go around again. That is not a product\ncategory! That is a `while`\n\nstatement.\n\nWith iii, loop engineering is something you *implement* from a pattern, not\na feature or a product that you have to buy or adopt net-new.\n\nThis post shows what that looks like.\n\n## The turn orchestrator, and the trouble with agentic orchestration\n\nThe centerpiece of every loop-engineering solution is the *turn\norchestrator*: the thing that runs a turn of the loop and exposes lifecycle\nhooks, such as on turn start, on tool call, on turn complete. These hooks are\nkey places where you attach your own logic.\n\nThere are multiple ways to implement the orchestration layer. Harnesses like Claude Code and Codex are fully agentic, meaning the AI model decides everything on every turn. If the model is the decision-maker for every single loop, that means a lot of LLM calls, resulting in latency and cost, but most importantly a degree of variance in the results it produces.\n\nLLMs are probabilistic. Imagine that you have a workload where the model is\nscanning a bunch of files for security vulnerabilities. To know that you’re\ndone processing all files, you may need to compare the list of processed\nfiles with the list of *all* files, and see if the lists are identical. Now,\nask one of the current flagship LLMs whether two lists of files are\nidentical, and sometimes you’ll get the correct answer — but some of the\ntime the answer will be wrong. As a result, an LLM-orchestrated loop that\nrelies on file list comparisons may finish too early, or too late, or not at\nall. Not ideal!\n\nFor open-ended work, using LLM as a turn orchestrator may be an acceptable solution because the benefits, such as the LLM being able to judge a fairly broad set of criteria to know whether a turn is done or not, outweigh the possible mistakes.\n\nBut the vast majority of the work being orchestrated won’t be so open-ended — it will be numerical and mechanical and rather straightforward. In such scenarios using an LLM to evaluate whether a loop is over is wasteful, expensive, slow, and inconsistent.\n\n## An alternative to fully agentic orchestration\n\nWe already have something that’s better than an LLM at judging inputs with consistency, speed, low cost, and high accuracy: functions!\n\nYou don’t *have* to use an LLM as a turn orchestrator 100% of the time.\nDespite what the currently most popular harnesses may have led you to\nbelieve, it is OK to not be fully agentic all the time.\n\nIn fact, *most* turn orchestration doesn’t need an LLM and instead are\nbetter off as a simple function.\n\nFollowing a file list example from above: if, in order to know whether you are done, you need to compare two lists of files and tell whether they are identical — most programming languages already have a suitable pattern in their standard library. Sort and compare. One or two function calls, superfast, basically free, and correct every time.\n\n## Orchestrating a turn with triggers and functions in iii\n\nFor the readers new to iii: it is an unreasonably simple approach to\nsoftware engineering. In iii, [everything is a Worker, a Function, or a\nTrigger](https://iii.dev/docs/understanding-iii).\n\nI used the iii harness, which works directly with these iii primitives, to set up a workflow that scans a GitHub repository for security vulnerabilities.\n\nIf I were using the LLM-driven orchestration that’s standard for other harnesses on the market, this would have generated extra LLM calls for each turn and added cost and latency. But in this example, iii uses a function to tell whether a turn is complete.\n\nI started with this prompt:\n\n```\nScan a GitHub repository for real security vulnerabilities and give me a live dashboard of the results.\n\nRepository and sub-tree: https://github.com/wonderwhy-er/DesktopCommanderMCP/tree/main/src/handlers\n\nWork out how to do this with whatever workers and coordination you have available — I'm describing the outcome, not the implementation.\n\nOutcomes I want:\n\nCover the selected tree (skip any vendored, generated, binary files, PDFs, images). Real, specific vulnerabilities only — each with file, line, severity, one-sentence description. No style nits. Scan in parallel so a large repo finishes quickly, not one file at a time. Persist every finding in a database so results survive and can be queried. Detect completion reliably on your own: know when every part has actually been scanned, mark the run finished, tell me the total — without me watching or polling. Present findings in a simple web dashboard, grouped by severity.\n\nProperties the solution must have (what makes it correct, not how to build it):\n\nKeep bulk data moving worker-to-worker; don't route it through this conversation. Make parallel units independent: no shared counter they race to update. Use fp::worker as needed. Use max. 5 sub-agents at any one time (there is a built-in limit). Use the State worker to record state, set up reactive hooks and do the scheduling - such as launching a new sub-agent when another sub-agent has completed its work and doesn't take up a slot anymore. Do not use cron for anything. The loop has to be purely reactive. All files indicated have to be reviewed. Reuse workers and UI that already do the job; don't rebuild what exists. Whatever runs the completion step needs permission to write results and the done-signal, not just read. Start now: discover what's available, decide the approach, write down the plan for what you'll do and let me approve before proceeding.\n```\n\nThe harness started by preparing a plan per my request, and in the process\nhad a look at all the workers available in the system as well as in the iii\nWorkers Registry. It discovered that there is a `database`\n\nworker available\nin the registry, but it isn’t installed. It added the worker into the system\nand started it in order to use the database.\n\nIn comparison, other harnesses would have spent a significant amount of tokens and effort selecting a database to use, adding that database, and then adding an SDK to use it plus producing all the integration code necessary to use the SDK. With iii, it took just a few seconds and a handful of tokens to add a worker and use it.\n\nThe harness then created the table to keep the discovered vulnerabilities, and kicked off work to create and serve a web interface over HTTP.\n\nNow to the scheduling: in the prompt, I specifically asked for the scheduling to be handled by triggers and functions rather than the LLM-level orchestration. The harness registered relevant triggers and achieved seamless, fast and cheap flow control.\n\nYou can see the reactions being logged in the main conversation as they happen:\n\nThe harness then analyzed all the files, with a sub-agent taking a batch of a few files, and inserted the results into the database I added earlier, then showed them through the UI.\n\n## Turning the exploratory session into a worker\n\nAs the next step after this initial analysis, I wanted to turn it into a more stable workflow that I can use from other sessions and as a larger part of my system — so I asked the harness to turn the scanner into a worker.\n\nIt did just that and tested it right there in the session. You can see the worker hot reload and join the system. What was once a one-off loop is now a reusable vulnerability scanner.\n\nI then started a new conversation and had the system use the newly created worker to do the analysis, with all of the orchestration happening seamlessly inside the worker:\n\nHere is the video walkthrough of the entire flow:\n\n## Walking down the LLM stack\n\nIn most cases, using functions for orchestration is the most efficient, most cost-effective, and most reliable choice.\n\nBut here is when it *makes sense* to use an LLM to orchestrate, and when iii\nwill do so.\n\nWhen you are building a workflow from scratch, it makes the most sense to start with an exploratory agentic session. You don’t yet know the shape of a problem, and a capable model is the fastest way to find that out. Let it be fully agentic initially. Watch what it does.\n\nBut exploration is a phase, and it shouldn’t be the architecture. Once you can see the solution, the job becomes moving as much of it as possible into deterministic code, because deterministic code is better by every metric: cost, latency, reliability, testability, debuggability. The question you ask on every iteration is:\n\n**What is the smallest part of this that still needs an LLM?**\n\nEverything outside that part gets walked down the stack:\n\n**Can I do this with code?** If yes, do that. It’s free, instant, and correct.**Can I do this with ML?** A classifier, an embedding lookup, a small fine-tuned model — if yes, do that. It’s cheaper, faster than an LLM, and its accuracy is more predictable.**Else, use an LLM**. The smallest one that works. Start with a frontier model like Fable while you’re exploring, then reduce: a smaller model, a cheaper provider, eventually maybe no LLM at all.\n\nEach step down is an order-of-magnitude improvement in cost and latency, and\na step *up* in reliability. A mature system built this way has LLM calls\nonly at the joints where genuine judgment is required, and deterministic,\nunit-tested functions everywhere else.\n\nWith iii, this progression naturally takes place as you move from an\nexploratory LLM session, into creating a worker that does things through\ncode *and* LLM calls, and progressing into more code and fewer LLM calls\nover multiple steps.\n\n## Why iii is the right system for this\n\nNobody else is set up to do such progressions from exploration into production code as robustly and thoroughly as iii, and the reason is structural.\n\nThe walk down the stack only works if the LLM version of a step and the code\nversion of a step are *interchangeable*. On iii, they are, by construction:\nboth are Functions, invoked by Triggers, hosted in Workers. When a\n`vulnscan::fetch-batch`\n\ncall stops being a Sonnet 5 call and becomes a\ndatabase query, nothing that calls it changes.\n\nThe small primitives pay off in the other direction too: they’re what make\niii systems reliable for LLMs to *use*. An agent operating inside a iii\nsystem has exactly three concepts to hold, one always-accurate live view of\nwhat exists, and function IDs that mean what they say. The same minimalism\nthat lets you walk logic out of the LLM lets the LLM operate what remains.\n\nSo the loop-engineering picture on iii ends up looking like this: a loop whose turns are controlled by triggers, whose validators are unit-tested functions, whose LLM calls are confined to the smallest parts that genuinely need judgment, and whose every component can be observed, tested, and swapped independently.\n\niii is open source. The docs are at [iii.dev/docs](https://iii.dev/docs).\nGive it a try today, and you won’t want to go back to other systems.", "url": "https://wpnews.pro/news/loop-engineering-is-a-pattern-not-a-feature", "canonical_source": "https://iii.dev/blog/loop-engineering-is-a-pattern-not-a-feature/", "published_at": "2026-07-29 14:49:17+00:00", "updated_at": "2026-07-29 14:52:33.902945+00:00", "lang": "en", "topics": ["artificial-intelligence", "ai-agents", "ai-infrastructure", "developer-tools"], "entities": ["iii", "Claude Code", "Codex"], "alternates": {"html": "https://wpnews.pro/news/loop-engineering-is-a-pattern-not-a-feature", "markdown": "https://wpnews.pro/news/loop-engineering-is-a-pattern-not-a-feature.md", "text": "https://wpnews.pro/news/loop-engineering-is-a-pattern-not-a-feature.txt", "jsonld": "https://wpnews.pro/news/loop-engineering-is-a-pattern-not-a-feature.jsonld"}}