Why every Claude Code session forgets your context — and what to do about it
Claude Code doesn't remember yesterday. It can re-read your repo, but it can't re-derive the decisions that aren't in the code. Here's the pattern that actually survives context resets.
Every time you open Claude Code, it's a stranger. It has never met you. It doesn't know what you built last week, what you tried and abandoned, which branch is the "real" one, or why the file you're about to ask it to edit is structured the way it is.
You probably already know this. What's less obvious is how much your workflow depends on it not being true — and how much rework you're eating because it is.
This is a post about context resets: why they happen, why the usual fixes (CLAUDE.md, long prompts, "just keep the session open") don't scale, and what actually works.
The shape of the problem
A Claude Code session has two kinds of memory.
Short-term is the conversation: the messages, the tool calls, the reasoning trail. It's sharp and precise while it's active, and gone the moment the session closes or compacts. Anything you "explained" in chat lives here.
Long-term is whatever the agent can read from disk on demand: the codebase, CLAUDE.md, docs, git history. It survives between sessions, but only the parts that are actually written down. The agent can't re-read your reasoning; it can only re-read your artifacts.
The failure mode is when load-bearing decisions live in short-term memory. You explain a constraint once ("we can't touch the payments table during business hours"), the agent honors it for that session, then the session ends. Tomorrow's agent re-reads the same code, sees nothing about payments hours, and makes a different call. You catch it in review if you're lucky.
Multiply that by every decision you make in a week, and the "AI is making weird choices again" feeling starts to make sense. It's not weird. It's downstream of amnesia.
Why the usual fixes don't go far enough
CLAUDE.md is great for stable project rules: build commands, conventions, "don't touch this directory." It's also a blunt instrument. Everything in CLAUDE.md is loaded into every session, so it has a ceiling before it starts eating context budget. And it's global — there's no good way to say "this rule only applies when editing the auth module."
Long system prompts work for one session. They don't carry forward. You end up retyping the same paragraph at the start of every conversation, which means you retype an incomplete version, which means the agent gets a slightly different brief every day.
Keeping the session open works until the context compacts, at which point short-term memory gets summarized into something lossy. Summaries are fine for conversation flow, terrible for load-bearing technical decisions. The compacted version will say "the user asked me to refactor the auth module" — it will not say "the user explicitly ruled out moving the session cookie to localStorage because of the subdomain deployment."
Git commit messages are the closest thing to persistent reasoning most projects have. They're better than nothing, but the agent has to go find them, and they're organized chronologically rather than by the feature you're working on.
None of these are wrong. They're just each solving one slice of the problem.
The pattern that actually works: per-feature specs
The pattern I keep coming back to is this: give each non-trivial feature its own spec document, checked into the repo, that the agent reads before touching that feature's code.
Not a PRD. Not a design doc. A spec — meaning a short, structured document that states:
- The goal (what this feature is for, in one or two sentences)
- User stories (who does what, and why)
- Acceptance criteria (how you'll know it works)
- Edge cases (what breaks it)
- Failure states (what happens when it breaks)
- Out of scope (the decisions you already ruled out)
That last bullet is the one nobody writes down, and it's the one that matters most between sessions. "We decided not to do X because Y" is the highest-leverage thing you can give a future agent. It's the reasoning that the code cannot show.
The spec lives next to the code — I keep mine under docs/specs/ or inline in the feature folder. The agent reads it at the start of any session that touches that feature. When the agent proposes a change, you review it against the acceptance criteria, not against your gut.
When you add a new requirement, you update the spec first, then ask the agent to reconcile the code. The spec is the source of truth; the code is the projection.
Why this survives context resets
A spec is external, structured, and local to the feature. That's three things CLAUDE.md isn't.
External means it doesn't consume your context budget until you ask for it. The agent only reads it when it's relevant. You can have 50 specs in your repo and none of them cost you anything until you're in the right directory.
Structured means the agent can use it without ambiguity. "Acceptance criteria" is not a prose paragraph the model has to interpret; it's a list the model can check against. "Out of scope" is not "I sort of mentioned this" — it's an explicit boundary.
Local to the feature means you can scope context precisely. Instead of one CLAUDE.md trying to cover everything, each feature gets its own brain. When you're editing auth, the auth spec loads. When you're editing billing, you don't pay for the auth spec.
The upshot is that context resets stop mattering. A fresh agent reads the spec, catches up in 30 seconds, and makes the same decisions your last agent would have made. The short-term memory still evaporates, but nothing load-bearing lives there anymore.
What a good spec looks like in practice
Keep it under 400 words. Longer than that and nobody updates it, including you. The shape I use:
# Feature: <name>
## Goal
<one or two sentences — what is this for>
## User stories
- As a <role>, I want <action>, so that <outcome>
- ...
## Acceptance criteria
- [ ] <observable behavior 1>
- [ ] <observable behavior 2>
- ...
## Edge cases
- <case>: <how it should behave>
- ...
## Failure states
- <failure>: <what the user sees, what gets logged>
- ...
## Out of scope
- <decision you ruled out> — <why>
- ...
The "why" lines under "Out of scope" are the part future-you (and future-agent) will thank you for. They're the only record of the decisions you made that aren't in the code.
The update discipline
A spec that's out of date is worse than no spec, because the agent will trust it.
The discipline is: update the spec before you change the code, not after. If you can't write down what you're changing and why, you don't understand the change well enough to make it. And if the agent's first action in a session is "read the spec, then propose a diff against it," stale specs produce diffs that don't match reality, which you catch immediately.
This is also a nice forcing function for the thing you were supposed to do anyway, which is think about the change before typing it.
Where ClearSpec fits
I'll be blunt about this part. ClearSpec exists because writing specs by hand is annoying enough that most people skip it, and skipping it is exactly how you end up with the amnesia problem above.
You describe a feature in plain English, and ClearSpec produces a structured spec in the format above — with user stories, acceptance criteria, edge cases, failure states, and out-of-scope already filled in. You tighten it, commit it to your repo, and hand it to Claude Code. The agent executes against it cleanly.
It's free to start and doesn't require a credit card. It works with Claude Code, Cursor, and Codex because the output is just a markdown file your agent can read.
The TL;DR
Claude Code forgets. CLAUDE.md helps with global rules, but doesn't scale. The pattern that actually survives context resets is per-feature specs checked into the repo, short enough to maintain, structured enough to trust, and specifically including the decisions you ruled out. Update them before the code, not after. Let the spec be the persistent memory between sessions, and let the agent's short-term memory stay disposable.
The amnesia stops mattering once the load-bearing stuff lives on disk.
Related: Vibe coding vs spec-driven development — the real difference isn't speed and How to write a spec for Claude Code (that it actually follows).
ClearSpec turns a plain-English description into a structured spec AI agents can execute. Free to try — no credit card.