How to Build Persistent Memory with Claude Code: Session Handoff & Wake-Up Files
Problem
Every time I started a new Claude Code session, I lost everything from the previous session. Claude would forget:
- What we worked on last time
- Architecture decisions we made
- Bugs we discovered and fixed
- Patterns specific to my codebase
- What was supposed to happen next
I found myself repeating the same context over and over:
# Session 1me: "Fix the auth bug in src/auth/login.ts"Claude: [fixes it, discovers RLS policy issue]
# Session 2 (next day)me: "Continue working on auth"Claude: "What auth issue? Can you show me the codebase?"me: [repeats entire context]This wasted 5-10 minutes every session. Even worse, Claude kept making the same mistakes because it didn’t remember what it learned before.
I tried using MCP servers for knowledge storage. That didn’t work either - Claude would skip calling the tools unless I explicitly reminded it.
Environment
- Claude Code (latest version)
- Working directory:
/Users/zhaocaiwen/Private/bw/bswen-ai-gen/claudeaiclaudemdasos - Using MCP servers for external knowledge access
- Multiple sessions per day across different tasks
What happened?
A Reddit user shared their setup for persistent memory in Claude Code. The key insight: treat each session like a shift change.
The outgoing shift writes a handoff document. The incoming shift reads it before starting work. This is exactly what hospital nurses do between shifts.
I implemented this pattern in my project.
Here’s my wake-up file:
# Claude Project Memory
READ THIS FIRST: This file is my persistent memory. Read completely before any task.
## Project OverviewBuilding a React Native app with Expo, TypeScript, and Supabase backend.
## Previous Session (2025-02-04)- Fixed navigation bug in AuthStack- Added user profile screen- Discovered: Supabase RLS policies were blocking writes
## Current Priorities1. [ ] Implement push notifications2. [ ] Add offline mode with AsyncStorage3. [ ] Refactor auth context (useReducer pattern)
## Knowledge Base
### Architecture Decisions- Using Context + useReducer for global state (not Redux)- Navigation: React Navigation v6 with type-safe screens- API: Supabase client with RLS for data security
### Gotchas & Patterns- **IMPORTANT:** Always check Supabase RLS policies before debugging "permission denied" errors- Use `useCallback` for event handlers passed to child components- AsyncStorage key format: `@AppName:featureName`
### Code Patterns```typescript// Type-safe navigation patterntype RootStackParamList = { Home: undefined; Profile: { userId: string };};Next Session Handoff
- Push notifications setup is partially complete (config done, need listeners)
- Check /docs/notifications.md for implementation plan
- Don’t forget to test on iOS vs Android (different behaviors)
Session Log
[Append session summaries here]
The critical part is at the top: **"READ THIS FIRST"**. This tells Claude to read the entire file before starting any task.
I set up a journaling system too:
```markdown title="SESSIONS.md"# Session Journal
Template for each session entry:
## Session [Date]
### Started With- What context did I have?- What was the plan?
### What We Accomplished- [ ] Task 1- [ ] Task 2
### Key Learnings- New pattern discovered- Bug root cause identified- Architecture decision made
### Problems Encountered- Issue: description- Solution: how we fixed it
### What's Next- Priority tasks for next session- Context to carry forward
### Files Modified- List of changed files for reference
---
## Session 2025-02-05
### Started With- Context from CLAUDE.md- Goal: Fix push notification iOS permissions
### What We Accomplished- [x] Added iOS permission request flow- [x] Tested notification handling- [x] Updated docs/notifications.md
### Key Learnings- iOS requires `UNAuthorizationOption` configuration in Info.plist- Android permissions work differently (auto-granted on targetSdkVersion 33+)- Added to Knowledge Base: iOS/Android permission differences
### What's Next- Implement notification categories- Add notification tap handlerNow when I start a new session, Claude reads both files. It knows exactly what happened last time and what to do next.
I also added autonomous scanning tasks to CLAUDE.md:
## Autonomous Operations
### Content Scanning ProtocolOn session start, automatically:
1. **Check for new documentation:** ```bash find /docs -name "*.md" -mtime -7If new files found → Summarize and update Knowledge Base
-
Check for new features:
Terminal window git log --since="1 week ago" --name-only --oneline | grep "src/"If new components → Document architecture changes
-
Check session journal: Read last 3 sessions from SESSIONS.md Identify patterns, recurring issues
Auto-Update Triggers
Update Knowledge Base when:
- You encounter a bug twice
- You discover a new code pattern
- You make an architecture decision
- You find a better way to do something
Update Format
When updating Knowledge Base, use:
**[Date]**: [Insight]- Context: Why this matters- Pattern: Code example if applicableThis makes Claude proactive. It scans for changes and updates its own knowledge base.
## Why this matters?
The Reddit user shared some interesting data:
**Passive context vs Active tools:**- **Passive context** (knowledge in CLAUDE.md): 100% usage rate- **Active tools** (MCP servers, lookup commands): 44% usage rate (56% skip)
When knowledge is directly in context, Claude uses it automatically. When knowledge requires tool calls, Claude often skips the tool unless explicitly prompted.
Here's the comparison:
```markdown## Knowledge Access Strategies
### Strategy 1: MCP Tool (44% usage rate)```json{ "tool": "search_knowledge_base", "query": "How to handle Supabase RLS errors?"}Problem: Claude often skips tool calls unless explicitly prompted.
Strategy 2: Direct Context (100% usage rate)
## Troubleshooting Supabase RLS- "Permission denied" errors are usually RLS policies- Check: `supabase.rpc('get_policies')` to debug- Common fix: Add `auth.uid()` check to policyBetter: Knowledge is immediately available, always used.
Recommendation: Use MCP for external data (API calls, web search), use CLAUDE.md for internal knowledge you want Claude to always remember.
I tested this myself. When I had RLS troubleshooting steps in an MCP server, Claude would forget to check it. When I moved the same information into CLAUDE.md, Claude applied it every time without prompting.
## How to solve it?
Here's how I set up persistent memory in three steps:
### Step 1: Create CLAUDE.md
In your project root, create `CLAUDE.md`:
```markdown# Project Context
IMPORTANT: Read this file completely before starting any task. This is your persistent memory across sessions.
## Previous Session Summary[What happened last time]
## Current Priorities1. [ ]2. [ ]
## Knowledge Base Notes- Key insight about codebase: ...- Don't forget: ...- Architecture decision: ...
## Next Session Handoff[What to continue next time]Step 2: Add Startup Instructions
At the top of CLAUDE.md, add:
READ THIS FIRST: This file is my persistent memory. Read completely before any task.Step 3: Enable Journaling
Create SESSIONS.md:
## Session 2025-02-05
### What We Did- ...
### Key Learnings- ...
### What's Next- ...Instruct Claude to append to this file at the end of each session.
Step 4: Automate Knowledge Updates
Add this instruction to CLAUDE.md:
When you discover important patterns, architecture decisions, or recurring issues, update the "Knowledge Base Notes" section above.Now test it:
# Start new sessionme: "Continue working on auth"Claude: [reads CLAUDE.md, sees we fixed RLS issue last time]Claude: "I see from the previous session that we fixed Supabase RLS policies. What's the next priority?"me: "Implement push notifications"Claude: [sees in Current Priorities, checks Next Session Handoff for context]It works. Claude remembers everything.
The reason
I think the key reason this works is:
Passive context beats active tools.
When knowledge is in the startup file (CLAUDE.md), Claude reads it before processing your request. It’s part of the context window, always available.
When knowledge is in tools (MCP servers), Claude has to:
- Recognize it needs to check the knowledge base
- Decide to call the tool
- Wait for the tool response
- Incorporate the response into its answer
Claude often skips steps 1-2 unless explicitly prompted.
The Reddit user explained it well:
“If knowledge is in context, Claude uses it 100% of the time. If knowledge requires tool calls, usage drops to 44%.”
I’ve seen this myself. Critical patterns (like “check RLS policies first”) need to be in CLAUDE.md. Peripheral information (like fetching latest docs from a website) can use MCP servers.
Summary
In this post, I showed how to build persistent memory in Claude Code using wake-up files and session handoffs. The key point is putting knowledge directly in CLAUDE.md for 100% usage rate, versus 44% for MCP tool-based approaches.
Quick setup checklist:
- Create CLAUDE.md with project context
- Add startup instructions (READ THIS FIRST)
- Set up SESSIONS.md for journaling
- Define autonomous scanning tasks
- Create Knowledge Base section
- Add Next Session Handoff section
- Test: Start new session, verify it reads context
The shift handoff pattern:
- Outgoing session updates CLAUDE.md with what it learned
- Incoming session reads CLAUDE.md before starting work
- Knowledge accumulates across sessions
- Claude becomes more effective over time
This transforms Claude Code from a chatbot into a persistent development partner that remembers everything.
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