cd /news/ai-agents/stop-blaming-the-model-when-your-age… · home topics ai-agents article
[ARTICLE · art-109922] src=dev.to ↗ pub= topic=ai-agents verified=true sentiment=· neutral

Stop Blaming the Model When Your Agent Repeats the Same Mistake

A developer argues that coding agents fail repeatedly because their loops treat the context window as the only memory, discarding evidence from prior attempts. The developer proposes an append-only decision ledger stored in SQLite, where agents record what they tried and the outcome, and replay this history before each new attempt. A minimal Python implementation is provided to demonstrate the pattern.

read6 min views1 publishedAug 25, 2026

Consider a typical coding-agent run. The model fixes an import error, the test suite passes, and the loop moves on to the next task. Twenty minutes later, a refactor reintroduces the exact same failure, and the agent approaches it as if it had never seen it. The model is not stupid; the loop is amnesic.

That distinction matters more than most agent postmortems admit. When a coding agent fails twice on the same problem, the default explanation is that the model is not good enough, and the default remedy is a bigger model or a longer prompt. A more accurate diagnosis is that the system threw away the only evidence that would have prevented the second failure: the record of the first attempt. There is a growing discussion about giving agents durable reasoning ledgers, and the pattern deserves more than a mention in an architecture post.

The root problem is that most agent loops treat the context window as their only memory. That design has three predictable costs:

A context window is a cache. It is fast and local, but caches are not durable state. The fix is not to make the cache bigger; it is to add a durable layer underneath it.

The pattern that keeps showing up in reliable agent systems is an append-only decision ledger: a small database where the agent records what it tried, why, and whether it worked. Nothing is ever rewritten; when a decision is reversed, the agent appends a new entry that points at the old one. That makes the ledger a debugging tool disguised as a database, because you can always answer the question "what did the agent believe, and when?"

Here is a minimal, runnable implementation in Python using SQLite:

import sqlite3
import time

class DecisionLedger:
    def __init__(self, path: str = "agent_ledger.db"):
        self.conn = sqlite3.connect(path)
        self.conn.execute(
            """
            CREATE TABLE IF NOT EXISTS decisions (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                run_id TEXT NOT NULL,
                ts REAL NOT NULL,
                kind TEXT NOT NULL,
                summary TEXT NOT NULL,
                detail TEXT NOT NULL,
                outcome TEXT
            )
            """
        )
        self.conn.commit()

    def record(self, run_id: str, kind: str, summary: str, detail: str, outcome: str | None = None) -> None:
        self.conn.execute(
            "INSERT INTO decisions (run_id, ts, kind, summary, detail, outcome) VALUES (?, ?, ?, ?, ?, ?)",
            (run_id, time.time(), kind, summary, detail, outcome),
        )
        self.conn.commit()

    def recent(self, kind: str | None = None, limit: int = 20) -> list[tuple]:
        query = "SELECT ts, kind, summary, outcome FROM decisions"
        args: list = []
        if kind:
            query += " WHERE kind = ?"
            args.append(kind)
        query += " ORDER BY id DESC LIMIT ?"
        args.append(limit)
        return self.conn.execute(query, args).fetchall()

The API is deliberately small: record

appends an entry, and recent

replays the last N entries of a given kind. That is enough to change how an agent loop behaves.

The loop change is small but structural. Before the agent writes a single line of code, it replays the relevant ledger entries and folds them into the prompt. After the attempt, it records the outcome. Here is the shape of that loop:

import uuid
from ledger import DecisionLedger

ledger = DecisionLedger()

def run_fix(task: str) -> dict:
    run_id = uuid.uuid4().hex[:8]
    history = ledger.recent(kind="fix", limit=10)
    context = "\n".join(
        f"- {summary} (outcome: {outcome})" for _, _, summary, outcome in history
    )

    prompt = f"Task: {task}\nPreviously attempted fixes:\n{context}\n"
    result = call_model(prompt)  # your agent's model call goes here

    ledger.record(
        run_id=run_id,
        kind="fix",
        summary=task,
        detail=result["patch"],
        outcome=result["test_status"],
    )
    return result

Two details matter. First, the replay is filtered by kind, so the agent sees only fixes and their outcomes, not the full transcript. Second, the record happens even on failure, because a failed attempt with a recorded error message is exactly what prevents the next attempt from repeating it.

Not everything deserves durable memory. A decision table that works well separates state that shapes future decisions from state that is only relevant to the current turn:

Persist in the ledger Keep in context only
Fixes that worked and why Current file contents
Tests that failed and the error text The diff under review
Commands with side effects Chatty tool output
Decisions later reversed Large generated artifacts

The rule of thumb is simple: if the next run would behave differently by knowing it, persist it; if it is just noise from the current turn, leave it in the context window.

The ledger pattern has a hidden requirement: the database has to survive between runs. If your agent loop runs on a throwaway container, the ledger resets every time, and you are back to amnesia. That is where a persistent free server becomes a real architectural choice rather than a marketing line.

A setup like MonkeyCode's free tier is relevant here for two concrete reasons. The free server option gives the ledger a home that outlives any single run, and the free model token allowance (10 million tokens at the time of writing) is enough to iterate on the loop itself without watching a meter. Disclosure: This article was prepared as part of MonkeyCode's product outreach.

I am not recommending the pattern because it is free; I am recommending it because the discipline it forces is the same discipline that free infrastructure rewards. When tokens are cheap, it is tempting to stuff everything into context and hope. On a constrained tier, you cannot afford hope, so you persist what matters and replay it only when needed. The constraint produces better agent engineering, not worse.

The ledger is not a memory system for every problem. If your agent needs semantic retrieval across thousands of documents, a decision ledger is not a vector database, and pretending otherwise will give you brittle keyword matches. If you are building a one-shot script that never runs twice, the ledger is pure overhead. And free tiers have rate limits and no uptime guarantees, so the ledger makes recovery possible, not automatic; you still need a supervisor to notice when a run stalls.

The pattern also assumes your agent loop is deterministic enough that replaying a decision changes behavior. If your prompts are so large that ten ledger entries are noise, start by shrinking the context, not by adding more memory. Check the current tier details of any free infrastructure before relying on it in production.

Most agent failures that look like model failures are memory failures. The model is not being asked to reason; it is being asked to reconstruct state that the system discarded. An append-only ledger is a cheap, durable correction, and it runs fine on free infrastructure.

If you want to see the pattern in a real loop, MonkeyCode's free server is a reasonable place to start, but the ledger itself is the part worth keeping. Run it on whatever persistent storage you already have; the code does not care where it lives.

── more in #ai-agents 4 stories · sorted by recency
── more on @sqlite 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/stop-blaming-the-mod…] indexed:0 read:6min 2026-08-25 ·