Skip to content
← All guides

Context windows explained for people who just want to ship

6 min read

Why your agent gets worse an hour in, the signals that tell you it has happened, and the handful of habits that keep sessions sharp.

An hour into a session, the answers get worse. Not obviously wrong, just vaguer: it suggests a fix you already tried, it re-reads a file it read at the start, it hedges where it was decisive. You cannot point to the moment it turned, and the model is the same model it was at the beginning.

Nothing degraded. The desk got full.

The desk, not the filing cabinet

The most useful mental model is a physical one. The context window is a desk, not a filing cabinet. Everything the agent can use to answer your next message has to be sitting on that desk right now.

What is on it: the system prompt, your project instruction file, every file it has read this session, the full output of every command it has run, every message you have sent, and every message it has sent back including all the code it wrote. Your repository is not on the desk. Your repository is in the building somewhere, and things only reach the desk when something fetches them.

The desk has an edge. When you push past it, older material has to be summarised or dropped. That is the entire phenomenon.

What fills it fastest

Ranked roughly by how much damage they do per action:

  • Pasted logs. A production log dump is the single most expensive thing you can put on the desk, and about four lines of it were relevant.
  • Whole-file reads of large files. A 2,000-line service file read in full to answer a question about one function.
  • Verbose test output. A full suite run prints every passing test name, plus setup noise, plus timing.
  • A big git diff. Especially across a branch with a lockfile change in it.
  • Dependency trees and install output. Enormous, and almost never worth its space.
  • Greps that hit generated code. One unbounded search across dist/, node_modules/ or a lockfile can cost more than the last twenty messages combined.

The pattern is that all of these are cheap for you to trigger and expensive for the agent to hold. One keystroke of yours can consume a large slice of the working set.

What compaction takes from you

When the window fills, the earlier history gets summarised so the session can continue. This is necessary and mostly works. But summarisation preserves conclusions and discards detail, and the specific detail it discards is the record of what has already failed.

A summary of your last forty minutes reads like "investigated the timeout, added retries to the HTTP client". What it drops is that you tried raising the pool size and it changed nothing, that the timeout only reproduces under concurrent load, and that the first retry implementation caused duplicate charges. Those are exactly the facts that stop the next hour repeating the last one.

The result is an agent that is confident, coherent, and quietly running experiments you already ran.

The signs you are near the edge

You do not get a warning. You get behaviour, and these four are reliable:

It re-reads a file it read twenty minutes ago. Not because it needs a refresher, but because that content is no longer on the desk.

It reintroduces a bug you already fixed together. The fix is gone from working memory; the original wrong approach is the one that reads as natural.

It drops a constraint you set at the top. You said no new dependencies. Fifty turns later there is a new dependency.

It starts hedging. "You may want to check whether", "depending on how your setup works". Vagueness is what generation looks like when the specifics are no longer in front of it.

Any of these means stop and reset, not push harder. Fighting a full window is the least productive thing you can do with an agent.

Tactics that actually work

One task per session. Finish the pagination change, then start a fresh session for the caching work. The cost of a new session is that you retype a bit of context. The cost of not doing it is everything above.

Narrow the task before you start. "Fix the failing test in src/lib/money.test.ts" keeps a small working set. "Fix the failing tests" invites the agent to read the whole suite.

Search instead of reading. A targeted search returns the ten lines you need; a file read returns two thousand you do not.

# expensive: pulls an entire service file onto the desk
# cat src/services/billing.ts

# cheap: find the definition, then read only around it
rg -n "export function chargeCard" src/
rg -n --glob '!*.lock' --glob '!dist/**' "STRIPE_" src/ | head -n 20

Truncate command output before it lands. This is the highest-leverage habit on the list because it costs nothing and applies to every command you run.

# don't: the whole suite's output, mostly passing test names
pnpm test

# do: the failures and nothing else
pnpm vitest run src/lib/money.test.ts 2>&1 | tail -n 40
pnpm tsc --noEmit 2>&1 | head -n 30
git diff --stat main...HEAD

Write durable findings to a file. Anything you would be annoyed to rediscover should leave the conversation and go somewhere that survives summarisation.

cat >> notes/session.md <<'EOF'
## Timeout investigation, 1 Aug
- Retry wrapper lives in src/lib/http.ts, not per-service.
- Only reproduces with >20 concurrent requests to /invoices.
- Dead end: raising the pool size to 50 changed nothing.
EOF

Use a separate session for exploration. When you need to understand how something works before changing it, do the reading in one session and bring back ten lines of summary to the session that does the work. The expensive reading stays where it happened. This pairs directly with the handover habit in Why your agent forgets everything.

And restart rather than fight. When you see two of the warning signs, open a fresh session, paste your ten-line summary, and carry on. It feels wasteful. It is faster every time.

The bill and the wait

Two secondary effects worth naming, because they push in the same direction as everything above.

More context means slower turns. Every message has to process everything on the desk, so a session two hours deep responds noticeably more slowly than one five minutes old. That latency is a decent proxy for how full things are.

More context also means higher cost, since the whole working set is reprocessed on every exchange. A disciplined session is not just sharper, it is cheaper, and the two improve together rather than trading off.

Try this at the start of your next session, before you ask for anything:

git log --oneline -n 10
git diff --stat main...HEAD
cat notes/session.md

Three bounded commands, a few hundred tokens, and the agent knows where the project is without reading a single source file. Then state the one task you want done, and keep the desk clear for it.

context-windowworkflowai-agentsproductivity