Skip to content

Instantly share code, notes, and snippets.

@geyang
Created April 6, 2026 00:57
Show Gist options
  • Select an option

  • Save geyang/33b4feb11a74b5c2412eafa136c5c5cc to your computer and use it in GitHub Desktop.

Select an option

Save geyang/33b4feb11a74b5c2412eafa136c5c5cc to your computer and use it in GitHub Desktop.
Claude Code: Memory & Context Management Architecture

Memory & Context Management Architecture

Layer Hierarchy

┌─────────────────────────────────────────────────────────────┐
│  SYSTEM PROMPT  (constants/prompts.ts)                      │
│  ┌───────────────────────────────────────────────────────┐  │
│  │  CONTEXT LAYER (context.ts) — memoized until /compact │  │
│  │  ┌─────────────────────────────────────────────────┐  │  │
│  │  │  CONFIGURATION  (utils/config.ts, env.ts)       │  │  │
│  │  │  ┌───────────────────────────────────────────┐  │  │  │
│  │  │  │  MEMORY  (~/.claude/memory/)              │  │  │  │
│  │  │  │  ┌─────────────────────────────────────┐  │  │  │  │
│  │  │  │  │  MESSAGES (query.ts, messages.tsx)  │  │  │  │  │
│  │  │  │  │  ┌───────────────────────────────┐  │  │  │  │  │
│  │  │  │  │  │  PERSISTENCE & RESUME         │  │  │  │  │  │
│  │  │  │  │  │  (log.ts, ResumeConversation) │  │  │  │  │  │
│  │  │  │  │  └───────────────────────────────┘  │  │  │  │  │
│  │  │  │  └─────────────────────────────────────┘  │  │  │  │
│  │  │  └───────────────────────────────────────────┘  │  │  │
│  │  └─────────────────────────────────────────────────┘  │  │
│  └───────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────┘

1. System Prompt — constants/prompts.ts

getSystemPrompt() returns string[] (3 elements), later converted to TextBlockParam[] in querySonnetWithPromptCaching():

Segment / Function Content
getCLISyspromptPrefix() Identity, capabilities, tool usage rules
getEnvInfo() cwd, platform, model, date, git repo status
Security warnings Injection defense, permission boundaries
Memory instructions CLAUDE.md conventions

2. Context Layer — context.ts

getContext() — memoized; gathered once at startup, cleared by /compact.

Returns a dict; each key wrapped as XML in the system prompt via formatSystemPromptWithContext() (services/claude.ts):

<context name="codeStyle">...merged CLAUDE.md content...</context>
<context name="gitStatus">...branch, staging, commits...</context>

Context Sources

Key Source Notes
codeStyle getCodeStyle() (utils/style.ts) — walks cwd to root Root-first merge (deepest appears last)
gitStatus Branch, staging, recent commits, main branch, author's log Status truncated to 200 lines
directoryStructure File tree snapshot Taken once at startup
readme Project README.md Raw content
claudeFiles **/*/CLAUDE.md in subdirectories Additional per-dir instructions
Custom context projectConfig.context Set via claude context set k v

CLAUDE.md Resolution

/                     ← /CLAUDE.md (if exists)       ← appears FIRST in output
/home/user/           ← /home/user/CLAUDE.md
/home/user/project/   ← /home/user/project/CLAUDE.md ← appears LAST (deepest)

Collected deepest-first, then styles.reverse() before joining — root-first in final output.


3. Configuration — utils/config.ts, utils/env.ts

Scope Path Schema
Global ~/.claude.json (default); ~/.claude/config.json if CLAUDE_CONFIG_DIR set GlobalConfig
Project Inside global file → projects[absolutePath] ProjectConfig
Memory ~/.claude/memory/ Flat files
  • GlobalConfig: { theme, primaryApiKey, mcpServers, onboarding, numStartups, projects: { [path]: ProjectConfig } }
  • ProjectConfig: { allowedTools, context: {k:v}, mcpServers, dontCrawlDirectory, mcpContextUris }
  • MCP Server Precedence: Project config > .mcprc file > Global config

4. Memory System — ~/.claude/memory/

~/.claude/memory/
  MEMORY.md           ← index file (<200 lines)
  user_role.md        ← individual memory files with YAML frontmatter
  feedback_testing.md
  project_auth.md
  ...

System prompt instructs Claude to manage memory via Read/Write/Edit tools targeting ~/.claude/memory/. Each file has frontmatter:

---
name: memory name
description: one-line description
type: user | feedback | project | reference
---

Memory Types (from system prompt)

Type Purpose
user Role, preferences, knowledge
feedback Corrections and confirmed approaches
project Ongoing work, goals, decisions
reference Pointers to external resources

5. Conversation Messages — query.ts, utils/messages.tsx

Message Types

Type Role Content
UserMessage user Text input or tool_result blocks
AssistantMessage assistant Text + tool_use blocks + cost/duration
ProgressMessage (internal) Filtered before API

Normalization — normalizeMessagesForAPI()

  1. Filter out ProgressMessage
  2. Merge consecutive tool_result messages into one user message

Prompt Caching — addCacheBreakpoints()

Adds cache_control: { type: "ephemeral" } to last 2 messages (index > messages.length - 3). Reduces re-tokenization costs in recursive tool-use loops.


6. Persistence & Resume — utils/log.ts, hooks/useLogMessages.ts, screens/ResumeConversation.tsx

File Layout

~/.cache/claude-cli/{project-dir-hash}/messages/
  2025-01-27T01-31-35-104Z.json                     ← initial conversation
  2025-01-27T01-31-35-104Z-1.json                   ← fork 1
  2025-01-27T01-31-35-104Z-1-sidechain-1.json       ← sidechain off fork 1

ISO date filenames via dateToFilename(). Each file is an array of message objects with per-message metadata: { cwd, userType, sessionId, timestamp, version }.

At read-time, loadLogList() computes: date, forkNumber, firstPrompt, messageCount.

useLogMessages() hook auto-saves after each message array mutation.

Resume Flow

/resume → loadLogList() → user selects → deserializeMessages() (utils/conversationRecovery.ts) → new fork number → REPL

7. Conversation Compression — commands/compact.ts

/compact → send all messages + "summarize" prompt → API
        → reset token counts to 0, clear messages
        → inject summary as new starting context
        → clear memoized caches (getContext, getCodeStyle)

Restarts the conversation with compressed history; cache clearing forces fresh context on next query.


8. API Request Assembly — services/claude.ts

Public entry: querySonnet() wraps internal querySonnetWithPromptCaching().

Field Value
system TextBlockParam[] with cache_control on segments
messages Normalized, cache breakpoints on tail
tools Generated from zodToJsonSchema
thinking Optional budget_tokens (ANT-only, triggered by "think hard")
temperature 1.0

Retry logic: exponential backoff (500ms base, 32s max), up to 10 retries on 408/429/5xx.


9. Shell Persistence — utils/PersistentShell.ts

Singleton shell per session via getInstance(). Spawns login shell (-l) with GIT_EDITOR: 'true' to prevent interactive editors. File-based IPC (/tmp/claude-*). Queue-based serial execution (concurrency=1). Tracks cwd and exit codes.


Request Lifecycle

  CLI Startup
      │
      ▼
  getSystemPrompt()  ──────────────────────────────┐
      │                                            │
  getContext() [MEMOIZED]                          │
      │  walks CLAUDE.md, git, dir tree, readme    │
      ▼                                            ▼
  ┌─────────────────────────────────────────────────────┐
  │  SYSTEM: [core instructions | env info | security]  │
  │  + <context name="...">...</context> per key        │
  └───────────────────────────┬─────────────────────────┘
                              │
  User Input ─── processUserInput() ──▶ UserMessage
                              │
                              ▼
                  ┌───────────────────────┐
                  │   query()             │
                  │   formatSystemPrompt  │
                  │   + messages + tools  │
                  └─────────┬─────────────┘
                            │
                            ▼
              querySonnet() → API call with prompt caching
                            │
                            ▼
                   AssistantMessage
                            │
              ┌─────────────┴──────────────┐
              │                            │
        has tool_use?                 no tool_use
              │                            │
              ▼                            ▼
     Execute tool(s)              Render final response
     (concurrent if read-only,         │
      serial otherwise, max 10)        ▼
              │                  useLogMessages() → disk
              ▼
     tool_result → UserMessage
              │
              └──────▶ recurse query()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment