CodeDocs Vault

8. Memory and Context

8.1 Three persistent stores

Claude Code has three distinct long-lived stores that survive across sessions:

Store Location Who writes Who reads Purpose
Auto-memory ~/.claude/projects/<slug>/memory/ The model, via a stop-hook fork Every turn (via loadMemoryPrompt) Durable facts about user, feedback, project, references
CLAUDE.md Repo / ~/.claude/ / /etc/claude-code/ Humans (mainly) Every turn Project rules, conventions, workflows
Session transcript ~/.claude/sessions/<sessionId>/transcript.jsonl The system as messages arrive --resume path Exact message history for resumption

8.2 Auto-memory

Structure

~/.claude/projects/<project-slug>/memory/
├── MEMORY.md                 # Index, always loaded, capped at 200 lines / 25 KB
├── user_role.md              # One memory per file
├── feedback_testing.md
├── project_merge_freeze.md
├── reference_linear_ingest.md
└── auto/                     # Auto-extracted by session memory
    └── <topic>.md

Each memory file has YAML frontmatter:

---
name: user role
description: user is a data scientist, currently focused on observability/logging
type: user
---
 
Body text here, optionally with **Why:** and **How to apply:** lines for feedback/project types.

MEMORY.md is a curated index — not a memory itself. Entries are one line under ~150 characters: - [Title](file.md) — one-line hook.

Guards

Four types, four discipline levels (memdir/memoryTypes.ts)

Type When it's valuable Body structure
user User role, knowledge level, preferences Free-form
feedback Corrections AND confirmations from user Rule + **Why:** + **How to apply:**
project Who/what/when about the work Fact + **Why:** + **How to apply:**
reference External system pointers (Linear, Grafana, Slack) Free-form

The "**Why:** + **How to apply:**" scaffolding is the single cleverest part of this prompt: it forces the model to capture the reason behind a rule, which later lets it judge whether the rule applies in an edge case (or whether the rule is now stale).

When NOT to save

The exclusion list (reproduced in doc 07) bans saving anything derivable from the code itself — patterns, architecture, file paths, git history, debugging solutions. The explicit clause is:

These exclusions apply even when the user explicitly asks you to save. If they ask you to save a PR list or activity summary, ask what was *surprising* or *non-obvious* about it — that is the part worth keeping.

This resists the failure mode where users treat memory as scratchpad.

Recall-side drift

A memory that names a specific function, file, or flag is a claim that it existed *when the memory was written*. It may have been renamed, removed, or never merged. Before recommending it: if the memory names a file path, check the file exists. If the memory names a function or flag, grep for it.

The recall prompt explicitly flags that git log is authoritative for recent change history and that code is authoritative for current state — memory should be verified when about to act on.

Extraction path (services/extractMemories/)

Auto-memory extraction runs as a Stop hook. When the model finishes a turn without tool calls:

  1. Check token delta and tool-call count since last extraction (gate in services/SessionMemory/).
  2. Build an extraction prompt (buildExtractCombinedPrompt / buildExtractAutoOnlyPrompt).
  3. Spawn a perfect fork (shares cache) via runForkedAgent().
  4. Fork uses FileWrite / FileRead / FileEdit to update MEMORY.md and topic files.
  5. Log metrics (tokens, count of memories added/updated).

Session memory (services/SessionMemory/)

A separate, background track: periodic forked subagent extracts highlights to a session-scoped transcript. Gated by shouldExtractMemory() with config DEFAULT_SESSION_MEMORY_CONFIG (token threshold + tool-call count since last run).

8.3 CLAUDE.md — utils/claudemd.ts

Project rules, loaded every turn (cached until /clear or /compact). Priority order (reverse applied so closest wins):

  1. /etc/claude-code/CLAUDE.md — managed by the org, global across users.
  2. ~/.claude/CLAUDE.md — user, all projects.
  3. CLAUDE.md, .claude/CLAUDE.md, .claude/rules/*.md — checked into the repo.
  4. CLAUDE.local.md — per-project private.

Supports @include path directives for cross-file composition.

Nested CLAUDE.md

When FileReadTool reads a file inside a directory that has a CLAUDE.md sibling, it records a nestedMemoryAttachmentTriggers entry (tools/FileReadTool/FileReadTool.ts:27). On the next turn, that CLAUDE.md is auto-attached so the agent picks up local rules without the user having to ask.

Why read-only agents skip it

omitClaudeMd: true on BuiltInAgentDefinition (loadAgentsDir.ts:128-132). The Explore and Plan agents don't write, so the commit / PR / lint guidance in CLAUDE.md is noise. Dropping it saves tokens.

Cached break-cycle

bootstrap/state.ts holds cachedClaudeMdContent to break a load-order cycle: yoloClassifier → claudemd → filesystem → permissions → yoloClassifier. Without the cache, the permission system can't decide whether to allow the claudemd read because its own evaluation needs the claudemd content.

8.4 Context injection points

System prompt

Composed once per turn (cached sections unless mutated). See doc 04 §4.5 for the full structure.

User context (prepended to conversation)

utils/queryContext.ts:fetchSystemPromptParts returns a userContext dict. The keys are flattened into a user-role message that includes:

See constants/prompts.ts:606-643 for the exact <env> block format.

Attachments (per-turn <system-reminder> messages)

Pushed on specific triggers:

Function Result Clearing (FRC) and summarize-tool-results

Two late dynamic sections (constants/prompts.ts:522-526):

Memory prompt body

loadMemoryPrompt() returns the composed text the model sees about how to use memory: the four types, the "what not to save" section, the "when to access" guidance, and the "before recommending from memory" drift caveat. Also includes MEMORY.md content and relevant topic files selected by findRelevantMemories().

8.5 File history (utils/fileHistory.ts)

Every FileEditTool / FileWriteTool call records a snapshot so /rewind can restore. Persisted as fileHistoryState in AppState and serialized into the session log. Not in the prompt — purely client-side recovery.

8.6 Attribution (utils/commitAttribution.ts, utils/attribution.ts)

Tracks whether commit messages should be co-authored by Claude and which exact suffix to use. Derived from settings and fed into the git-commit prompt section (tools/BashTool/prompt.ts:79-80 for external; ant-only variants configure differently). Under certain modes (e.g. undercover, ant internal) the attribution is suppressed or altered.

8.7 The read-file state cache (utils/fileStateCache.ts)

Per-conversation FileStateCache tracks every file Read has visited. Used by:

This is the mechanism that prevents the most common LLM-editor failure mode: editing a file based on a stale cache.