Context Rot: Why Claude Code Sessions Decay, and How to Govern Them

The context window is a core feature of every frontier model. Measured in tokens, it is typically made up of the system prompt and a growing history of prompts, responses and tool calls stretching back as far as the limit allows.
For every token the model generates, it first looks back across the entire context window. This is the only mechanism by which it has memory of a chat session. The model holds no persistent internal state from one turn to the next. And as we will see, the context window is not passive storage. Everything in it has the potential to shape the model’s output, for better or worse.
This is a common experience: a session that starts strong and slowly loses the thread. The gradual decline in a model’s output quality driven by the contents of the context window is commonly referred to as context rot.
We can separate the sources of context rot into two categories. The first is intrinsic rot: a property of how a model applies attention across the context window as it generates output. We’ll go into more detail below, but for now the key takeaway is this: however perfectly relevant the context is, the model’s ability to recall and distinguish information is imperfect.
The second category we call content rot. This is the accumulation of stale, wrong and contradictory information across a session. The failed approach the model keeps going back to, or the dozen tangential tool calls that went nowhere. All of it repeatedly reprocessed, slowly shaping the outcome of the session.
Fortunately, unlike intrinsic rot, content rot is ours to manage – where learning to control it transforms tools like Claude Code from occasionally frustrating to consistently sharp.
Intrinsic rot: the model floor
Intrinsic rot refers to the performance limitations inherent to the model’s architecture. It is not ours to prompt around or improve; it is the floor everything else rests on. But the mechanism is worth understanding for two reasons: it explains the motivation behind some of the practices described later in this post, and it helps dissolve the illusion that there is a little engineer back there quietly accumulating an understanding of your project. (For a full walkthrough of attention, 3Blue1Brown’s lesson is excellent.)
Each turn, your entire session (prompts, responses, file reads, tool outputs) is flattened into one long sequence of tokens and passed through the model. LLM architecture is complex, but attention heads are the component that matter most for context. Each head answers a single question: how much should each token draw on every token before it? A relevant token contributes heavily to the next prediction; an irrelevant one contributes little, but never nothing.
That “never nothing” is the crux. Each head’s relevance scores pass through softmax, a function that forces scores to sum to one. This means there is a fixed budget of attention. Because softmax is built on exponentials, no token’s share of the budget can ever reach exactly zero. Every token in your window, however irrelevant, competes for the same fixed budget. This is no implementation accident; softmax is central to attention precisely because it turns competing scores into a smooth, learnable distribution. But, that useful property reflects a tradeoff: irrelevant context is never free. To be clear, dilution is only one of several leading explanations for long-context degradation. And models do learn partial workarounds, offloading spare attention onto throwaway positions, but these are mitigations, not escapes.
The consequence of this is subtle. As context grows, the model may still rank the right tokens highest; the ordering survives. What erodes is the margin: the gap between the token that matters and the diffuse mass of everything else. Even when the model “knows” where to look, the read arrives blurred, mixed with thousands of faint contributions from the surrounding window. Think of it as dilution: a fixed budget spread ever thinner, worsening signal-to-noise.
The stated context limit is not a performance cliff; the erosion is gradual, and it starts early.
Position matters too. Word order is fundamental to language, so models encode where tokens sit (open models typically via rotary positional encoding; closed systems rarely disclose). The exact mechanism matters less than the measured consequence: place a fact at varying positions along a long context and retrieval accuracy traces a U, highest at the very start and very end, lowest in the middle (Liu et al., 2024). The exact cause is still debated. What matters for us is the dip: in an hours-long session, the broad middle is where most of your real content lives, and it is not safe storage.

These are known as needle-in-a-haystack benchmarks. For the simple case, vendor curves are relatively flat and essentially solved. Make retrieval only slightly harder, stripping the easy word-overlap between question and answer so the model has to match on meaning (NoLiMa, Modarressi et al., 2025), and the drop arrives far earlier than the headline limit suggests. When holding several pieces at once and reasoning across them: performance degrades well inside the stated window even with perfect retrieval and every distractor stripped out (Du et al., 2025). A model that can find a fact at 100k tokens cannot necessarily think with it there.
So, the working assumption for anyone trying to get work done: your useful context budget sits well below any stated limit.
Content rot: how sessions degrade
This section is about the content loaded into context during a session. Earlier we described content rot as our domain of control. While this is true, in practice a session has multiple actors: us, the model, and any subagents spawned along the way.
The extent of autonomy we allow is typically governed by a set of permitted commands: grep a project workspace, pull from a remote git repository, MCP access to a company knowledge base. A loose leash of autonomy is the point of these tools; it is where the productivity comes from. As we walk through the various failure modes that lead to content rot, the aim is not to shorten the leash, but to recognise that we are still the best error correction in the loop: to catch the overly broad file read, the error being circled that is really a missing config, and stop the cycle before the damage is done.
Your session is a feedback loop. With each turn, everything in the model’s context window, every file read, tool output and failed attempt, is fed back through the model, shaping what it produces before being folded into the next token. Output becomes input. A clean step adds a clean line; a confused step adds a confused one, while the model continues to condition on its own confusion. The error persists and feeds forward.
The four failure modes that follow are Drew Breunig’s taxonomy of context failures (confusion, clash, distraction, and poisoning), from his post How Long Contexts Fail, here grounded in the day-to-day of agentic coding sessions:
Loading too much into scope (confusion).
It is becoming increasingly common to front-load each session with an ever-growing roster of tools, skills, and MCP servers. This makes sense in isolation: dedicated tools with specialised instruction sets can be highly efficient and perform well. But ever notice a model reaching for a tool to perform the most menial tasks, or even the wrong tool? Worse, a bloated apparatus not only confuses tool selection (Kate et al., 2025), but adds input on every turn, where we already showed reasoning to degrade with input length well below the stated limit (Levy et al., 2024; Du et al., 2025).
Faced with a task, a model with many tools tends to reach for them anyway, even when its own knowledge would do: a measured tendency to invoke tools to paper over reasoning gaps (Zeng et al., 2026). In plainer terms, even the idle tool is not free: its definition sits in the window on every turn, taking a slice of the attention budget whether you call it or not.
Letting a debugging detour set the theory (clash).
Ever find yourself working hard to convince a model that its diagnosis is wrong, while it bends new contradictory observations towards an assumption that no longer makes sense, only to return to that same point after the task is already solved? The effect has been measured: models commit early to a reading and struggle to let go of it. Tasks they solve cleanly when handed everything in one pass, they fumble once the same information arrives muddled across turns (Laban et al., 2025). The diagnosis here is that the path itself can become sticky.
Searching broad and pulling in look-alikes (distraction).
When the agent greps wide or dumps a directory to find the thing it needs, it pulls in test fixtures, dead implementations, mocks and similarly named functions from unrelated modules, all of which look plausible. The trouble is that models weight the window heavily: they do not treat context as optional reference material, but reliably incorporate it, even when it is irrelevant (Shi et al., 2023). A single topically related distractor is enough to measurably drop performance (Mirzadeh et al., GSM-Symbolic, 2024), and a codebase is full of them. The model over-focuses on what the search dragged in, at the expense of the reasoning it would have done cleanly without it. This ties straight back to the floor: the margin between the target and its near neighbours collapses, and a search meant to clarify instead populates the window with convincing alternatives the model cannot help but attend to.
Letting a wrong note harden into truth (poisoning).
This is particularly prevalent on long-running tasks. Often it follows from good intention: as the project grows and the decisions pile up, the agent records what it has found in a NOTES.md, or a series of named files tracking steps taken and work done, meaning to provide useful future context. Later you spot one of those assumptions in the live chat and it is wrong. You interrupt, correct it, move on. But the note was never updated. It sits in the file, gets read back later, and can outlive your chat correction. Once the correction slides out of the window, the stale file is the version that remains. A note the model wrote is not evidence; it is a claim waiting to be confirmed. The failure mode is stale state, not state itself.
To Breunig’s four modes I would add the compounding. Each feeds the next: a wrong note in a file sends the agent searching for a fix that was never needed, the search drags in a pile of plausible look-alikes, those mislead it towards a fresh wrong theory, and a debugging detour spawned to sort it out lays down another. Each turn conditions on the accumulated mess of the last, and the mistakes do not just add up; they make the next more likely.
This leads to a more subtle point: the model rarely hedges as it degrades. Following a wrong turn, it builds on the error rather than flagging it. (Laban et al., 2025), and a session deep in rot can read like a healthy one right up until the output breaks. You can’t rely on the model to call time on itself, so an outside observer is still required for the best outcomes.
If the real limit is content quality, then managing context becomes less about saving tokens and more about recognising the pattern and changing future behaviour.
Managing context: the everyday practice
The practical rule is simple: context is not storage. It is active input. Everything below is framed around Claude Code, the tool I know best, but each practice is a principle first: the guidance carries over to any agentic tool, even where the command names differ.
Before the first prompt: curate
If it is not already clear, a fresh start is worth more than any recovery path later. This is what makes the upfront work worthwhile: a well-curated project (a tight CLAUDE.md, the right skills and hooks) makes a fresh session cheap to spin up. The cost is paid once, deliberately, so that every reset after is close to free.
Most people will be familiar with the CLAUDE.md file. Every session starts by reading this file, and it is carried through each turn. This is why it pays to be ruthless when editing: every line earns its place, and bloat is cut. A useful framing is to treat it as the minimum required reading for a new engineer on day one. Specifically, what could they not work out by reading the code alone: the build and test commands, the shape of the project, the conventions you actually hold to, the gotchas. Leave out anything the model can infer, anything that changes often, and anything only sometimes relevant. /init gives you a useful starting point to prune, aggressively.
Keep the context that is always loaded minimal and high signal. General knowledge is readily recalled by the model and is wasted as context, where it only adds to the dilution we met earlier. Keep the window for what is specific, novel, or changed since training, and lean on the model’s own knowledge for the rest.
What you cut does not need to be wasted; move it somewhere that loads only when required. Procedures and domain knowledge become skills, whose content sits dormant until invoked. Rules that must hold every time (formatting, a blocked command) become hooks, which run outside of your main session context. Make capturing these a habit: noting useful information costs far less in the moment than reconstructing it after the fact.
Audit what you put in scope. We have seen how a crowded tool space drops performance. Run /mcp or /skills and disable the servers or skills a new task does not need.
Seed with what narrows, not what is related. If you know the relevant files, name them with @path/to/file.
Let it plan before it writes. A wrong plan costs a paragraph and is a cheap fix. Shift+Tab into plan mode, or /plan, for anything touching more than a couple of files.
While you work: keep it clean
Keep the goal recent. We know the middle of a long context window is where model recall is least reliable. On longer tasks, refresh the session goals at each milestone: restate the current objective, live constraints, and a short running task list for the agent to rewrite.
Push verbose work out to subagents. A test run, a log trawl, a dependency audit: anything that generates a wall of output you do not need to keep. We only need the conclusion.
Externalise durable state, and keep it true. A notes file the agent maintains lives outside the window and survives a reset; anything that must persist across sessions can live here. But be intentional: a stale memory is worse than none. It can outlive the correction you made in chat and re-enter later as apparent ground truth.
Return to ground truth, and make it a habit. Check against the file, the test, the actual error, not the model’s memory of them. The ! prefix runs a shell command and drops its real output straight into context, so !git status or !npm test grounds the session again in what is actually true rather than what the model recalls. If you find yourself doing this often, make it your own: a small skill that injects your project’s real state (the git status, the test result, the type check) in one go.
When it turns: reset, don’t push
This is the hardest guidance to follow; at this point your history of turns feels like progress you would be throwing away. That is the sunk cost fallacy: those tokens are spent whether you keep the window or clear it, and the only question is whether the next turn starts from a rotten context or a healthy one.
Two corrections on the same point is the signal. When you have told it twice that the bug is not in the auth layer and it keeps circling back, stop. Reset.
Catch it mid-step if you can. If you see it heading the wrong way, Ctrl+C and redirect rather than letting a bad change land and pile up. If it already has, Esc+Esc opens rewind: roll back the conversation, the code, or both to a prior checkpoint.
Regenerate, don’t carry forward. For self-contained, re-derivable work, regenerating the result in a clean session often beats a distilled history. The effect is sharpest once an attempt has already gone wrong. In Letta’s Recovery-Bench, agents handed the full history of their failed attempts did worse than those starting clean, the rotten context actively dragging down recovery rather than informing it.
When to act, and what to carry forward, depends on the current state of the session:
- New, unrelated task →
/clear. You want none of the old context. - Next phase of related work, session healthy → hand off the state (see below).
- Context limit reached mid-task, session healthy →
/compact. You want the distilled history of what has happened. - Session has turned → snapshot the state by hand and clear. You cannot trust the model to summarise a context it can no longer read well, so you extract what matters yourself, from files, diffs, tests, and known decisions, before resetting.
Handoff state, not the transcript. At a healthy boundary, have the agent write a handoff brief.
Instructive failures are useful here, and the way you keep them matters: distil each to a one-line lesson (“tried X, it failed because Y”).
Open the next session on the brief and on ground truth. A fresh window is fastest when its first act is to orient, not to guess. Point it at the handoff brief, then establish reality directly: read the relevant files, run the tests, check git status. The brief tells it where things stood; the live checks tell it where things actually are.
For long or parallel jobs
Decompose at verifiable seams. Split a task where the result is cheap to check (a test that passes, a build that compiles, a number that reconciles), not down to the smallest possible unit.
Fan out subagents only when the parts are independent. A clean context per subtask, each returning a distilled summary, works well for breadth: parallel research, independent lookups. For coding, where subtasks are usually coupled, isolated agents make conflicting assumptions and you inherit the job of reconciling them. Keep tightly coupled work in one thread, and where you do want isolation without the coordination risk, a git worktree (claude -w) gives a parallel task its own branch to work on.
Isolate the debugging. A bug is the case where forking pays for itself. Send the investigation to a fork or start a session from scratch, let it form and discard wrong theories in a context you will throw away, and bring back only the cause and the fix.
Bring in fresh eyes. A /code-review, or a dedicated reviewer subagent reading from a clean context, may catch what a rotten session cannot see in itself.
Tying it together: a session as a git tree
This section describes my own workflow, shaped by the findings above. It’s meant to make those principles automatic, and to take the decision fatigue out of running many sessions at once. It isn’t benchmarked, so treat it as one practitioner’s synthesis.
Frame a session like a git branch. Your main conversation thread is the orchestrator of the task, and the aim is for its context to stay clean and focused on the task. When a detour comes up (the kind that will burn cycles on research, dead ends or data digging), you fork it off into its own session with the history so far (claude --continue --fork-session) and do the messy work there. This is where the fork differs from a subagent. Subagents already handle parallel, independent work: spawn, explore, return a summary. The fork is for the sequential detour off your main thread: the messy investigation that needs your full session history to make sense, where there is no automatic path back and you want to choose what returns.
This gives context management a simple and familiar shape: branch, explore, distil, merge. The fork is disposable context by design. It can accumulate as much rot as it needs, because you are going to throw the context window away and keep only the result. Nothing that happens in the branch should pollute main.

When the branch has an answer, you distil it and merge it back. The two halves of this process are skills I have built on top of the native fork. A /conclude skill writes the branch down to a single file in a dedicated folder (I use ./cc-branches); a type argument selects from a number of templates describing different methods for concluding a branch, matching the kind of work performed. Back in the main session, a /merge skill loads that file, appending to context the conclusion and none of the noise that produced it.
Beyond context hygiene, the git framing has brought clarity to my workflow and cut the fatigue of switching between many tasks at once. It gives a clean mental model: each named branch becomes a discrete question with a clean answer, stored for future reference.
Everything so far assumes a corrector in the loop, and most of the time that is a person. Not because people are better than the model at the work, but because the model has no internal brake. It cannot see its own rot, so correction has to arrive from outside it. That is what governing context comes down to: someone outside the window deciding what enters it, what stays out, and what survives.
Governed context
Spend any time with Claude Code, watching it read files, run commands, write patches, spawn subagents, and maintain notes, and it quickly starts to feel like a little engineer back there: internalising your codebase, understanding the boundary between tasks and errors, and getting on with fixing the problems.
Not quite, and not in the way that matters here.
The model does not experience your project as a project. It experiences the current context: the instructions, the visible files, the tool outputs, the recent conversation. All of it, together, as working input. Some of it is signal. Some of it is noise. Some of it used to be true. Some of it was never true. The model has to act anyway. When we treat the session as accumulated understanding, our behaviours change, our output gets worse, and sometimes we end up blaming the model.
That is why context management is not a side concern. Claude Code is a control surface for the context reaching the model, and its core commands (clear, compact, rewind, branch, subagents, skills and hooks) are not just convenience features. They are controls over what enters context, what stays outside it, and what survives between sessions.
Governing context is not commanding the model. It is tending the half of the problem that is yours, the content, above a floor the architecture sets and you cannot move. The floor improves on the labs’ schedule. The content layer improves with you.
This is the shape of successful work with these tools: not maximum context, but governed context.



