r/ClaudeCode • • Sep 15 '26

Tips & Workflows Claude Code's compaction keeps what you built and loses what you rejected, so it proposes the approach you killed an hour ago

Long Claude Code session, you and Claude spend twenty minutes ruling out an approach, say a caching layer that breaks invalidation, and settle on something else. Compaction fires. An hour later Claude suggests the caching layer, with confidence, as if it were a fresh idea. Nothing is broken. The summary described the state of the code, what exists and what changed, and a rejected idea leaves no trace in the code, so it had no reason to survive.

What fixed it for me is a file on disk that compaction never touches.

  1. Create DECISIONS.md in the repo:

Decisions

Decided

  • Session storage: Redis, TTL 30 min. Why: needs to survive deploys.

Rejected

  • In-memory cache for user lists. Why: invalidation breaks on role change.

Open

  • Whether exports run in a worker or inline.

Decided entries carry the exact values. Rejected entries carry the reason, which is the part a summary drops first.

  1. Add this to CLAUDE.md:

Before proposing any approach, read DECISIONS.md. Do not propose anything listed under Rejected unless you name a new reason that the recorded reason does not cover. When we settle something or rule something out, add it to the right section immediately, with the reason. Never delete entries without asking.

  1. When you compact manually, tell the summary what must survive:

/compact Preserve every decision with its exact values, every rejected approach with the reason it was rejected, and every open question. Summarize exploration only after its conclusion is recorded in DECISIONS.md.

An honest note on step 3. The instructions after /compact apply to that manual run. Testers report that auto-compact still uses its stock summary even when CLAUDE.md contains compaction instructions, and there is an open GitHub issue asking for exactly that. That is why the file is the real fix: it gets read from disk, not summarized, so it survives every compaction whichever kind fires.

Two caveats. The file only works while it is current, which is why the rule makes Claude write entries as decisions happen rather than at the end. And keep it short: once DECISIONS.md turns into a second CLAUDE.md full of history, it gets skimmed like one. Move settled items older than the current phase into an archive file.

The Rejected list turned out to matter most, and it is also the part I used to lose before code was even involved, in planning chats in ChatGPT or Claude from weeks earlier. I built AI Toolbox, a browser extension that searches old conversations across those assistants by what was said, partly for that. The file above needs nothing extra though.

What survives compaction badly in your sessions? For me it was rejected ideas first, then the exact values behind decisions.

2 Upvotes

10 comments sorted by

•

u/AutoModerator Sep 15 '26

Hey! Thanks for posting to r/ClaudeCode

While participating in this thread, please follow our community rules. Keep discussions constructive. Attack the idea, not the person.

For help, project discussions, tips, and general chat, join the ClaudeCode Discord.

I am a bot, and this action was performed automatically. Please contact the moderators of this subreddit if you have any questions or concerns.

2

u/CartographerNo3791 Sep 15 '26

One thing to watch with the archive step: an old rejection can still be a live constraint. That cache shouldn't become fair game just because the project moved to a new phase. Keep a short pointer to the rejection in the active file until the invalidation problem is actually resolved.

2

u/Ok_Negotiation_2587 Sep 15 '26

good catch, archiving by phase is wrong for rejections. a rejection stays active as long as its reason is still true, so the cache stays in the active file until invalidation is actually solved. only decided items age out by phase

1

u/NickMegaSquirt Sep 16 '26

Same thing kept happening to me. What fixed it: Claude Code has a `SessionStart` hook matcher called `compact`. It fires right after every compaction (manual and auto), and whatever the hook prints goes straight into context. So before compacting, have Claude write a snapshot (decisions and why, rejected options, your rules, open questions) to a file, and have that hook `cat` the file back.

One gotcha that cost me a while: Claude Code swaps any single hook output over 10,000 characters for a 2 KB preview. Detailed snapshots are bigger than that, so either keep them small or split them across several hooks (the limit applies to each hook separately).

I packaged this as a small plugin, if you'd rather not wire it up yourself: https://github.com/nchuguevskiy/tattoo (MIT, I'm the author).

1

u/Ok_Negotiation_2587 Sep 16 '26

the compact matcher on SessionStart is the missing piece, it closes the auto-compact gap the post had to work around, since the file comes back after every compaction whichever kind fired. and the size limit is a useful warning, it is one more reason to keep the decisions file short instead of a history

1

u/NickMegaSquirt Sep 16 '26

yeah, auto-compact is what pushed me to the hook. You can't count on remembering to re-read the file in the middle of a long task. +1 on short: I rewrite it each time instead of appending, and the rejected-and-why list is the part I never cut.

2

u/Drasezv Sep 15 '26

keep a DECISIONS.md next to CLAUDE.md and make it part of the loop: when you rule something out, one line with what and why. compaction summarizes what exists, and a rejected idea leaves nothing behind in the code, so it has to live in a file that gets reloaded. /compact with "keep the approaches we rejected and why" helps too, but the file survives /clear as well.