"Write everything down" is good advice for the first two months of a project. It stops being good advice around the point where your memory file is longer than the module it describes. Project memory bloat is the predictable end state of a habit nobody told you to maintain: you were told to append, and append is all you ever did.

The symptom is easy to recognise. You open .prjcontext/memory/decisions.md looking for why the queue retries three times instead of five, and you scroll past an entry about a CSS framework you removed in March, two entries about an auth approach you abandoned, and a note saying "revisit before launch" dated eleven months ago. You eventually find the retry decision. It took forty seconds longer than it should have, and your assistant, reading the same file, had no way to know which half of it was still true.

Project memory bloat is what append-only looks like at month six

Early on, every entry is load-bearing. The project is small, the decisions are fresh, and anything you write down is something you would otherwise have to reconstruct. Adding a line costs nothing and the file stays readable, so there is no feedback telling you to curate.

What changes is not the habit, it is the ratio. A memory file is useful in proportion to how much of it currently applies. At twelve entries where ten are live, the file is a briefing. At sixty entries where twenty-five are live, it is an archive with a briefing hidden inside it. The writing habit that got you here has no natural stopping point and no built-in editing step, which is why the file degrades quietly instead of failing loudly.

There is a second-order effect that is easy to miss. Once you stop trusting the file to be current, you stop reading it, and once you stop reading it you stop noticing which entries went stale. The decay accelerates exactly when you need the file most.

A file too long to read is a context window problem wearing a disguise

For a human reader, bloat costs time. For an assistant, it costs something more specific. Whatever you load into a session competes for the same budget as the code, the diff and the conversation itself, and a long memory file takes a real share of it. If you have not thought about this before, how a context window actually works is the mechanics behind it.

The cost is not only volume. Stale decision records actively mislead. If your memory file contains a 2026-02 entry choosing a REST client and a 2026-07 entry replacing it, an assistant reading both has to infer which one won from the dates, and inference is where it guesses. Guessing is how you get a suggestion to reinstall the library you deliberately dropped, which is the exact failure project memory was supposed to prevent.

Contradiction is worse than omission. An empty memory file produces an assistant that asks. A contradictory one produces an assistant that is confidently wrong, and you only find out during review.

What earns a permanent line

The test I use is narrow: does this entry explain something about the code as it exists right now? Not as it existed, not as it might. Right now.

That keeps a small number of things:

  • Decisions still shaping the code. The constraint that explains why a module looks odd. "Queue retries cap at three because the upstream provider rate-limits on the fourth call in a minute."
  • Rejected approaches that are still tempting. The ones an assistant will propose again because they look obviously right from the outside. This is the highest-value category and the one people cut first by mistake.
  • Traps and sharp edges. The generated file you must not edit, the test that fails only on a cold database, the env var that silently defaults to the wrong thing.
  • Current state and open questions. Short, and rewritten rather than appended to.

Everything else is history. History is valuable, but it does not belong on the page someone reads to orient themselves. If an entry would not change what you or your assistant do next, it is not earning its line. The same filter applies to the decision records you keep, and it applies with more force to instructions: CLAUDE.md bloat is the same disease in a file that gets loaded automatically, which makes it more expensive.

What to cut

Four categories, roughly in order of how safe they are to remove.

Superseded decisions. A later entry reversed or replaced an earlier one. Keep the current decision. Fold the useful part of the old reasoning into it as a single clause ("replaced the REST client in July after the retry semantics proved unworkable") and delete the original entry.

Dead ends from code paths that no longer exist. You spent a day on an approach for a feature that was later cut. The rejected approach only matters while the problem it addressed is still a problem.

Duplicate rationale. The same reason explained in three entries written months apart. Pick the clearest, delete the others.

Notes that became code. "TODO: add index on events.created_at" stops being memory the moment the migration lands. The migration is the record.

What stays even when it looks like clutter: anything dated and still unresolved, and anything you have had to re-explain to a session more than once. Repeated re-explanation is the strongest signal an entry is doing work.

Prune on a calendar, not on a feeling

Pruning when the file finally annoys you means pruning once a year, badly, at the worst moment. Memory file maintenance works better attached to something that already happens.

Good anchors: the end of a sprint, a release, a major refactor landing, or the point where you hand the project to someone else. A refactor is the best one, because it is exactly when a batch of entries goes stale simultaneously, and you are already holding the context to judge them.

Fifteen minutes, top to bottom, asking one question per entry: still true? Mark the superseded ones as you go and delete in one pass rather than agonising entry by entry. If you are pruning decision logs for the first time after a long stretch, expect to cut a third of the file and expect that to feel wrong. Read the shortened version afterwards. It usually reads better than you feared.

Do not delete the history, just move it off the front page

The reason people avoid pruning is not laziness, it is loss aversion. Deleting a paragraph you wrote at 1am after finally understanding a race condition feels like destroying evidence, and sometimes it is. Three months later someone asks why you did it that way and the answer is gone.

So separate the two concerns. The live file is the briefing. The history lives somewhere you can still reach it:

.prjcontext/memory/
  decisions.md       # active, pruned, read every session
  state.md           # where things stand now
  archive/2026-h1.md # superseded entries, kept but not loaded

An archive/ folder costs nothing and removes the excuse. If an entry might matter later, it moves rather than disappears, and the decision to prune stops being irreversible.

Version history does the same job with less filing. We built PrjLab so project memory travels as versioned files beside your code: you edit decisions.md down to what is true today, run prj push, and the longer version is still sitting in the previous version where you can open it in the browser and diff the two. Pruning becomes an edit instead of a deletion, which is the difference between a file people maintain and one they are afraid to touch. The getting-started guide covers setting that up, and if you are still deciding what belongs in memory in the first place, the broader guide to project memory comes before this one.

Either way, the shift is in how you think about the file. It is not a log you add to. It is a document you edit, and like any document, the version that helps is the one someone bothered to shorten.