Skip to content

How Do I Use CLAUDE.md for Project Memory in Claude Code?

I opened Claude Code the next day and it had no idea what I was working on.

“Can you continue on the authentication feature?”

“What authentication feature?”

The feature I spent three sessions building. The one with the OAuth integration. The one where we decided on JWT over sessions. All that context, gone.

This kept happening. Every new session started with me re-explaining the project. Frustrating. Then I found the CLAUDE.md pattern that changed everything.

The Problem: No Persistent Memory

Claude Code doesn’t remember anything between sessions by default. Each conversation starts fresh. This is fine for quick tasks but brutal for ongoing projects.

I tried various approaches:

  • Summarizing at session end: Claude would write a summary. Next session I’d paste it. Worked, but I kept forgetting to do it.
  • Mega prompts: I wrote a huge prompt explaining everything. Too long, Claude ignored parts of it.
  • README files: Claude read them sometimes. But READMEs are for humans, not AI context management.

None of these scaled. I needed something built into Claude Code itself.

The Solution: Two-Component Memory System

The insight from a Reddit discussion clicked for me: CLAUDE.md should be a current state snapshot, not a history log.

memory-vs-history-comparison
┌─────────────────────────────────────────────────────────────────┐
│ WRONG APPROACH: CLAUDE.md as History Log │
├─────────────────────────────────────────────────────────────────┤
│ Day 1: Started project, set up Next.js... │
│ Day 2: Fixed bug in authentication... │
│ Day 3: Added Stripe integration... │
│ Day 4: Refactored database layer... │
│ ... 500 lines later ... │
│ Day 47: Now Claude has to read all 47 days to find current state│
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ RIGHT APPROACH: Two-Component System │
├─────────────────────────────────────────────────────────────────┤
│ CLAUDE.md (Snapshot - Under 30 Lines): │
│ - Current feature: Payment integration - IN PROGRESS │
│ - Branch: feat/stripe-webhooks │
│ - Next: Test webhook handling │
│ │
│ Session Recaps Folder (History): │
│ /docs/session-recaps/ │
│ ├── 2026-03-27-auth-setup.md │
│ ├── 2026-03-26-database-design.md │
│ └── ... detailed history when needed ... │
└─────────────────────────────────────────────────────────────────┘

The distinction is crucial:

AspectMemory SnapshotHistory Log
PurposeCurrent state onlyHistorical record
LengthUnder 30 linesCan be extensive
ContentWhat IS nowWhat HAPPENED
UpdatesReplaced when state changesAppended continuously
LocationCLAUDE.md main sectionSession recap folder

How I Structure My CLAUDE.md

Here’s what works for me:

CLAUDE.md
# MyProject - Current State
## Active Work
- Feature: Payment integration - IN PROGRESS
- Branch: feat/stripe-webhooks
- Blockers: Waiting on Stripe test keys
## Architecture Decisions
- Stack: Next.js 14, TypeScript, Prisma, PostgreSQL
- Auth: NextAuth.js with Google provider
- Why: Team familiarity, good DX
## Key Files Claude Needs
- `src/app/api/webhooks/stripe/route.ts` - Main webhook handler
- `prisma/schema.prisma` - Database schema
- `src/lib/auth.ts` - Auth configuration
## Conventions
- Commits: feat:/fix:/chore: prefixes
- Testing: Jest unit, Playwright E2E
## Next Steps
- [ ] Test webhook in staging
- [ ] Add payment confirmation emails
---
Session Recaps: /docs/session-recaps/

Twenty-eight lines. Claude reads it all. Gets immediate context.

The Session Recap Folder

For detailed history, I create separate files:

folder-structure
my-project/
├── CLAUDE.md # Snapshot (under 30 lines)
├── docs/
│ └── session-recaps/
│ ├── 2026-03-27-stripe-integration.md
│ ├── 2026-03-26-database-schema.md
│ └── 2026-03-25-project-kickoff.md

Each recap captures what happened, not what’s current:

2026-03-27-stripe-integration.md
# Session Recap - 2026-03-27
## Goals
- [x] Implement Stripe webhook handler
- [ ] Test in staging environment
## Decisions Made
- Chose Stripe over PayPal: Better API docs, team experience
- Used raw webhooks not Stripe CLI: Simpler for Vercel deployment
## Code Written
- `src/app/api/webhooks/stripe/route.ts` - Handles payment events
## Issues & Resolutions
- Signature verification failed initially
- Fix: Used raw body parser, not JSON parser
## Next Session
- [ ] Set up staging test cards
- [ ] Add idempotency key handling

Why This Works

1. Claude reads everything in the snapshot

Under 30 lines means Claude actually processes all of it. My old 200-line “memory” file? Claude skimmed it and missed things.

2. State vs. History separation

I used to mix current state with project history. Claude would reference outdated decisions. Now snapshot = current, recaps = history. Clear separation.

3. Easy to maintain

After each session:

update-memory.sh
# Create recap
cp template.md "docs/session-recaps/$(date +%Y-%m-%d)-feature.md"
# Fill in recap details...
# Update CLAUDE.md snapshot
# Replace old state with new current state
# Commit both
git add CLAUDE.md docs/session-recaps/
git commit -m "docs: update project memory"

4. Context window is not the problem

I was paranoid about context limits. Then I saw this Reddit comment: “I’ve gone 80-90% into the 1M context limit and still worked fine.”

The issue isn’t context size. It’s context organization. A messy 50-line file is worse than a clean 30-line file.

Poly-Repo Projects

If you have multiple repos, include the structure:

CLAUDE.md for monorepo
# Monorepo Structure
monorepo-root/
├── apps/
│ ├── web/ # Next.js frontend (port 3000)
│ └── api/ # Express backend (port 3001)
├── packages/
│ └── shared/ # Shared utilities

Claude understands which repo you’re working in and how they relate.

Common Mistakes I Made

Mistake 1: Using CLAUDE.md as a changelog

I listed every change chronologically. Claude had to read through 47 days of history to find current state. Fixed by moving history to session recaps.

Mistake 2: Too much detail in snapshot

I included API documentation, schema details, configuration. Claude got overwhelmed. Fixed by keeping only what Claude needs RIGHT NOW.

Mistake 3: Not updating the snapshot

I created a perfect CLAUDE.md once. Never updated it. Became stale and misleading. Fixed by making it part of my commit routine.

Mistake 4: No session recaps

I relied only on git history. But git commits don’t capture WHY decisions were made. Session recaps fill that gap.

The Template I Use Now

session-recap-template.md
# Session Recap - YYYY-MM-DD
## Goals This Session
- [ ] Goal 1
- [ ] Goal 2
## What Got Done
- Thing completed
## Decisions & Rationale
- Decision: [what]
- Why: [reasoning]
## Code Changed
- `path/to/file.ts` - What it does
## Blockers / Issues
- Problem: [description]
- Status: [unresolved / workaround]
## Next Session
- [ ] Continue with...

After each session, I fill this out and update the CLAUDE.md snapshot. Takes 2 minutes. Saves hours of re-explaining context.

Key Takeaway

CLAUDE.md is not a diary. It’s a snapshot of NOW.

Keep the snapshot under 30 lines. Put the history in separate files. Update both after each session. Claude will remember everything that matters, and you’ll stop re-explaining your project every single day.

Final Words + More Resources

My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me

Here are also the most important links from this article along with some further resources that will help you in this scope:

Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!

Comments