The Files Are the Memory
The obvious way to run a long agent loop is to keep the conversation going — let each iteration see everything that came before. It's also why long loops rot. The best loops do the opposite: they throw the context away every iteration and keep their memory on disk.
Thesis: Accumulated conversation history is not an asset in a long loop — it's a liability that degrades the model measurably, and well before you hit the token limit. The durable pattern moves memory out of the context window and onto disk: each iteration starts from a fresh context, reads only what it needs from files, does one step, and writes its progress back. Compute is disposable. Memory is external.
This is Post 5 of "The Loop." Post 4 put the verifier in a fresh context. This post asks the natural follow-up: if iterations start fresh, where does the loop's knowledge live?
The Assumption That Backfires
It feels obviously right that more context helps. The agent worked on this task for the last twenty iterations — surely it should remember all of it? Keep the transcript, keep everything in view, let it build on its own history.
In a long loop, that intuition backfires. The accumulated transcript fills with things that actively hurt the next step: failed approaches it might retry, tool outputs that are now stale, reasoning it did under an assumption that's since changed, dead ends presented with the same visual weight as the live plan. The context stops being memory and becomes noise — and not harmless noise.
One subagent-loop harness names the problem in its own README: running everything in one growing session lets context accumulate in a way that undermines the original Ralph design — the one that explicitly said "the files are the memory." The fix they landed on: run "each iteration in a fresh-context subagent instead of accumulating in one session."
Context Rot Is Measurable
This isn't a vibe. It's measured. Chroma's Context Rot study (2025) tested 18 models — GPT-4.1, Claude 4, Gemini 2.5, Qwen3 and others. The study found performance degrades non-uniformly as input grows, beginning well before the context limit. A one-million-token window does not reliably reason over one million tokens. The old "lost in the middle" effect compounds with distractor interference: the more you stuff in, the more the signal you actually need gets buried.
flowchart TD
subgraph accumulate["Accumulating context"]
direction TB
A1["iter 1<br/>small, sharp"] --> A2["iter 10<br/>filling with dead ends"] --> A3["iter 30<br/>signal buried in noise —<br/>degraded reasoning"]
end
subgraph fresh["Fresh context per iteration"]
direction TB
F1["iter 1<br/>reads disk, acts"] --> F2["iter 10<br/>reads disk, acts"] --> F3["iter 30<br/>reads disk, acts —<br/>same sharpness"]
end
style A3 fill:#9d4444,color:#fff
style F3 fill:#2d6a4f,color:#fff
The implication for loops is direct. A loop is the one place where context grows without bound by default — every iteration appends. So a loop is exactly where rot does the most damage, and exactly where "just use a bigger window" fails most reliably. The window isn't the fix. Not filling it is.
The Inversion: Disk Is Memory, Context Is Scratch
The Ralph technique's core move — the one that survives everything else being stripped away — is that memory lives in files, not the conversation. A plan file. A spec directory. A progress log. Each iteration re-reads what it needs from disk, does one focused piece of work, writes the result back to disk, and ends. The next iteration starts clean and reads the updated files.
A framework I work with states the same thing as "a cycle inits blind: it reads only its Spec." The context window becomes scratch paper — used hard within an iteration, then thrown away — while the disk holds the durable state that crosses iteration boundaries.
flowchart LR
Disk[("Disk: durable memory<br/>plan · progress · ledger · decisions")]
Disk -->|"read what's needed"| Iter["Fresh iteration<br/>(disposable context)"]
Iter -->|"do ONE step"| Iter
Iter -->|"write result + handover"| Disk
Iter -.->|"context discarded"| Gone["∅"]
Disk -->|"next iteration reads<br/>updated state"| Iter2["Next fresh iteration"]
style Disk fill:#5a5a8a,color:#fff
style Gone fill:#9d4444,color:#fff
style Iter fill:#5a5a8a,color:#fff
style Iter2 fill:#5a5a8a,color:#fff
This is the loop-level version of externalizing knowledge out of the system that consumes it. There, knowledge moved out of the MCP server so it could evolve independently. Here, state moves out of the context window so it can survive the window being reset. Same principle: the thing that needs to persist shouldn't live inside the thing that's disposable.
And it doubles as a clean-room property. A fresh iteration doesn't inherit the last iteration's anchoring, its half-formed theories, or its failed attempts — it inherits only what got written down deliberately. That's the same reason subagents with fresh context catch what a marinated main agent can't. Reset is a feature.
What Goes on Disk
"Put memory in files" is only useful if you're disciplined about which memory. The loops that do this well converge on a small set of artifacts:
| Artifact | Holds | Why it survives the reset |
|---|---|---|
| Plan / spec | The goal and the approach | Each iteration re-derives intent from here, not from transcript |
| Progress log | What's done, what's next | The frontier; where the next iteration picks up |
| Ledger | Task states (todo/doing/done/blocked) | Machine-checkable "are we there yet" (next post) |
| Decisions | Choices made and why | Stops the loop from relitigating settled questions |
| Handover note | Mid-flight state at iteration boundary | Lets a fresh context resume without re-reading everything |
Anthropic's long-running-agent patterns use exactly this shape: an agent-maintained PROGRESS.md, auto-commits so each reset starts from a clean, known checkpoint, and compaction — summarize the context and reinitialize a fresh window, preserving the architectural decisions and open questions while discarding the redundant churn. Compaction is the bridge between the two worlds: it's how you distill a full context down to the disk-worthy essence before you throw the context away.
One discipline worth stealing, from a worker prompt I saw: "half a task with a great handover beats a truncated mid-edit." When an iteration is going to end, the valuable output isn't how much it did — it's how cleanly it wrote down where it stopped. Optimize the handover, not the mileage.
The Cost: You Have to Write It Down
Fresh-context loops aren't free. They demand a serialization discipline that accumulating loops let you skip. If a piece of state matters across iterations and doesn't get written to disk, it's gone at the reset — and unlike a dropped detail in a long transcript, it's gone completely. The failure mode flips from "buried in noise" to "never recorded."
So the tax is real: every iteration has to end by persisting its meaningful state, and the plan/progress/ledger files have to be trustworthy enough that a blind iteration can act on them. Practically, this also raises the value of before-you-reset triggers — the practitioner rule of thumb is to compact before the window is ~70–80% full rather than at the limit (that number is folklore, not from the Chroma paper — treat it as a heuristic, not a law). The point isn't the threshold; it's that you distill while the context is still coherent enough to distill well.
When to Just Keep the Context
Not every loop needs the disk-memory apparatus. Keep the running context when:
- The loop is short. A handful of tight iterations well under the rot threshold don't need externalized memory — the overhead outweighs the benefit.
- Every iteration genuinely needs the full history. Rare, but real — some tasks are inherently cumulative in a way that doesn't compress cleanly. Measure before assuming yours is one.
- You're exploring, not producing. A scratch session where you're figuring out the problem shape is fine to let grow; externalize once you know what's worth writing down.
The apparatus earns its cost as loops get long and unattended — which, again, is the direction the whole field is moving.
What to Do Next
- Move state out of the transcript. List what your loop needs to remember across iterations. Each item should have a home on disk — a file, not a place in the conversation.
- Make iterations init blind. Have each iteration read its plan and progress from files rather than inheriting a growing context. If it can't reconstruct what it needs from disk, that's a missing artifact.
- Compact before you reset, not at the limit. Distill the context to its disk-worthy essence — decisions, open questions, frontier — while it's still coherent enough to summarize well.
- Optimize the handover. Reward an iteration for a clean write-down of where it stopped, not for how far it pushed before the context died.
- Measure your rot. Don't assume a big window saves you. Check whether your loop's quality sags as context grows — it probably starts sagging earlier than you'd guess.
Next: The Loop Is a Ledger, Not an Orchestrator — that disk-borne state turns out to be the whole control system; the "loop" is barely there. Related: Externalize the Knowledge and Subagents: Fresh Eyes on Demand.