Memory System
此内容尚不支持你的语言。
Claude Code’s memory system gives the agent persistent, file-based knowledge that survives across sessions. Unlike the ephemeral conversation context (which is lost after compaction or session end), memory files accumulate learnings, preferences, and project knowledge over time.
Architecture
Section titled “Architecture”graph TD subgraph "Memory Directory (~/.claude/projects/<project>/memory/)" E["MEMORY.md<br/>(index file, max 200 lines)"] T1["topic-1.md"] T2["topic-2.md"] L["logs/YYYY/MM/YYYY-MM-DD.md<br/>(daily logs)"] end
subgraph "System Prompt" SP[Memory Prompt Section] end
subgraph "Team Memory" TM["Team member shared memory"] end
E --> SP T1 --> SP TM --> SPThe memory directory follows a standard structure:
- MEMORY.md — the index/entrypoint file, loaded into every system prompt
- Topic files — detailed memory on specific topics, referenced from MEMORY.md
- Daily logs — chronological activity logs (used in KAIROS/assistant mode)
Path Resolution
Section titled “Path Resolution”Memory paths are resolved by getAutoMemPath() in src/memdir/paths.ts with a priority chain:
export const getAutoMemPath = memoize((): string => { // 1. Env var override (Cowork/SDK) const override = getAutoMemPathOverride() ?? getAutoMemPathSetting() if (override) return override
// 2. Default: ~/.claude/projects/<sanitized-git-root>/memory/ const projectsDir = join(getMemoryBaseDir(), 'projects') return join(projectsDir, sanitizePath(getAutoMemBase()), AUTO_MEM_DIRNAME) + sep})The resolution order:
| Priority | Source | Use Case |
|---|---|---|
| 1 | CLAUDE_COWORK_MEMORY_PATH_OVERRIDE env var | Cowork space-scoped mount |
| 2 | autoMemoryDirectory in settings.json | User custom directory |
| 3 | ~/.claude/projects/<sanitized-path>/memory/ | Default |
Git Worktree Awareness
Section titled “Git Worktree Awareness”The base path uses findCanonicalGitRoot() so all worktrees of the same repository share one memory directory:
function getAutoMemBase(): string { return findCanonicalGitRoot(getProjectRoot()) ?? getProjectRoot()}Enable/Disable Logic
Section titled “Enable/Disable Logic”Auto-memory can be disabled through multiple mechanisms:
export function isAutoMemoryEnabled(): boolean { // 1. Env var override (explicit off) if (isEnvTruthy(process.env.CLAUDE_CODE_DISABLE_AUTO_MEMORY)) return false
// 2. Bare mode (--bare / SIMPLE) if (isEnvTruthy(process.env.CLAUDE_CODE_SIMPLE)) return false
// 3. CCR without persistent storage if (isEnvTruthy(process.env.CLAUDE_CODE_REMOTE) && !process.env.CLAUDE_CODE_REMOTE_MEMORY_DIR) return false
// 4. Settings.json opt-out const settings = getInitialSettings() if (settings.autoMemoryEnabled !== undefined) return settings.autoMemoryEnabled
// 5. Default: enabled return true}MEMORY.md: The Index File
Section titled “MEMORY.md: The Index File”MEMORY.md is the entrypoint that gets loaded into the system prompt. It has strict size limits:
export const ENTRYPOINT_NAME = 'MEMORY.md'export const MAX_ENTRYPOINT_LINES = 200export const MAX_ENTRYPOINT_BYTES = 25_000 // ~125 chars/line at 200 linesWhen MEMORY.md exceeds these limits, it’s truncated with a warning:
export function truncateEntrypointContent(raw: string): EntrypointTruncation { const contentLines = raw.trim().split('\n') const wasLineTruncated = contentLines.length > MAX_ENTRYPOINT_LINES const wasByteTruncated = raw.trim().length > MAX_ENTRYPOINT_BYTES
if (!wasLineTruncated && !wasByteTruncated) { return { content: raw.trim(), /* ... */ } }
// Line-truncate first (natural boundary), then byte-truncate let truncated = wasLineTruncated ? contentLines.slice(0, MAX_ENTRYPOINT_LINES).join('\n') : raw.trim()
if (truncated.length > MAX_ENTRYPOINT_BYTES) { const cutAt = truncated.lastIndexOf('\n', MAX_ENTRYPOINT_BYTES) truncated = truncated.slice(0, cutAt > 0 ? cutAt : MAX_ENTRYPOINT_BYTES) }
return { content: truncated + `\n\n> WARNING: ${ENTRYPOINT_NAME} is ${reason}.Only part of it was loaded. Keep index entries to one line under ~200 chars;move detail into topic files.`, // ... }}The design forces MEMORY.md to be an index, not a dump. Each entry should be one line under ~200 chars, pointing to topic files for details.
Memory Types
Section titled “Memory Types”Memory content is categorized by type, defined in src/memdir/memoryTypes.ts:
// Memory taxonomy (from memoryTypes.ts)// - User preferences and style// - Project architecture and conventions// - Feedback and corrections// - Reference documentationThe memory prompt includes specific guidance on what to save and what not to save:
import { MEMORY_FRONTMATTER_EXAMPLE, TRUSTING_RECALL_SECTION, TYPES_SECTION_INDIVIDUAL, WHAT_NOT_TO_SAVE_SECTION, WHEN_TO_ACCESS_SECTION,} from './memoryTypes.js'Agent-Specific Memory
Section titled “Agent-Specific Memory”Custom agents can declare their own memory scope:
// In agent frontmatter or JSONmemory: 'user' | 'project' | 'local'| Scope | Location | Shared? |
|---|---|---|
user | User-level directory | Across all projects |
project | Project-level directory | Within project |
local | Local-only | Not shared |
When an agent has memory enabled, its system prompt is dynamically appended:
getSystemPrompt: () => { if (isAutoMemoryEnabled() && memory) { return systemPrompt + '\n\n' + loadAgentMemoryPrompt(agentType, memory) } return systemPrompt}Additionally, file tools (Read, Edit, Write) are automatically injected into the agent’s tool set when memory is enabled:
if (isAutoMemoryEnabled() && parsed.memory && tools !== undefined) { const toolSet = new Set(tools) for (const tool of [FILE_WRITE_TOOL_NAME, FILE_EDIT_TOOL_NAME, FILE_READ_TOOL_NAME]) { if (!toolSet.has(tool)) { tools = [...tools, tool] } }}Memory Snapshots
Section titled “Memory Snapshots”The AGENT_MEMORY_SNAPSHOT feature enables project-level memory snapshots — a way to distribute pre-built memory to all users of a project:
async function initializeAgentMemorySnapshots(agents: CustomAgentDefinition[]): Promise<void> { await Promise.all(agents.map(async agent => { if (agent.memory !== 'user') return const result = await checkAgentMemorySnapshot(agent.agentType, agent.memory) switch (result.action) { case 'initialize': // Copy snapshot to local if no local memory exists await initializeFromSnapshot(agent.agentType, agent.memory, result.snapshotTimestamp!) break case 'prompt-update': // Newer snapshot available — flag for user prompt agent.pendingSnapshotUpdate = { snapshotTimestamp: result.snapshotTimestamp! } break } }))}Team Memory
Section titled “Team Memory”The TEAMMEM feature enables shared memory across team members:
// src/memdir/memdir.ts — conditional importconst teamMemPaths = feature('TEAMMEM') ? require('./teamMemPaths.js') : nullTeam memory paths (src/memdir/teamMemPaths.ts) and team memory prompts (src/memdir/teamMemPrompts.ts) allow teammates to share a common memory directory, enabling knowledge transfer between agents in the same team.
Extract Mode
Section titled “Extract Mode”The EXTRACT_MEMORIES feature runs a background agent that extracts memories from the conversation:
export function isExtractModeActive(): boolean { if (!getFeatureValue_CACHED_MAY_BE_STALE('tengu_passport_quail', false)) return false return !getIsNonInteractiveSession() || getFeatureValue_CACHED_MAY_BE_STALE('tengu_slate_thimble', false)}The background extraction agent scans conversation turns for memorable information and writes it to the memory directory. When the main agent writes memories itself, the background agent skips those ranges (deduplication via hasMemoryWritesSince).
Daily Log Mode
Section titled “Daily Log Mode”In KAIROS/assistant sessions, memory takes a different form — daily log files:
export function getAutoMemDailyLogPath(date: Date = new Date()): string { const yyyy = date.getFullYear().toString() const mm = (date.getMonth() + 1).toString().padStart(2, '0') const dd = date.getDate().toString().padStart(2, '0') return join(getAutoMemPath(), 'logs', yyyy, mm, `${yyyy}-${mm}-${dd}.md`)}Rather than maintaining MEMORY.md as a live index, the agent appends to date-named log files as it works. A separate nightly /dream skill distills these logs into topic files and MEMORY.md.
Path Validation
Section titled “Path Validation”Memory paths undergo strict security validation:
// src/memdir/paths.ts — validateMemoryPathfunction validateMemoryPath(raw: string | undefined, expandTilde: boolean): string | undefined { // Reject: relative paths, root/near-root, Windows drive-root, // UNC paths, null bytes if ( !isAbsolute(normalized) || normalized.length < 3 || /^[A-Za-z]:$/.test(normalized) || normalized.startsWith('\\\\') || normalized.startsWith('//') || normalized.includes('\0') ) { return undefined } return (normalized + sep).normalize('NFC')}The isAutoMemPath() function is used by the filesystem permission system to grant write access to memory files without explicit user permission — a carve-out that makes memory writes seamless but requires careful path validation to prevent abuse.