DEV Community

Cover image for Why Does Every AI Agent Still Look Like `while (true) { ... }`?

Why Does Every AI Agent Still Look Like `while (true) { ... }`?

tom on August 18, 2026

Open any agent codebase today — Claude Code, Codex, Pi, most of the open-source ones — and you'll find the same skeleton. Something like: let st...
Collapse
 
reidmarlow profile image
Reid Marlow

Event logs are the part most agent loops rediscover too late. Replay helps, but the bigger win is making interruption a normal event instead of a corrupt half-turn. I’d keep one boring invariant beside it: every tool effect needs an idempotency key, or replay can become a second execution bug.

Collapse
 
anasbuilds997 profile image
anassBld

Spot on breakdown. The standard while (true) loop is the biggest architectural trap in modern agent runtimes because it assumes the execution thread is permanent and all tool invocations are atomic.

The moment you have network timeouts, operator interrupts, or process crashes, an in-memory state object becomes a liability. An append-only event log solves the auditability and replay half of the problem beautifully.

In our agent state machinery, we ran into a critical nuance when pairing event logs with external mutations:

  • Pure reasoning events (planning, schema validation, prompt generation) can be replayed from the log deterministically at zero risk.
  • External mutation events (API POSTs, database writes, CLI actions) cannot simply be replayed on restart, because the previous in-flight process might have already committed the change before dying.

To bridge this, we attach deterministic intent fingerprints to every mutation event before dispatch. If a recovered worker replays the log and sees an unconfirmed external action, it doesn't re-invoke the tool—it enters an explicit reconciliation phase to verify whether the fingerprint already exists on the remote system.

In your event log runtime, how do you handle recovering an in-flight mutation event after a hard crash? Do you rely on provider-side idempotency keys during replay, or do you emit an explicit pending/unconfirmed event that triggers a readback check before the next step?

Collapse
 
publiflow profile image
PubliFlow

Moving from a synchronous polling loop to an event-driven architecture completely changes how you handle state mutations in AI agents. I have found that using an event log not only makes debugging hallucinations easier since you get a strict chronological trail of tool calls, but it also allows you to pause and resume long-running tasks without losing context. The tricky part usually comes down to handling backpressure when the LLM generates events faster than your downstream systems can process them. Have you experimented with how this event log approach scales when multiple agents need to subscribe to the same state changes concurrently?

Collapse
 
eduzsh profile image
Edu Peralta

The cracks you name show up the moment a coding agent leaves the demo and lives in a real session. Mutable state makes an interrupted tool call look like a finished turn, and the next plan then reasons over a lie. Treating the event log as the source of truth flips that: you can ask what the model actually saw, rewind to the last honest sequence, and replay without reconstructing a bag of objects by hand. Parallel tool calls and retries stop being special cases because they are just more events with cause links. The loop is fine for a weekend prototype. It falls apart the moment you need to explain why the agent did something three hours ago.

Collapse
 
eduzsh profile image
Edu Peralta

The event log as source of truth is the bit that held up under real debugging. Mutable loop state is fine until you need to answer what the model actually saw when it made a bad call, and then the bag of objects is already a reconstruction. Treating every tool result as an append only row makes retries, forks, and ignored errors into ordinary queries instead of special cases bolted onto the loop. Curious whether long sessions have forced snapshots yet, because rebuilding context from a long tail is the next tax that design usually pays.

Collapse
 
mnemehq profile image
Theo Valmis

The event log swap is the right fix and it's worth naming why: a while(true) loop treats state as the source of truth, so anything that happens outside a clean iteration, an interrupt, a hung tool, a parallel call, has nowhere honest to go. An event log makes the history the source of truth instead, which is what actually makes rewind and replay possible.

Collapse
 
alexshev profile image
Alex Shev

This is the kind of detail that belongs in an architecture decision record: the tradeoff, the rejected alternative, and the trigger for revisiting it. That context is what keeps future refactors from reintroducing the same problem.

Collapse
 
mickyarun profile image
arun rajkumar

You've rediscovered the ledger, and I mean that as the compliment it is. Payments went through this exact argument a long time ago and landed in the same place: never store the balance, store the entries and derive the balance. A mutable state object is a stored balance. It's a cache of history that has quietly stopped agreeing with history.

The part that made it click for us wasn't rewind or replay, useful as those are. It was that an append-only log makes "what did this thing actually see when it decided" answerable months later, by someone who wasn't there. With a mutable state bag that question has no answer, and in a regulated system "no answer" is itself the finding.

Where I'd push: the log only holds if every side effect is written before it's attempted, not after it returns. Write the entry on the way out and a call that times out leaves no trace of having happened. The one case you built the log for is the one case it's blank.

Collapse
 
subnetica profile image
Subnetica

Is there any kind of access control or anything built-in? Skimmed the codebase and couldn't find any. Seems like it pretty much just passes anything not recognized as a built-in command directly to the shell.

Collapse
 
_hm profile image
Hussein Mahdi

The one cli-to-shell tool is elegant but is also an unbounded RCE surface ; every event is auditable, sure, but auditing after the shell already ran isn't a guardrail.

Collapse
 
kartik-nvjk profile image
Kartik N V J K

The while(true) shape sticks around because most loops never had a real exit contract, they just call the model again until the output looks finished. Mine got stable once I scored every turn against a stop condition I could actually test, so a bad step failed loudly instead of spinning. The state-machine version you describe is what people pretend a raw while loop already does for them.