The Memory and Context System
Managing context, keeping memory, and tuning Claude to hold on to what matters across sessions
Chapter 3 | Designing Claude Code to remember well, even when the session changes Written for: every level — newcomers building the basics, veterans reaching for the advanced techniques
Understanding the context window and Claude’s memory
Before designing a good memory system, you need to understand how Claude works, because Claude “forgetting” is not a bug. It is the normal behaviour of the LLM architecture.
What is a context window?
The context window is Claude’s “field of view” at any given moment. Claude can read only what is inside the context. It cannot “remember” anything outside it.
| Inside the context window | Outside the context window |
|---|---|
| The whole of the current conversation | Every previous session |
| Files handed to it this time | Files handed over in another session |
| The text in CLAUDE.md (if there is one) | Work you did together yesterday |
| The system prompt (if there is one) | The project name, unless you say it in this session |
The size of Claude’s context window
Current Claude models have a 200,000-token context window. That sounds enormous, but in practice it comes with real limits:
| 200,000 tokens | Roughly 150,000 lines of code, or a book of about 500 pages |
|---|---|
| Price rises with tokens | Every input token is billed. Context that keeps growing = a growing bill |
| Performance drops | With a very long context, Claude pays less attention to the material in the middle |
| Cleared on a new session | Close the terminal or run claude again = the context is gone |
💡 Get clear on tokens
English: ~4 characters = 1 token | Thai: ~2-3 characters = 1 token
1 line of code ≈ 10-30 tokens | a 100-line file ≈ 500-1,500 tokens
The prompt “summarise the project” ≈ 10 tokens | but if the project has 50 files it may take 50,000+ tokens
Claude Code’s four levels of memory
Claude Code has four levels of memory, each with a different lifetime and scope:
| Level | Name | Where it lives | Lifetime | Scope |
|---|---|---|---|---|
| 1 | In-Context Memory | The current conversation | The whole session | This session only |
| 2 | External Files | CLAUDE.md, .md files | Permanent | Project / global |
| 3 | Tool Results | MCP, Bash output | The whole session | This session only |
| 4 | Model Weights | Trained knowledge | Permanent (but dated) | Everywhere |
This chapter teaches you how to get level 2 (External Files) working at full strength, because it is the part you control most.
CLAUDE.md — Claude Code’s permanent memory
CLAUDE.md is the file Claude Code reads automatically at the start of every new session. Think of it as a briefing document telling Claude where it is, what it is working on, and what the rules are.
The order CLAUDE.md files are read in
Claude Code reads CLAUDE.md down the folder hierarchy, from broad to narrow. Information closer to the project overrides the general kind:
~/.claude/CLAUDE.md ← read first (Global: applies to every project)
~/Projects/CLAUDE.md ← read next (Parent folder)
~/Projects/myapp/CLAUDE.md ← read last (Project: this project only)
~/Projects/myapp/src/CLAUDE.md ← read when working inside src/
💡 Put the hierarchy to work
Global CLAUDE.md: personal preferences, such as “always answer in Thai” or “use 2-space indent”
Project CLAUDE.md: project-specific material — tech stack, conventions, prohibitions
Subfolder CLAUDE.md: rules for one module, such as src/api/ having different validation rules from src/ui/
A complete CLAUDE.md structure (template)
Below is a template covering every important section. Use it as a starting point and adjust it to your project:
# CLAUDE.md — [project name]
> Last updated: 2025-01-15 | Version: 1.4
## 🎯 Project Overview
What [project name] is: a system that [explain in 2-3 sentences]
Current stage: [MVP / Beta / Production]
Team: [headcount / solo]
## 🛠 Tech Stack
- Runtime: Node.js 20 LTS
- Framework: Next.js 14 (App Router)
- Language: TypeScript 5.3 (strict mode)
- Database: PostgreSQL 16 + Prisma ORM
- Auth: NextAuth.js v5
- Styling: Tailwind CSS 3.4
- Testing: Vitest + Playwright
- Deploy: Vercel (staging) + AWS ECS (production)
## 📁 Project Structure
src/
app/ ← Next.js App Router pages
components/ ← React components (ui/ and features/)
lib/ ← Utilities, helpers, constants
server/ ← Server Actions, API handlers
types/ ← TypeScript type definitions
prisma/ ← Database schema and migrations
tests/ ← E2E tests (Playwright)
## ✅ Coding Conventions
### Naming
- Components: PascalCase (UserCard.tsx)
- Files/folders: kebab-case (user-profile/)
- Functions: camelCase (getUserById)
- Constants: SCREAMING_SNAKE_CASE (MAX_RETRY)
- Types/Interfaces: PascalCase + descriptive (UserWithProfile)
### Code Style
- Indent: 2 spaces (never tabs)
- Quotes: single quotes for JS, double for JSX
- Semicolon: none (no-semi)
- Line length: 100 characters maximum
- Every async function must have try/catch
## 🚫 DO NOT (absolute prohibitions)
- Do not edit files under /legacy/* without approval
- Do not use any in TypeScript; use unknown if you must
- Do not commit .env or any secret
- Do not use moment.js (deprecated); use dayjs
- Do not add a new dependency without discussing it with the team
- Do not edit the database schema directly; always go through a Prisma migration
## 🔧 Common Commands
```bash
npm run dev # Start development server (port 3000)
npm run build # Build for production
npm run test # Run all Vitest tests
npm run test:e2e # Run Playwright E2E tests
npm run lint # ESLint check
npm run typecheck # TypeScript check
npx prisma studio # Open Prisma GUI
npx prisma migrate dev --name [name] # Create migration
🔑 Key Files
- src/lib/auth.ts ← Authentication config (edit with care)
- src/lib/db.ts ← Prisma client singleton
- src/server/actions/ ← All Server Actions
- .env.local ← Environment variables (see .env.example)
🎯 Current Focus
[update every sprint] Working on: Feature X
- Sprint 3 (2025-01-15 to 2025-01-29)
- Goal: payments via Stripe
- Blocked: waiting on the API key from Stripe (ETA: Wednesday)
📝 Recent Decisions
- 2025-01-10: moved from REST → Server Actions (less boilerplate)
- 2025-01-08: Zustand instead of Context API (performance)
- 2025-01-05: no GraphQL (over-engineering at this size)
⚠️ Known Issues
- User image upload is slower than it should be on mobile (TODO: optimize)
- Search debounce is not smooth yet (fix in Sprint 4)
🔗 Important Links
- Figma: [URL]
- Staging: https://staging.myapp.com
- Linear (Issues): [URL]
- Notion (Docs): [URL]
### Have Claude write CLAUDE.md for you
You do not have to write all of CLAUDE.md yourself. Tell Claude to analyse the project and draft it:
Ask Claude to analyse the project and create CLAUDE.md
Analyse this entire project, then create a CLAUDE.md file covering: tech stack, folder structure, conventions, important commands, and things to watch out for Use package.json, tsconfig.json, and the folder structure
Or have Claude update CLAUDE.md when the work is done
Update CLAUDE.md to reflect what we just did:
- add the new dependency we installed
- update Current Focus
- add the Known Issues found today
### The .md file system for steering Claude Code
Beyond CLAUDE.md, Claude Code reads several kinds of Markdown files, each with its own purpose. Knowing all of them gives you far finer and more powerful control over Claude.
| | Type 1: CLAUDE.md — Memory & Rules |
|---|---|
The main file already covered. It holds the project's memory and rules, and Claude reads it automatically every session.
| | Type 2: Custom Slash Commands (.md inside .claude/commands/) |
|---|---|
You can create your own / commands by putting .md files in the .claude/commands/ folder. Claude recognises them immediately.
Folder structure: .claude/ commands/ review.md ← creates the /project:review command deploy-check.md ← creates the /project:deploy-check command new-feature.md ← creates the /project:new-feature command daily-summary.md ← creates the /project:daily-summary command
### Example: .claude/commands/review.md
Code Review Command
Review the changed code in the Git staging area against the checklist below, then give a score and the action items that must be fixed before merge:
Checklist
- Security: any SQL injection, XSS, CSRF?
- Error Handling: does every async have try/catch?
- TypeScript: no unnecessary any?
- Performance: any N+1 query or memory leak?
- Tests: are the added test cases covering edge cases?
- Naming: are variable and function names clear?
- Comments: do they explain “why”, not just “what”?
Output format
✅ Passed (X/7)
⚠️ Must fix before merge
💡 Further suggestions
Use it by typing /project:review in Claude Code, and Claude runs the command straight away.
### Example: .claude/commands/new-feature.md
New Feature Template
Create the basic structure for a new feature: $ARGUMENTS (use $ARGUMENTS to take the feature name from the user)
Create the following files:
- src/features/{name}/index.ts
- src/features/{name}/{Name}Page.tsx
- src/features/{name}/components/ (empty folder)
- src/features/{name}/tests/{name}.test.ts
- src/server/actions/{name}.ts (Server Actions)
What goes in each file:
- the relevant TypeScript types
- TODO comments wherever implementation is needed
- an error boundary for the Page component
- wiring to auth following the pattern in src/lib/auth.ts
Usage: /project:new-feature UserProfile or /project:new-feature PaymentHistory
| | Type 3: Context Files — reference documents |
|---|---|
Ordinary .md files in the project that Claude reads when you reference them with @. They are not read automatically, but they are extremely useful when you want Claude to know something specific.
docs/ architecture.md ← explains the system architecture api-reference.md ← every API endpoint database-schema.md ← ER diagram and field descriptions decisions.md ← ADR (Architecture Decision Records) onboarding.md ← how a new developer sets the project up runbooks/ ← fixes for recurring problems, e.g. deploy, rollback
How to use them in Claude Code
Read @docs/architecture.md, then design the Payment module to match Look at @docs/database-schema.md, then write a suitable query Check @docs/decisions.md before proposing a new library
### Example: docs/decisions.md (ADR format)
Architecture Decision Records (ADR)
ADR-001: Server Actions instead of a REST API
Date: 2025-01-10 Status: Accepted
Context
We want less boilerplate around creating API endpoints
Decision
Use Next.js Server Actions for all mutations
Consequences
- ✅ 40% less code for CRUD operations
- ✅ Type-safe end to end, automatically
- ❌ Harder to debug because it is hidden
ADR-002: No GraphQL
…
| | Type 4: .clodeignore — telling Claude to skip files |
|---|---|
Like .gitignore, but it tells Claude which files or folders not to read. It saves tokens and keeps Claude from accidentally editing something important.
.claude/.clodeignore
Generated files
node_modules/ .next/ dist/ build/
Sensitive files
.env* *.pem *.key
Legacy code (do not touch)
legacy/ deprecated/
Large data files
*.csv *.sql data/
Test snapshots (no need to read)
snapshots/ *.snap
| | Type 5: Settings Files — configuring Claude's behaviour |
|---|---|
Besides CLAUDE.md (Markdown) there is settings.json, which controls system behaviour:
// ~/.claude/settings.json (Global) { “model”: “sonnet”, “editor”: “code”, “theme”: “dark”, “autoApproveEdits”: false, “notifications”: true }
// .claude/settings.json (Project-level — overrides Global) { “model”: “opus”, “autoApproveEdits”: false, “permissions”: { “allow”: [ “bash:npm run *”, “bash:git *”, “bash:npx prisma *” ], “deny”: [ “bash:rm -rf *”, “bash:sudo *” ] } }
⚠️ Project-level permissions matter a great deal <br> The deny list stops Claude running a dangerous command by accident <br> The allow list limits Claude to the commands you have approved <br> With no permissions set, Claude asks every time before running any command
### The handoff prompt — the tool professionals use daily
A handoff prompt is a systematic way of summarising work before closing a session so the next session can pick it straight back up with no time lost re-explaining. It pays off both in efficiency and in token cost.
## Why does handoff matter so much?
Picture this: you work with Claude for three hours and the context is packed with information. The next day you open a new session and Claude remembers nothing. Without a handoff you have to explain everything again, which can take 10-15 minutes — and you may forget something important.
| Without handoff | With handoff |
|---|---|
| Explain the context afresh every time | Claude understands the context immediately |
| Risk of forgetting an important decision | Every decision is on record |
| Claude has to re-read the code = high token use | Claude knows the current state = low token use |
| Slow to resume | Back at work within 1-2 minutes |
| Risk of mistakes from missing context | Low risk because the history is clear |
### The basic handoff prompt (5 minutes)
Good for newcomers. Use this prompt before closing every session:
Before this session ends, create a Handoff Summary for me Put it in CLAUDE.md under ”## Current Session Handoff” covering:
- work finished today (bullet points)
- work still outstanding and the exact next steps
- files modified (list)
- decisions taken and the reasoning
- problems hit and the fixes already tried
- commands to run at the next step
### The advanced handoff prompt (for professionals)
Use this when you want the most detailed, immediately usable handoff:
Create a complete Handoff Document and save it to .claude/handoffs/handoff-[date]-[time].md in this structure:
📊 Session Summary
- Date/time: [fill in automatically]
- Duration: [approximate]
- Main feature/task: [name]
✅ Completed
- [list of finished work, with sub-bullets if needed]
🚧 In Progress (unfinished)
- [outstanding work + % done + the exact next step]
📝 Files Modified
[run git diff —name-only HEAD and paste the result]
🔑 Key Decisions Made
- [decision]: [reasoning] | [alternatives rejected]
🐛 Issues & Blockers
- [problem]: [what was tried] → [still open / fixed this way]
💻 Next Session: Exact Commands to Run
# run these the moment the new session starts
[the actual commands]
🤖 Context for Next Claude Session
[a 3-5 sentence paragraph covering the context Claude needs immediately]
Once saved, update the “Current Focus” section of CLAUDE.md with a 2-3 sentence TL;DR
### A template for starting a new session
After a good handoff, starting a new session is fast and to the point:
Prompt for opening a new session (use this template every time)
Read @CLAUDE.md and @.claude/handoffs/handoff-[latest date].md then tell me where we left off and what the next step is Then run the commands listed under “Next Session: Exact Commands”
If there is no handoff file
Read @CLAUDE.md and tell me:
- what this project is and what it is doing
- what TODOs or Known Issues exist
- where we should start
### A handoff system for teams
On a team the handoff document matters even more, because other members have to pick the work up too:
.claude/ handoffs/ README.md ← explains the handoff format 2025-01-15-john.md ← John’s handoff on the 15th 2025-01-15-jane.md ← Jane’s handoff on the 15th 2025-01-16-john.md ← the 16th latest.md ← symlink or copy of the most recent
.claude/handoffs/README.md
Handoff Protocol
How to create a handoff
- Before finishing work, run: /project:handoff
- The file is created at .claude/handoffs/{date}-{name}.md
- Always commit this file before pushing
How to receive a handoff
- Read .claude/handoffs/latest.md
- Ask Claude: ”> Read @.claude/handoffs/latest.md and tell me what to do next”
### A slash command for automatic handoffs
.claude/commands/handoff.md
Auto Handoff Command
Create a complete Handoff Document and save it to a file immediately:
- Run
git diff --name-only HEADto see the modified files - Run
git log --oneline -10to see the latest commits - Run
date "+%Y-%m-%d-%H%M"to get a timestamp - Create the file .claude/handoffs/{timestamp}-handoff.md in the Advanced Handoff format
- Update .claude/handoffs/latest.md
- Update the Current Focus section of CLAUDE.md
- Show the summary to the user
Usage: type /project:handoff and press Enter. Everything happens on its own.
### Managing context efficiently
A full context window is a problem everyone runs into. Knowing how to manage context saves money and makes Claude's answers more accurate.
### Signs the context is filling up
Claude starts forgetting what you discussed early in the session
Claude gets noticeably slower
Claude starts looping, or proposes an approach you already rejected
The warning "Context is getting long" appears
Answers become unusually short or truncated
### /compact — compressing the context instead of starting over
/compact tells Claude to condense the whole conversation into a tight summary and drop the old history, leaving only the summary in context. It saves tokens while Claude still "remembers" the substance.
How to use /compact
/compact
/compact with instructions on what to preserve
/compact please keep: the decision about auth architecture, the bug found in the payment flow, and the list of TODOs
See the current context size
/context
| Situation | What to do |
|---|---|
| Context not full, but the conversation is very long | /compact to save tokens |
| Starting a new feature in the same project | /compact and continue, or start a new session |
| Claude is looping on the same wrong answers | Better to start a new session |
| Doing work that genuinely needs a long context | Pass files by @ reference instead of pasting into chat |
| Working with a very large codebase | Use RAG (chapter 6) instead of sending every file |
### Cutting tokens without losing effectiveness
### 1. Reference files instead of pasting
❌ Bad: pasting 200 lines of code into chat
Here is the code: [paste 200 lines] fix the bug in the validateUser function
✅ Good: use an @ reference
Fix the bug in the validateUser function in @src/lib/auth.ts
### 2. Be specific about what you want
❌ Bad: far too broad
Look at the project and tell me what problems it has
✅ Good: specific
Review only @src/server/actions/payment.ts checking error handling and race conditions
### 3. Use --max-tokens for one-shot runs
Cap the answer length to reduce output tokens
cat README.md | claude -p “summarise this file in 5 bullets”
Set max tokens in the settings
claude config set maxTokens 4096
### Using /memory and User Memory
Beyond CLAUDE.md, Claude Code has a memory system managed through the /memory command, which lets Claude store and retrieve the user's personal information.
### The /memory commands you will use most
See every stored memory
/memory
Add a new memory
/memory add I prefer a functional programming style /memory add always answer in Thai, except for code and technical terms /memory add use 4-space indent for Python projects
Edit a memory
/memory edit [id]
Delete a memory
/memory delete [id]
Search memories
/memory search “python”
### User Memory vs Project Memory
| Topic | User Memory (/memory) | Project Memory (CLAUDE.md) |
|---|---|---|
| Where it lives | ~/.claude/CLAUDE.md | project/CLAUDE.md |
| Applies to | Every project, every session | This project only |
| Suits | Personal preferences | Project rules |
| Examples | "Answer in Thai", "prefers functional style" | "Tech stack", "Conventions", "DO NOT" |
| Who edits it | Claude, via /memory | Claude or the developer |
### A good global CLAUDE.md (User Memory)
~/.claude/CLAUDE.md
My Personal Claude Preferences
Communication
- Always answer in Thai, except for code, technical terms and proper nouns
- Explain briefly first, then expand; do not be verbose
- If unsure, say so plainly; do not make things up
Coding Style
- Prefers functional programming (pure functions, immutability)
- Always TypeScript for a JavaScript project
- Test-driven: write the test first where possible
- Prefer explicit over implicit
Review Style
- Review like a senior developer mentoring a junior — explain the reasoning
- Point out critical problems first, then the nice-to-haves
- Always include a code example
Workflow
- Ask for clarification before starting if the requirement is unclear
- Work one step at a time and wait for approval before continuing, on large jobs
- Summarise what was done at the end of each task
### Advanced techniques for the memory system
### Technique 1: A knowledge base inside CLAUDE.md
Use CLAUDE.md as a mini knowledge base for the things Claude needs to know constantly, cutting the tokens spent re-explaining them:
Knowledge Base
Business Rules
- Free tier users: limited to 100 requests/day
- Pro tier users: unlimited + priority queue
- Admins can override the limit
Error Code Reference
- E001: Unauthorized (redirect to login)
- E002: Rate limit exceeded (show upgrade prompt)
- E003: Invalid input (show field error)
- E500: Server error (show friendly error + log)
Third-party Service Info
- Stripe: use webhooks, not polling
- SendGrid: template ID prefix = “d-”
- AWS S3 bucket: myapp-{env}-uploads
### Technique 2: Living documentation
Have Claude update the documentation automatically after every significant feature:
After adding a new feature
The feature is done. Now do the following:
- Update @docs/api-reference.md with the new endpoints
- Add an entry to @docs/decisions.md for the technical decision
- Update the “Key Files” section of CLAUDE.md if important files were added
- Add any known limitation to CLAUDE.md
Create a slash command to do it automatically
.claude/commands/update-docs.md
Update Documentation
After a feature is finished, update every related doc
Check git diff to see which parts of src/ changed
then update the corresponding docs
### Technique 3: The session state pattern
For work spanning several sessions, use a state file to hold the progress:
.claude/state.md (created by Claude, updated every session)
Current State
Active Task
Implementing: Stripe Payment Integration PR: #47 (draft)
Checklist
- Create the Stripe client singleton
- Implement createPaymentIntent
- Webhook handler skeleton
- Handle payment_intent.succeeded event
- Handle payment_intent.failed event
- Write integration tests
- Update API docs
Blocking Issues
- Not yet tested against the Stripe test clock
Environment
- Stripe test mode: ✅ configured
- Webhook local testing: ✅ stripe-cli running
Last Updated
2025-01-15 16:30 by John
Prompt for updating the state automatically
Update @.claude/state.md:
- tick the checkboxes that are done
- add any new blocking issue
- update Last Updated
Starting a new session
Read @.claude/state.md and tell me what comes next then start on the next checkbox
### Technique 4: Multi-agent memory sharing
If several Claude agents work at once, share memory through files:
Structure for multi-agent work
.claude/ shared/ context.md ← shared context every agent reads decisions.md ← the shared decision log interfaces.md ← API contracts between modules agents/ frontend-agent.md ← memory for the Frontend Agent only backend-agent.md ← memory for the Backend Agent only test-agent.md ← memory for the Testing Agent only
The Frontend Agent starts work
Read @.claude/shared/context.md and @.claude/agents/frontend-agent.md then build the UI against the interface defined in @.claude/shared/interfaces.md When finished, update @.claude/agents/frontend-agent.md
### Technique 5: Memory versioning
For a project running for months, put CLAUDE.md under version control too:
CLAUDE.md should always be committed to Git
git add CLAUDE.md git commit -m “docs(claude): update current focus to Sprint 4”
See the history of CLAUDE.md
git log —oneline — CLAUDE.md
See what changed in CLAUDE.md this sprint
git diff HEAD~10 — CLAUDE.md
Have Claude analyse the changes
git diff HEAD~10 — CLAUDE.md | claude -p “summarise how the project changed, from this CLAUDE.md diff”
### Common memory-system problems and how to fix them
### Problem: Claude does not read CLAUDE.md
Check the file is in the right place
ls -la CLAUDE.md ls -la ~/.claude/CLAUDE.md
Check which files Claude is reading
Tell me which CLAUDE.md files you are reading and what you can see in them
Force a read of CLAUDE.md
Read @CLAUDE.md again and summarise what you see
### Problem: CLAUDE.md is too long and fills the context
If CLAUDE.md runs past 500 lines, split it into smaller files:
Split CLAUDE.md into parts
CLAUDE.md ← keep only the overview + links .claude/ tech-stack.md ← the tech stack in detail conventions.md ← coding conventions knowledge-base.md ← business rules, error codes runbooks.md ← how-to guides
The main CLAUDE.md references the smaller files
Tech Stack
See the detail in @.claude/tech-stack.md
Conventions
See the detail in @.claude/conventions.md
### Problem: Claude does something CLAUDE.md forbids
Add emphasis in CLAUDE.md
🚫 CRITICAL: DO NOT (absolutely forbidden)
MUST NEVER: edit files under /legacy/* MUST NEVER: use any in TypeScript MUST NEVER: commit .env files
Add a rule in .claude/settings.json
{ “permissions”: { “deny”: [“bash:rm *”, “bash:sudo *”] } }
If Claude still ignores it, say so in the prompt
Important: before doing anything, always read the DO NOT section of CLAUDE.md
### Problem: the handoff is incomplete and Claude cannot resume
Fix it by making the handoff more detailed and checking it before the session ends:
Checklist before ending a session (run /project:handoff)
Before this session ends, check the handoff is complete: □ Is all finished work listed? □ Does the outstanding work have clear next steps? □ Is the list of modified files complete? □ Are there “Exact Commands” for the next session? □ Is the context for the new Claude written out fully? Fill in anything missing
## Glossary for this chapter
| Context Window | Claude's temporary memory frame, 200K tokens in size |
|---|---|
| Token | The unit of text an AI processes; in Thai ~2-3 characters = 1 token |
| CLAUDE.md | The Markdown file Claude reads automatically every session — its notebook |
| Handoff Prompt | The technique of summarising work before closing a session so the next one resumes immediately |
| /compact | The command that compresses context by summarising the old conversation, cutting token use |
| User Memory | Personal memory used across every project, managed with /memory |
| Project Memory | Project-specific memory, kept in the project's CLAUDE.md |
| Slash Command | A command you create yourself by adding a .md file to .claude/commands/ |
| ADR | Architecture Decision Record — a note of why a decision was taken |
| .clodeignore | The file telling Claude which folders and files not to read |
| Permissions | The settings controlling which commands Claude may run |
| Living Documentation | Documentation updated automatically as the code changes, so it never goes stale |
| Session State | A file holding the work's progress, letting you resume across sessions |
| Multi-Agent | A setup running several Claude instances in parallel |