---
title: "Claude Code Memory: How CLAUDE.md Actually Works"
description: "How Claude Code memory works: the CLAUDE.md hierarchy, auto memory files and caps, session resumption, and where file-based facts go stale."
canonical: https://past.dev/blog/claude-code-memory
date: 2026-09-02
category: Research
authors: The past.dev team
---
# Claude Code Memory: How CLAUDE.md Actually Works

Claude Code memory is file-based. Every session begins with a fresh [context window](/glossary/context-window), and persistence comes from two documented mechanisms loaded at the start of each conversation: CLAUDE.md instruction files you write, and an auto memory directory Claude maintains for itself ([memory docs](https://code.claude.com/docs/en/memory)). Conversation transcripts are a third, separate store, saved continuously as local JSONL and reloaded by `claude --continue` or `claude --resume` ([sessions docs](https://code.claude.com/docs/en/sessions)). Everything sits on your machine as plain text you can open, edit, or delete.

## Claude Code memory files: the CLAUDE.md hierarchy

Claude Code loads CLAUDE.md from four scopes, broadest first ([memory docs](https://code.claude.com/docs/en/memory)):

| Scope | Location |
|---|---|
| Managed policy | `/Library/Application Support/ClaudeCode/CLAUDE.md` (macOS), `/etc/claude-code/CLAUDE.md` (Linux), `C:\Program Files\ClaudeCode\CLAUDE.md` (Windows) |
| User | `~/.claude/CLAUDE.md` |
| Project | `./CLAUDE.md` or `./.claude/CLAUDE.md` |
| Local | `./CLAUDE.local.md`, gitignored personal notes |

The resolution rules, all from the same [memory page](https://code.claude.com/docs/en/memory):

- Files in the working directory and every directory above it load at launch, concatenated from the filesystem root down, so the file closest to where you launched is read last.
- CLAUDE.md files in subdirectories load on demand, when Claude reads files in those directories.
- `@path/to/file` anywhere in a CLAUDE.md imports that file into context at launch. Imports recurse to a maximum depth of four hops, and paths inside backticks or code fences stay literal.
- A project-level import that resolves outside the working directory triggers a one-time approval dialog before it loads.
- Claude Code reads CLAUDE.md rather than AGENTS.md; the documented bridge is a CLAUDE.md containing `@AGENTS.md`, or a symlink.
- `.claude/rules/` holds topic files, and a rule with `paths:` frontmatter loads only when Claude works with matching files. Personal rules live in `~/.claude/rules/`.

`/init` generates a starting CLAUDE.md from the codebase, `/memory` lists and opens every memory file, and `/context` shows what actually loaded into the current session ([commands docs](https://code.claude.com/docs/en/commands)).

## Auto memory: the notes Claude writes to itself

Auto memory is on by default and toggles from `/memory` or the `autoMemoryEnabled` setting, with `CLAUDE_CODE_DISABLE_AUTO_MEMORY=1` as the environment-variable off switch ([memory docs](https://code.claude.com/docs/en/memory)). Claude records four documented note types, marked in each file's frontmatter: `user`, `feedback`, `project`, and `reference`. It skips anything derivable from the codebase and anything a CLAUDE.md already says ([memory docs](https://code.claude.com/docs/en/memory)).

Storage is one directory per git repository at `~/.claude/projects/<project>/memory/`, shared across worktrees of that repository and local to the machine; the docs state files are never shared across machines or cloud environments ([memory docs](https://code.claude.com/docs/en/memory)). Inside sit a `MEMORY.md` index, one line per memory, and a topic file per subject.

The caps are specific ([memory docs](https://code.claude.com/docs/en/memory)):

- At session start, Claude Code loads the first 200 lines of MEMORY.md or the first 25KB, whichever comes first. Content past that threshold is invisible until something opens the file.
- Topic files never load at startup; Claude reads them on demand with its file tools.
- A write that pushes MEMORY.md over the limit succeeds, and Claude Code then returns an error telling Claude to rewrite the index, since the excess would be dropped on the next load.
- CLAUDE.md has a separate ceiling: loaded in full up to 4 MiB, skipped entirely above that, with guidance to stay under 200 lines per file for adherence.

Session transcripts are deleted after a retention period; the memory directory is excluded from that sweep, so entries stay until you or Claude edits them ([memory docs](https://code.claude.com/docs/en/memory)).

## Sessions: what --continue and --resume restore

Transcripts are JSONL at `~/.claude/projects/<project>/<session-id>.jsonl`, written continuously as you work ([sessions docs](https://code.claude.com/docs/en/sessions)). `claude --continue` reopens the most recent session in the current directory, `claude --resume` takes a picker, a name, or a session ID, and `/resume` switches conversations from inside a session ([sessions docs](https://code.claude.com/docs/en/sessions)).

A resumed session restores the full conversation history including tool calls and results, the model it was using, the agent it ran as, and in the common terminal cases its permission mode ([sessions docs](https://code.claude.com/docs/en/sessions)). Launch flags are a documented exception: `--mcp-config`, `--settings`, and directories added with `--add-dir` must be passed again ([sessions docs](https://code.claude.com/docs/en/sessions)). Default transcript retention is 30 days via the `cleanupPeriodDays` setting ([sessions docs](https://code.claude.com/docs/en/sessions)).

Compaction has its own rule: after `/compact`, the project-root CLAUDE.md is re-read from disk and re-injected, while instructions given only in conversation are gone unless someone wrote them to a file ([memory docs](https://code.claude.com/docs/en/memory)).

## Context rather than configuration

The docs are explicit that both memory systems are context: Claude reads them and tries to follow them, with no guarantee of strict compliance, and CLAUDE.md content arrives as a user message after the system prompt rather than inside it ([memory docs](https://code.claude.com/docs/en/memory)). For a rule that must always apply, the same page points to PreToolUse [hooks](https://code.claude.com/docs/en/hooks-guide), which run as shell commands at fixed lifecycle events regardless of what Claude decides.

The documented saving flows, as of September 2026: ask Claude to remember something and it writes auto memory; ask it to add something to CLAUDE.md and it edits the file; `/memory` opens any memory file in your editor ([memory docs](https://code.claude.com/docs/en/memory)). The current interactive-mode shortcut reference and command list document no `#` memory prefix ([interactive mode](https://code.claude.com/docs/en/interactive-mode), [commands](https://code.claude.com/docs/en/commands)); those three flows are the documented ways in.

## Stale facts: the time axis file memory lacks

A CLAUDE.md line is true on the day someone writes it, and the format records nothing else about time: no record of when the fact became true, when it stopped, or what replaced it. The one timestamp in the documented system is the `modified` field Claude Code writes into auto memory frontmatter, an ISO 8601 write time that requires v2.1.214 or later ([memory docs](https://code.claude.com/docs/en/memory)). A write time is ingestion time; it says when the note was saved rather than when the fact happened, a distinction unpacked in [event time vs ingestion time](/guides/event-time-vs-ingestion-time).

Updates are manual by design. The docs tell you to review your CLAUDE.md files periodically to remove outdated or conflicting instructions, and warn that when two rules conflict, "Claude may pick one arbitrarily" ([memory docs](https://code.claude.com/docs/en/memory)). [Staleness](/glossary/memory-staleness) is handled by human review, and [supersession](/glossary/fact-supersession) by deletion: a new fact wins only once someone removes the old one. The tooling nudges in that direction: `/doctor` proposes trims for a checked-in CLAUDE.md, and when MEMORY.md nears its cap, Claude Code reminds Claude to merge or drop stale entries ([memory docs](https://code.claude.com/docs/en/memory)). Nothing in the documentation detects that a fact stopped being true.

Provenance is similarly thin. The documented frontmatter carries a `type` and a `modified` time; no field links an entry to the session, message, or event that produced it ([memory docs](https://code.claude.com/docs/en/memory)). An entry with no source and no [validity window](/glossary/validity-window) can be read, edited, or deleted, yet never audited back to its origin. In a living codebase most facts change eventually; the failure modes are cataloged in [facts that change over time](/guides/facts-that-change-over-time).

## For builders: memory with event time

Claude Code's files answer for one developer on one machine; an agent you ship needs a memory layer of its own. For that layer, past.dev is a memory API: POST /api/v1/ingest takes raw text with its original timestamp, entity resolution links references to the same person across sources, and stored facts carry event time, validity windows, and supersession links. POST /api/v1/recall returns ranked, dated evidence with sources and one of four status values (Supported, Conflicted, NoKnownSupport, UnknownBecauseDegraded), running managed or self-hosted in your own Postgres. The [Memory API quickstart](/docs/memory-api/quickstart) and the [benchmarks](/benchmarks) are the places to start.
