For months I've had a strong feeling that a fresh Claude Code session gives better output than a long-running one. Sharp at the start, mushy later.
So I did what you do with a feeling: I drew it. Context on the y-axis, time on the x. A fresh session fills fast and sawtooths: you hit the wall, compact, climb again. My setup fills slower, so I figured I was spending more time in the good zone. Then I built quality curves on top of that — an "output index" that decays as context fills, with the area under the curve as the cost. Fitted them, rescaled them, tuned the coefficients. The graphs are all up there.
Not one number in any of them was measured. I'd invented a unit and then spent a week reasoning from it.
On 29 Aug I acted on the model and set my auto-compact to 200K. It felt better immediately.
Then I got suspicious of "felt better," because I'd built the model from vibes and then confirmed it with vibes.
So I parsed every session transcript on my machine. 52 sessions, 20,668 assistant turns, 156 compaction events, ~790MB of JSONL from 19 Jul to 1 Sep. Six mechanical quality proxies, each measured against context size.
The result is a null. Every limb of my hypothesis failed. I'll take the loss, because the three things I found on the way are more useful than the thing I was looking for.
1. MCP tool definitions cost 1,305 tokens
Not 15%. Not 10%. 1,305 tokens — 2.6% of my session floor.
I A/B'd it. Identical claude -p run, same model, same prompt. All MCP servers loaded: 29,292 input tokens. --strict-mcp-config with an empty config: 27,987. Difference: 1,305.
The reason is that Claude Code defers MCP schemas by default and loads only tool names at startup. The full JSON schema gets fetched when a tool is actually reached for.
So all the advice about pruning MCP servers to save context is optimising about a quarter of one percent of a 1M window.
What actually fills a fresh session (median floor 49,553 tokens):
| Component |
Tokens |
Share |
| System prompt + built-in tool schemas + skill/agent listings |
~43,259 |
87.3% |
| SessionStart hook |
~2,746 |
5.5% |
| Auto-memory |
~1,660 |
3.3% |
| All MCP servers |
1,305 |
2.6% |
| CLAUDE.md |
~583 |
1.2% |
That 87% lump is the thing worth attacking. I have 87 local SKILL.md files and 10 agents, and their listings are in there somewhere. It never appears as a line item in any context meter, so nobody talks about it. I couldn't split it further without more A/B runs — that number is derived by subtraction, not measured directly.
2. Six proxies, 20,668 turns, nothing degrades
| Proxy |
n |
r vs context |
within-session r |
| Tool error rate |
21,405 |
-0.020 |
-0.017 |
| Bash error rate |
9,862 |
-0.022 |
-0.024 |
| Edit retry rate |
5,294 |
-0.093 |
-0.055 |
| User correction rate |
1,909 |
-0.107 |
-0.070 |
| Output tokens/turn |
20,668 |
+0.039 |
+0.014 |
| File re-read rate |
2,171 |
-0.145 |
-0.065 |
Negative means it gets better as context fills. Not one proxy degrades.
Don't read that as "quality improves." Largest |r| is 0.145, explaining 2.1% of variance. Everything is "significant" only because n is in the thousands. The honest reading is flat — these measures are essentially independent of context size.
The within-session column is the part I'd defend hardest. It demeans both variables inside each session, so it can't be explained away as "long sessions were just different sessions."
And two of these proxies are mechanically biased toward my hypothesis and still contradict it. Re-read rate should climb with context simply because more files have been read by then. Edit-retry should climb because more edits have accumulated. Both fall.
3. The threshold I was fighting was one I'd set myself
I believed Claude Code auto-compacts around 84% of the window. I'd read it in a few places and never questioned it.
There's no such documented default. The docs say that without an auto-compact window set, it compacts when the conversation reaches the model's context limit.
My corpus before 29 Aug contains exactly one auto-compaction. At 997,170 tokens — 99.7% of 1M. Exactly the documented behaviour.
After 29 Aug: 81 more, clustered at 165K-183K. Which is 84%... of 200,000. The ceiling my own PowerShell wrapper imposed.
Median context dropped from 267K to 122K across that boundary. Turns running above 200K went from 66% to 8.5%.
Not to zero, though — and that detail matters. The wrapper is a PowerShell function, so it only applies to sessions launched from PowerShell. Anything started from another shell still gets the full 1M, which is why 533 post-wrapper turns ran above 200K and one session reached 543K. I'd half-configured a constraint and then attributed the results to the tool.
The bit that killed the original model
My plan was "stay under 20% context."
My median fresh-session floor is 49,553 tokens — 24.8% of a 200K window before I type anything. The lowest context ever reached after any compaction, across 151 events, was 46,470.
36 turns out of 20,668 — 0.17% — ever sat below 40K.
I was prescribing an operating band below the machine's own floor. The sawtooth I drew starts at 7%. That number was invented. The real one is 25%, and it changes everything downstream.
And compaction isn't free
- File re-read rate in the 10 turns after a compaction: 53.9% vs 35.9% everywhere else. +18pp, p = 2e-7.
- Median 138 second stall per compaction.
- ~166K tokens fed back through the model each time to produce a ~5K summary.
- Prompt cache invalidated.
My aggressive regime compacted 3.4x as often and spent 1.8x the summarizer tokens per hour as my older deep-running sessions, which scored better on every proxy.
That last comparison is confounded and I won't pretend otherwise. Strategy was never randomised; the two groups differ by era, task mix and model.
The caveat that matters most
These are mechanical proxies. They cannot see reasoning quality.
A model that's subtly worse at reasoning — shallower analysis, weaker architecture calls, missed edge cases — while still emitting syntactically valid tool calls is completely invisible to all six of these. That's exactly the thing I thought I noticed, and exactly the thing this method can't test.
So this doesn't show context rot isn't real. It shows my tooling doesn't get worse in long context. Settling the rest needs matched tasks, alternating auto-compact settings, and blind human scoring.
Also: my corpus mixes four models sitting at different context depths, which is a live confound I haven't fully removed.
What I changed
- Dropped the
--autocompact 200k wrapper. Solving a problem the data doesn't show, at a cost the data does.
- Stopped pruning MCP servers for context reasons.
- Kept the Obsidian RAG. ~2.7K tokens at startup. It was never the floor.
Full report — every number, method, caveat, and the nine things I couldn't measure — plus the sanitised data and the investigation prompt so you can run the same analysis on your own transcripts:
https://github.com/bruhman-rtx/Resources/tree/main/studies/context-decay
Point the prompt at your own ~/.claude/projects/ and overwrite the parameters block. No network access needed.
Genuinely want to be wrong about this. If your data shows degradation, post it.
The original modelling is my son's — he built those Desmos curves, and they're what sent me looking for real numbers.