Reasoning Loop Design in Coding Agents
Separate your LLM from the harness to build coding agents that work reliably in production.

Here's the simplest way I can put it: a reasoning loop is just a cycle. The agent thinks, does something, sees what happened, and thinks again. It keeps going until it hits its goal or runs out of runway. That's it. Everything else is implementation detail.
That cycle has three moving parts.
- The core reasoning engine. The LLM. It reads the current situation, interprets the goal, and picks the next action.
- The planning module. What breaks a big, vague goal into concrete steps. Sometimes this is chain-of-thought reasoning happening inside the model. Sometimes it's structure built into the surrounding code.
- The tool use module. The agent's hands. File reads, terminal commands, API calls, test runners. Everything that actually touches the world.
State is the glue holding it all together across iterations. In a coding agent, that means the file tree, prior tool outputs, open buffers, accumulated errors. Every pass through the loop adds to it.
The distinction that trips up most teams: the LLM and the harness are separate concerns. The LLM supplies intelligence. The surrounding code, the harness, supplies reliability. It handles errors, manages budgets, cleans up observations before they enter context, and decides when to stop. Teams that blur this line end up with agents that are smart in demos and unreliable in production.
There's also a structural split between the inner loop and the outer loop. The inner loop handles execution step by step. One tool call, one observation, next action. The outer loop handles the bigger question: is the overall goal still on track? Does the plan need to change? Is the cost budget about to blow? These are genuinely different jobs. Blending them into one undifferentiated cycle is a design error that compounds quietly for weeks before it becomes obvious.
The mental model that actually matters: the model is one component inside the loop. Not the conductor. One instrument. Most prompt-centric thinking misses this, which is why prompt-centric thinking only gets you so far.
The Main Loop Architectures and What Each One Optimizes For
There are a few dominant patterns. Each one is, basically, a response to the limitations of the one before it.
ReAct: The Baseline
ReAct (Yao et al., 2022) is what most coding agents still build on. The structure is almost embarrassingly simple: thought, action, observation, repeat. The agent reasons in natural language, calls a tool, reads what came back, and reasons again.
And it works. Interleaving chain-of-thought with grounded tool actions makes behavior legible. For sequential, well-scoped tasks, it performs reliably.
Where it struggles is complexity. One tool call per turn breaks down when you need branching logic, variable reuse across steps, or multi-tool compositions. The loop gets long. Context gets heavy. The model starts losing the thread somewhere around turn 15 and the whole thing quietly falls apart.
Plan-Then-Execute: The Predictability Fix
This architecture puts a hard wall between planning and doing. A reasoning model decomposes the goal into concrete subtasks before any execution begins. A separate execution layer then runs those subtasks, potentially in parallel.
The benefits are real. Independent branches can run simultaneously. Tools can be scoped per subtask, which matters for security. The plan is legible and auditable before anything runs, which your future self will appreciate during post-mortems.
The problem is that upfront plans go stale. If the environment changes mid-execution, say a test fails in an unexpected way or a dependency is missing, re-planning adds latency and cost. Predictability has a price.
Reflexion: The Self-Correction Layer
Reflexion (Shinn et al., NeurIPS 2023) adds memory and self-critique to the loop. After a failed attempt, a reflection module generates a verbal summary of what went wrong. That summary gets stored and injected into the next trial.
The benchmark numbers are real. 91% pass@1 on HumanEval versus an 80% baseline. That's not nothing.
But the caveat matters as much as the headline. Self-correction where the model is judging its own output without any external signals is fragile. The gains hold only when reflection is grounded in something concrete: execution results, structured critics, or process reward models. A model that just thinks harder about why it failed, without a genuine external signal telling it something went wrong, will rationalize. It won't correct. It'll write a confident paragraph explaining why the broken code is actually fine.
Reflection is most useful at multiple checkpoints: before execution to check whether the goal is even feasible, during execution to evaluate each step, and at the end to verify completion. Slapping it on only at the end leaves most of the value sitting on the table.
CodeAct: The Action-Representation Shift
CodeAct (Wang et al., ICML 2024) reframes what an "action" even is. Instead of emitting a JSON tool call, the agent writes executable Python. One code block can compose multiple tool calls, branch conditionally, reuse variables, and handle multi-step logic in a single pass.
The CodeAct paper's benchmarks show meaningfully higher task success rates and fewer total actions compared to ReAct on complex tasks. OpenHands, SWE-agent, and Voyager have all adopted variants of this approach.
The tradeoff is non-negotiable. Running arbitrary generated code requires strict sandboxing, resource limits, input validation, and audit logging. These aren't optional hardening steps you add when you feel like it. They're load-bearing architecture from day one.
Agentic Programming: The Architectural Critique
A more recent framing (arxiv, June 2026) makes a sharper argument: the problems all of the above architectures share, token explosion, control-flow hallucination, and unreliable completion, are not bugs. They're architectural consequences of asking a probabilistic system to handle deterministic work.
Looping, branching, sequencing. These are deterministic operations. LLMs are probabilistic. When you hand control flow to the model, you get inconsistency exactly where you need reliability. It's like asking your accountant to improvise your tax return. They understand numbers. The output will still not file cleanly.
The proposed fix inverts the relationship: the program owns all control flow. The LLM gets called only where reasoning or generation is genuinely required. They call this LLM-as-Code. It's not mainstream yet. But it names the ceiling that the other architectures keep running into, which is useful even if the full solution is still being worked out.
How Loops Handle Tool Use and Why It Is Harder Than It Looks
Tool use is where the loop stops being abstract and starts touching things that actually break. File reads, terminal commands, API calls, test runners. Each one returns an observation that shapes the next reasoning step. Each one is also a new way for things to go sideways.
The first problem is parsing. In ReAct, the agent's output is natural language that the harness has to interpret. In structured tool-calling, the model outputs a function-call object. Structured is more reliable. The cost is that it hides the reasoning chain, which makes debugging genuinely harder when something breaks in production at 2 a.m.
The second problem is observation curation. Raw tool output fed directly into context is a reliability hazard. Log files, full diffs, and stack traces can run thousands of lines. Feeding them unfiltered into the prompt bloats context and degrades reasoning quality. Cleaning, truncating, and summarizing tool outputs before they enter context is a harness responsibility. Not something you hand off to the LLM and hope for the best.
The three most common tool-level failures in production:
- Context window overflow. The tool returns more data than the model can process. Simple to understand, surprisingly common.
- Tool timeouts. An external API blocks the agent indefinitely. Without a timeout and circuit breaker, the loop just sits there burning tokens and money.
- Reasoning loops. The agent repeats the same tool call without making progress. No external failure, no error. The loop is running. Nothing is happening.
CodeAct's structural advantage in multi-tool scenarios is that one code block can compose multiple tool calls with branching logic, replacing many sequential turns with a single executable action. Fewer turns means less accumulated context drift, which turns out to matter a lot.
What good tool integration actually looks like: retry limits per tool, clear failure reporting after a defined number of attempts, and circuit breakers that surface failures to the outer loop rather than silently retrying until the context fills up and the model loses its mind.
The Failure Modes That Derail Loops in Production
These failures share a common thread: they all come from loop design, not model capability. A stronger model running a poorly designed loop hits the same walls. Just faster and more expensively.
Context Rot and Token Explosion
This is the most common production failure. Each iteration appends code changes, error messages, and prior attempts to the conversation. The prompt grows. Eventually the model is reasoning inside its own noise, treating its own earlier mistakes as ground truth.
A concrete example: a Gemini 1.5 Pro coding agent handling a complex cellular automata task produced hundreds of lines of simulation output. The context grew past the 1M token limit and crashed with a hard 400 INVALID_ARGUMENT error. Not a model failure. A context management failure. The model didn't run out of intelligence. The harness ran out of space.
The subtler version is that earlier failures and rejected approaches stay in context and actively pollute later reasoning. The agent starts making decisions based on a conversation that no longer reflects what's actually true about the codebase. It's like trying to solve a problem while someone reads your old failed attempts out loud into your ear.
The Dumb Zone
Giving the agent the full repository introduces a related problem. The model conflates unrelated modules and produces "global fixes" that touch code it was never asked to change. Output quality degrades measurably with context length. Practitioners call this the Dumb Zone. Better prompting doesn't fix it. Explicit context scoping does.
Infinite and No-Progress Loops
Without progress detection, the loop enters a kind of stuck state. Small changes that don't solve the problem. Re-introducing issues it already fixed. The loop keeps moving, technically, but nothing improves.
Agents terminate without actually achieving success in roughly 30% of cases. That's not an edge case. That's a design problem running at scale.
Premature Exit and False Completion
The agent declares done because it has no immediate complaints. Not because it verified the goal. Without explicit, testable success criteria defined before the loop starts, subtle bugs pass undetected. The developer ships something they believe the agent verified. They're wrong, and they won't know it until a user finds it.
What Well-Engineered Loops Do Differently
Five things. They work together, and skipping one weakens the rest.
First, a specific goal with testable termination conditions, defined before the loop starts. Success gets verified by automated checks, not by the agent's own assessment. The agent declaring victory is not a stopping criterion. It never should have been.
Second, a curated, minimal tool set scoped to the task. Not every available tool. Scope creep in tool access is a reliability problem and a security problem at the same time. Give the agent what it actually needs for this specific task, nothing more.
Third, active context management. The harness summarizes and compresses. It doesn't just append. This is infrastructure work, and it pays off across every single iteration of every run you'll ever do.
Fourth, explicit failure exits. A hard iteration cap. No-progress detection, meaning exit if the output state hasn't changed across iterations. A hard token and cost budget per run. Any loop missing these will eventually fail in production, just at a time you can't predict and probably can't afford.
Fifth, error handling that produces genuine adaptation. Not retries of the same failed approach. A strategy change. Or a clean escalation to the human. The loop needs to know the difference between "try again" and "try something completely different."
The Ralph Loop Pattern
For long-running tasks where context rot is the primary risk, the Ralph Loop pattern is worth understanding. Each iteration starts the agent in a fresh context window. State carries forward through files or persistent artifacts, not conversation history.
The real cost: the summarization step that compresses completed work into external state is lossy. Variable naming rationale, rejected approaches, implicit constraints the model inferred from earlier tool outputs. These get discarded. For tasks where continuity matters more than context freshness, this is the wrong pattern. For tasks where the loop needs to run across many iterations without degrading, it's often the right call.
Inner and Outer Loop Discipline
Applied practically: the inner loop executes the current subtask. It handles tool calls, manages observations, and advances toward the next concrete deliverable. The outer loop asks whether the overall goal is still on track, triggers re-planning when it isn't, and enforces the cost budget across the full run.
Keeping these two separate is how you build a loop that can recover from mid-task failures without losing sight of what it was actually trying to accomplish in the first place.
Visibility as a Prerequisite for Control
Teams cannot tune a loop they cannot observe. Execution traces, token counts per iteration, and tool call outcomes need to be surfaced somewhere useful. Not buried in logs that nobody reads until something already broke. This sounds obvious. It is surprisingly rare in practice, and I have seen smart teams waste days debugging loops that had the answer sitting in a log file nobody checked.
What Loop Design Means for Teams Deploying Agents at Scale
One developer experimenting on a local codebase has a limited failure surface. A team running agents across a shared codebase does not. A loop that drifts or makes global fixes on one developer's machine can silently touch shared modules when you scale it up. The blast radius isn't proportional. It's multiplicative.
Guardrails that are optional in solo use become mandatory at team scale. Cost budgets. Context scoping. Audit logs of tool calls. Defined escalation paths when loops stall. These aren't paranoid additions. They're the minimum for operating safely in a shared environment.
Model choice and loop design are also more coupled than most teams account for. The same loop architecture behaves differently across models. Teams locked into a single vendor's model can't isolate whether a loop failure is a model problem or a harness problem. That ambiguity is genuinely expensive when you're debugging production failures and your on-call engineer has been awake for six hours.
The core argument from the Agentic Programming critique holds regardless of where model capabilities go: deterministic control-flow logic belongs in the harness, not inferred by the LLM. Models will keep improving. Probabilistic systems will still be probabilistic. That's not a knock on the technology. It's just how the math works.
The 2025 Stack Overflow Developer Survey found roughly 84% of developers already using AI tools. Most of them are prompting, accepting suggestions, running the occasional agent in an IDE. The teams that extract reliable, scalable output are the ones who stopped treating loop engineering as an afterthought: termination conditions, observation curation, context management, explicit failure exits. Everyone else keeps getting demos that look great and fall apart under real load.
The honest open question in this field is how much of loop design can itself be automated. Goal decomposition, termination condition generation, context summarization. Some of this is already being handed to models. But the judgment about what success actually means, and whether the agent genuinely achieved it, still requires a human who understands the goal. That's not a gap that closes automatically as models improve. It's a design responsibility that lives with the team building the loop, and that's exactly where it should stay.


