DEV Community

~K¹yle Million
~K¹yle Million

Posted on

Claude Code Memory: How Automatic Memory Extraction Actually Works

Claude Code Memory: How the Automatic Memory Extraction Actually Works

Published: 2026-04-09 | Author: ~K¹ / IntuiTek¹ | Tag: claudecode


After every complete query loop in Claude Code, something happens in the background that most people don't know about: a forked agent runs, reads your conversation, and writes durable memories to disk.

These memories persist across sessions. They inform future runs. They are the reason a well-used Claude Code agent seems to "know" things it was never explicitly told.

Here's exactly how it works — and how to use it deliberately.


The Mechanism

When you finish a session (or reach certain completion points), Claude Code forks a lightweight agent. That agent's sole job is to extract what's worth remembering and write it to a structured memory file.

The file lives at:

~/.claude/projects/<sanitized-cwd>/memory/MEMORY.md
Enter fullscreen mode Exit fullscreen mode

The <sanitized-cwd> is your working directory path with slashes replaced by hyphens. So if your project is at /home/user/myproject, the memory file is at:

~/.claude/projects/-home-user-myproject/memory/MEMORY.md
Enter fullscreen mode Exit fullscreen mode

This is project-scoped memory. Different working directories get different memory spaces. If you have two Claude Code instances running in two different directories, they have separate memory.


What Gets Extracted

The auto-extraction agent categorizes memories into four types:

User memories — who you are, your role, expertise level, preferences. These help Claude Code tailor its explanations and approach. If you mention you've been writing Go for ten years but you're new to React, that gets stored. Future sessions skip the basics.

Feedback memories — corrections and confirmations. If you told Claude Code not to add error handling for cases that can't happen, that goes into memory. If you confirmed a particular architectural choice was exactly right, that gets stored too. Both corrections and validations are worth keeping — you only want to say things once.

Project memories — what's in motion, why decisions were made, deadlines, constraints. The context behind the code that git history doesn't capture. "We're freezing merges Thursday — mobile team is cutting a release branch" is exactly the kind of thing that should persist.

Reference memories — where things live in external systems. Which Linear project tracks which bugs. Which Grafana board is the oncall dashboard. The map of your operational environment.


What Doesn't Get Extracted

This is equally important.

Code patterns, file paths, and architecture are not stored in memory — they're derived by reading the current codebase. If the memory says "the auth middleware is in src/middleware/auth.ts" and you've since renamed it, the memory is wrong. The file system is always authoritative.

Git history is not duplicated. "Who changed what and when" lives in git log and git blame. Memory doesn't replicate that.

Debugging solutions and fix recipes — the fix is in the code, and the commit message has the context. Memory doesn't need to store it.

Anything already in CLAUDE.md. If you've documented something in your project instructions, it doesn't need to be in memory too.


How to Read It at Session Start

The memory file is loaded into your conversation context automatically if you configure it correctly. But you can also read it explicitly — which is useful for active sessions where you want to surface something specific:

cat ~/.claude/projects/-home-user-myproject/memory/MEMORY.md
Enter fullscreen mode Exit fullscreen mode

For autonomous agents (headless mode with -p), reading memory at the start of each run is a session-start discipline, not automatic. Add it to your task prompt or your CLAUDE.md session checklist:

At session start: read ~/.claude/projects/-home-user-myproject/memory/MEMORY.md 
for recent context before proceeding.
Enter fullscreen mode Exit fullscreen mode

Writing Memories Deliberately

The auto-extraction is passive — it harvests what's already in your conversation. But you can also write memories directly.

The format is straightforward. Each memory is a markdown file with frontmatter:

---
name: feedback_testing_approach
description: Don't mock the database in integration tests — real DB required
type: feedback
---

Don't mock the database in these tests.

**Why:** We got burned last quarter when mocked tests passed but the prod migration failed. Mock/prod divergence masked a broken migration.

**How to apply:** Any test touching data persistence must use the real database — no mocks, no in-memory SQLite substitutes.
Enter fullscreen mode Exit fullscreen mode

The MEMORY.md index file points to each memory file. It's loaded at session start (lines after 200 get truncated, so keep entries concise):

- [Testing: No DB mocks](feedback_testing_approach.md) — integration tests require real DB; mocks caused prod incident
Enter fullscreen mode Exit fullscreen mode

The Two-Layer Memory Stack

Many serious Claude Code deployments run two memory systems simultaneously:

Layer 1: Claude Code auto-extraction — runs after every session, project-scoped, file-based, zero setup.

Layer 2: Supabase + pgvector — semantic long-term memory. Stores session summaries as vector embeddings, queryable by similarity at session start. Query at the start of a new session: "what do we know about X?" and the LTM layer surfaces prior context even if it predates the most recent auto-extraction window.

The two layers serve different purposes:

  • Auto-extraction is operational continuity — "what preferences, patterns, and constraints should inform this session?"
  • LTM is institutional knowledge — "what did we learn six sessions ago about this system's behavior?"

Neither replaces the other. Run both.


The Common Failure Mode

The most common memory failure is stale references. A memory file says "the payment handler is in src/payments/stripe.js" — but you refactored it three weeks ago. Now the agent confidently recommends a path that no longer exists.

The rule: a memory that names a specific function, file, or flag is a claim that it existed when the memory was written. Before acting on it, verify:

  • If the memory names a file path: check the file exists.
  • If the memory names a function or flag: grep for it.
  • If the user is about to act on your recommendation (not just asking about history): verify first.

"The memory says X exists" is not the same as "X exists now."


Practical Setup

If you want this working well across sessions:

  1. Check your memory directory exists: ls ~/.claude/projects/-home-user-yourproject/memory/ — if it doesn't exist after several sessions, auto-extraction may not be enabled.

  2. Add the memory read to your CLAUDE.md session checklist — don't rely on automatic loading alone for critical context.

  3. Write memories for things you only want to say once — user preferences, architectural decisions, standing constraints. Every correction that would be annoying to repeat belongs in a memory file.

  4. Keep MEMORY.md under 200 lines — after that, entries get truncated at load time. Use short, specific one-liners in the index.

  5. Verify before acting — before recommending from memory, check that what the memory describes still exists.


The memory system in Claude Code is genuinely useful — but only if you treat it as a tool that requires maintenance, not a magic layer that handles everything. Write to it deliberately. Read it at session start. Verify before acting on it.

That's the difference between an agent that feels coherent across sessions and one that constantly has to be re-taught what it already knows.


W. Kyle Million (~K¹) builds autonomous AI infrastructure at IntuiTek¹. Building revenue-generating agents without ongoing manual involvement.

Top comments (0)