# Beyond the Chat Window: How Claude Code Actually Persists Knowledge Between Sessions

> Every Claude Code session starts blank. No memory, no continuity. Yet somehow it knows your stack, your conventions, your quirks. Here's exactly how that works.

- Author: [Azraf Al Monzim](https://monzim.com/)
- Published: 2026-04-26
- Updated: 2026-06-13
- Topic: AI & tooling
- Tags: claude-code, ai-tools, developer-experience, productivity
- Canonical: https://monzim.com/blog/claude-code-memory-system-explained

---

Every Claude Code session starts with a completely blank context window.

No background sync. No hidden database. No persistent state quietly accumulating in the cloud. You open a new session and Claude Code, technically, knows nothing.

Yet it remembers you use `pnpm`. It knows your API handlers live in `src/api/handlers/`. It recalls that you never mock the database in tests because of a prod incident last quarter.

Here's exactly how that works.

---

## The Core Mechanic: Context Injection

There's no magic. Memory in Claude Code is **files read at startup and injected into the context window**. That's the whole trick.

The sophistication is in *which* files, *from where*, *written by whom*, and *how much* gets loaded. Two separate systems handle this — and they complement each other.

![Privacy Migration Workflow-2026-04-26-100224.svg](https://storage-portfolio.monzim.com/blogs/1777197756054-privacy_migration_workflow-2026-04-26-100224.svg)

Two systems. Two authors. One shared goal: give the next session enough context to be useful from message one.

---

## System One — CLAUDE.md: Memory You Write

`CLAUDE.md` is a plain markdown file. You write it. Claude reads it at session start, every time, no exceptions. Think of it as the onboarding doc for a new teammate — except this teammate reads it perfectly and forgets nothing within the session.

### The scope hierarchy

Claude walks up your directory tree collecting every `CLAUDE.md` it finds. All files concatenate — none override each other.

![privacy-migration-workflow-2026-04-26-095818-69ede1bfea96c.webp](https://storage-portfolio.monzim.com/blogs/1777197516443-privacy-migration-workflow-2026-04-26-095818-69ede1bfea96c.webp)

More specific wins. Your `CLAUDE.local.md` appends after the team file at the same level, so your personal preferences take precedence on conflict.

Subdirectory files (like `src/CLAUDE.md`) don't load at launch — they load lazily the first time Claude reads a file in that subdirectory. Keeps startup lean.

### What belongs in CLAUDE.md

Add something when:
- Claude makes the same mistake twice
- You type the same correction you typed last session
- A code review catches something Claude should have known
- A new teammate would need the same context on day one

Keep entries concrete. Vague instructions degrade fast.

<table>
  <thead>
    <tr>
      <th>Bad</th>
      <th>Good</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Format code properly</td>
      <td>Use 2-space indentation, no trailing commas</td>
    </tr>
    <tr>
      <td>Test your changes</td>
      <td>Run <code>pnpm test</code> before committing</td>
    </tr>
    <tr>
      <td>Keep files organized</td>
      <td>API handlers go in <code>src/api/handlers/</code></td>
    </tr>
    <tr>
      <td>Be careful with auth</td>
      <td>JWT tokens expire in 15 min — never extend server-side</td>
    </tr>
  </tbody>
</table>

### The 200-line limit

Stay under 200 lines per file. Longer files consume more context and — counterintuitively — produce *worse* adherence. Too many instructions dilutes attention on any single rule.

For large projects, use `.claude/rules/` — a directory of topic-scoped markdown files. You can gate rules to specific file paths with frontmatter:

```markdown
---
paths:
  - "src/api/**/*.ts"
---

All endpoints must include input validation.
Use the standard error response format.
```

These path-scoped rules only load when Claude touches matching files. Everything else stays out of context.

---

## System Two — Auto Memory: Memory Claude Writes

Auto memory flips the model. Instead of you writing instructions, **Claude takes notes on itself** as it works.

During a session, Claude quietly observes: how you build, how you test, what corrections you make, what patterns you favor. At the end, it decides what's worth saving for next time — not everything, just what future-Claude would actually use.

### Where it lives

```
~/.claude/projects/<repo>/memory/
├── MEMORY.md           ← sparse index, loaded every session
├── debugging.md        ← patterns that fixed recurring bugs
├── api-conventions.md  ← design decisions and rationale
└── workflow.md         ← build, test, deploy knowledge
```

The path is derived from your git repo root. Every worktree and subdirectory within the same repo shares one memory store.

### How loading works

![Privacy Migration Workflow-2026-04-26-100130.svg](https://storage-portfolio.monzim.com/blogs/1777197700927-privacy_migration_workflow-2026-04-26-100130.svg)

`MEMORY.md` is intentionally sparse — a table of contents, not a dump. Topic files are heavy with detail but never loaded at startup. Claude pulls them mid-session only when relevant.

### The four memory types

<table>
  <thead>
    <tr>
      <th>Type</th>
      <th>What it stores</th>
      <th>Example</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>User</strong></td>
      <td>Your role, expertise, communication style</td>
      <td>"Deep Go experience, new to React — frame frontend concepts in Go analogues"</td>
    </tr>
    <tr>
      <td><strong>Feedback</strong></td>
      <td>Corrections you made <em>and</em> approaches you validated</td>
      <td>"Don't mock the database — mocks passed but prod migration failed last quarter"</td>
    </tr>
    <tr>
      <td><strong>Project</strong></td>
      <td>Ongoing work, decisions, deadlines not in the code</td>
      <td>"Auth rewrite is compliance-driven, not tech debt — scope for compliance over ergonomics"</td>
    </tr>
    <tr>
      <td><strong>Reference</strong></td>
      <td>Pointers to external systems</td>
      <td>"Pipeline bugs tracked in Linear project INGEST"</td>
    </tr>
  </tbody>
</table>

Feedback saves both corrections *and* confirmations — if you only record mistakes, Claude grows overly cautious over time.

### What auto memory deliberately skips

Auto memory ignores things already derivable from the codebase: file structure, code patterns, naming conventions, git history. It targets knowledge that would otherwise vanish — the *why* behind a decision, the *context* that never made it into a commit message.

---

## The Sharp Edges

### Silent truncation

If `MEMORY.md` exceeds 200 lines, the overflow is **silently dropped**. No warning. No error. Claude just doesn't see older memories. It may behave like it forgot things — because it did.

Mitigation: Claude is supposed to keep the index sparse and move detail into topic files. On long-running projects, run `/memory` periodically to audit what's there and trim stale entries.

### After `/compact`

Running `/compact` compresses the conversation to recover context space. After compaction, the project-root `CLAUDE.md` re-injects automatically. But nested `CLAUDE.md` files in subdirectories do not — they reload only the next time Claude reads a file in that path.

If an instruction disappears after `/compact`, it was either given only in conversation or lives in a lazy-loaded subdirectory file. Fix: add it to the root `CLAUDE.md`.

### CLAUDE.md is context, not config

`CLAUDE.md` content is delivered as a user message, not enforced configuration. Claude reads it and tries to follow it, but there's no hard compliance guarantee — especially for vague or conflicting rules. If Claude isn't following an instruction, the issue is almost always instruction specificity, not a bug.

---

## Practical Setup

<table>
  <thead>
    <tr>
      <th>Scenario</th>
      <th>What to do</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Starting a new project</td>
      <td>Run <code>/init</code> — Claude generates a starter CLAUDE.md from your codebase</td>
    </tr>
    <tr>
      <td>Personal preferences across all projects</td>
      <td>Write to <code>~/.claude/CLAUDE.md</code></td>
    </tr>
    <tr>
      <td>Team standards</td>
      <td>Commit <code>CLAUDE.md</code> to repo root, keep it under 200 lines</td>
    </tr>
    <tr>
      <td>Local secrets / sandbox URLs</td>
      <td>Use <code>CLAUDE.local.md</code>, add to <code>.gitignore</code></td>
    </tr>
    <tr>
      <td>Tell Claude to remember something now</td>
      <td>Say it: "Remember that API tests need a local Redis instance"</td>
    </tr>
    <tr>
      <td>Audit what Claude has saved</td>
      <td>Run <code>/memory</code> in any session — browse and edit plain markdown</td>
    </tr>
    <tr>
      <td>Large project with many rules</td>
      <td>Use <code>.claude/rules/</code> with path-scoped files per domain</td>
    </tr>
  </tbody>
</table>

---

## The Full Picture

![Privacy Migration Workflow-2026-04-26-100027.svg](https://storage-portfolio.monzim.com/blogs/1777197640364-privacy_migration_workflow-2026-04-26-100027.svg)

Two files, two authors. Everything is plain markdown. Nothing is hidden.

That's the whole system. When it feels like Claude "remembers" — it's because someone wrote the right thing in the right file. When it feels like Claude forgot — it's because they didn't.

---

*Official docs: [How Claude remembers your project](https://code.claude.com/docs/en/memory)*
