How Claude Code Remembers Without a Vector Database
Large language models are stateless.
Every time you send a request, the model does not truly “remember” what happened before. It simply receives a new input containing the system prompt, part of the conversation history, and the latest user message.
And yet, tools such as Claude Code can appear to remember project conventions, user preferences, previous corrections, and ongoing project decisions across sessions.
How does that work?
The obvious answer would be a vector database:
- Convert conversations into embeddings.
- Store them in a vector database.
- Embed the current query.
- Retrieve the most similar memories.
- Inject them back into the context.
That is how many Agent frameworks implement long-term memory.
Claude Code takes a surprisingly different approach.
It does not rely primarily on embeddings or a vector database. Instead, it combines:
- Structured Markdown files
- A persistent memory index
- On-demand content loading
- A language model acting as a memory selector
- Explicit memory aging and verification rules
The result is a memory architecture that is simple, inspectable, and practical.
This article explains how that architecture works, why traditional memory approaches often fall short, and which ideas can be reused in your own Agent systems.
1. LLMs Do Not Actually Remember
When you reach the fiftieth turn of a conversation, the model may still appear to remember what you said at the beginning.
But the model itself has not stored that information internally.
Each request usually looks roughly like this:
System prompt
+ Conversation history
+ Current user message
The application sends the previous messages back to the model every time.
What we commonly call an LLM’s short-term memory is therefore just its context window.
A useful analogy is to imagine a highly capable employee with severe amnesia.
The employee can write code, analyze documents, call APIs, and solve difficult problems. However, every morning, they arrive at work without remembering anything from the previous day.
To help them continue working, you must leave notes on their desk:
You are working on the payment migration project.
The team uses PostgreSQL, not MySQL.
Integration tests must use a real database.
The release freeze begins on March 5, 2026.
An Agent memory system is essentially responsible for managing those notes.
It must answer three questions:
- Where should the notes be stored?
- Who decides which notes are worth keeping?
- When should old notes be updated or removed?
2. Short-Term Memory and Long-Term Memory
It is useful to separate Agent memory into two categories.
Short-term memory
Short-term memory is the current context window.
It contains information such as:
- The current conversation
- Recent tool calls
- Files that were just opened
- Intermediate reasoning results
- The current task state
When the context becomes too large, older content may be compressed or summarized.
This type of memory only needs to survive during the current session.
Long-term memory
Long-term memory persists outside the context window.
It may contain:
- User background
- User preferences
- Project decisions
- Team conventions
- External references
- Stable behavioral instructions
Long-term memory should survive across conversations.
Claude Code’s memory architecture is primarily designed around this second category.
3. Why Agents Need More Than Conversation History
For a normal chatbot, sending previous messages back to the model may be enough.
An Agent has a different workload.
A coding Agent may repeatedly:
Read files
Call tools
Search the repository
Modify code
Run tests
Inspect errors
Read more files
Call more tools
Tool output and source code can consume the context window extremely quickly.
More importantly, the information an Agent should remember is not necessarily the original conversation.
Suppose a user says:
I have ten years of Go experience, but I am new to React.
The useful memory is not the exact sentence. It is the extracted fact:
The user is an experienced backend engineer but a React beginner.
Similarly, suppose the user says:
Do not use mocked database responses in integration tests. We had a production migration failure because the mocks hid a real issue.
The useful memory is a behavioral rule:
Integration tests should connect to a real database.
Why:
A previous mocked test passed while the production migration failed.
How to apply:
Use this rule for tests classified as integration tests.
These are structured facts and preferences, not merely pieces of conversation history.
4. Why Common Memory Approaches Often Fall Short
Before looking at Claude Code’s design, it is worth examining the most common approaches to Agent memory.
4.1 Sliding-window memory
A sliding window keeps the most recent N messages and discards everything older.
The implementation is simple:
Keep the last 20 messages.
Delete everything before them.
This controls context size, but it assumes that older information is less useful than recent information.
That assumption is often wrong.
A user may describe their technical background in the first message and then spend fifty messages discussing unrelated details. Once the initial message falls outside the window, the Agent loses an important part of the user profile.
The fundamental problem is that sliding windows remove information based on age rather than importance.
4.2 Conversation summaries
A more sophisticated solution is to summarize older conversations.
Instead of keeping the original messages, the system asks an LLM to compress them into a shorter representation.
For example:
Original:
Our API gateway is Kong, not Nginx.
Compressed summary:
The team discussed several infrastructure details.
The summary preserves the general topic but loses the detail that may later matter.
If the user later asks how to diagnose an API gateway error, the Agent may provide Nginx-specific advice because the fact that the project uses Kong has disappeared.
Summarization introduces several risks:
- Important details may be removed.
- Repeated summarization can progressively distort information.
- Summarization consumes additional tokens.
- Each summarization step adds latency.
- The model decides what is important before knowing what future questions will be asked.
Summaries are useful for short-term context management, but they are unreliable as the only form of long-term memory.
4.3 Vector-based memory
Vector memory is currently one of the most popular approaches.
Each memory is converted into an embedding and stored in a vector database.
When a new query arrives, the system:
- Embeds the query.
- Calculates similarity scores.
- Retrieves the top-K closest memories.
- Adds them to the prompt.
This works well in many retrieval systems, but Agent memory introduces additional difficulties.
Similarity is not relevance
A question about a bug may retrieve every previous memory containing bug-related concepts.
Those memories may be semantically similar but irrelevant to the current repository, feature, or file.
Irrelevant memory is not harmless. Once injected into the context, it can influence the model and contaminate the final answer.
Retrieval behavior can be unstable
Results depend on many variables:
- Embedding model
- Chunk size
- Similarity metric
- Retrieval threshold
- Top-K value
- Metadata filtering
- Indexing strategy
Changing the embedding model can significantly change which memories are retrieved.
The infrastructure is expensive to maintain
A production vector-memory system may require:
- An embedding service
- A vector database
- Chunking logic
- Index updates
- Deduplication
- Conflict resolution
- Deletion policies
- Metadata management
- Retrieval evaluation
For an Agent with only a few hundred candidate memories, this can become unnecessary architectural weight.
Memory becomes difficult to inspect
The original text may still exist somewhere, but the retrieval process is driven by high-dimensional vectors and similarity scores.
When the wrong memory is retrieved, debugging often requires inspecting:
- The original chunk
- Its embedding metadata
- The query embedding
- The similarity score
- The retrieval threshold
- Competing candidate memories
This is far less transparent than reading a Markdown file.
4.4 Tiered memory
Some Agent systems divide memory into multiple levels:
- Core memory
- Recent memory
- Recall memory
- Archival memory
The model may then move information between levels, similar to how an operating system manages memory.
This is theoretically elegant, but it gives the Agent another complicated job.
In addition to completing the user’s task, the Agent must decide:
- Which memory belongs in which level
- When a memory should be promoted
- When a memory should be archived
- Which archived memory should be restored
- How conflicting memories should be resolved
The memory manager can become almost as complicated as the Agent itself.
5. The Shared Weaknesses of Traditional Memory Systems
These approaches look different, but they often suffer from the same underlying problems.
Unrestricted free text
If the Agent is allowed to store anything, the memory collection quickly becomes a dumping ground.
It may save information such as:
The user asked a React question today.
This function uses useMemo.
Five lines of code were changed.
The test passed after the second attempt.
These records may be true, but they are not necessarily useful as long-term memory.
No distinction between memory types
User identity, behavioral preferences, project decisions, and external references are different kinds of information.
Storing all of them in the same format and retrieving them with the same method makes the system less precise.
No aging mechanism
A memory may be correct when it is written but wrong six months later.
For example:
The project uses Kong as its API gateway.
If the project later migrates to Nginx, the old memory becomes an authoritative error.
Outdated memory can be more dangerous than missing memory because the model may treat it as trusted context.
Too much focus on retrieval
Many systems spend most of their complexity on answering:
How do we retrieve the right memory?
But the earlier question is just as important:
Should this information have been stored at all?
Poor memory extraction creates a classic garbage-in, garbage-out problem.
6. Claude Code’s Two-Layer Memory Architecture
Claude Code separates memory into two independent layers:
Static memory
Dynamic memory
The static layer contains explicit instructions.
The dynamic layer contains information learned from interactions.
Together, they form the complete memory system.
7. Static Memory: The CLAUDE.md Hierarchy
The static layer is based on CLAUDE.md files.
These files contain declarative instructions that the Agent should know before performing a task.
Examples include:
- Coding standards
- Security policies
- Project architecture
- Testing conventions
- Commit requirements
- Team workflows
- User-level preferences
A single CLAUDE.md file would not be enough because these rules come from different sources and have different visibility requirements.
A company-wide security rule should not be managed in the same way as one developer’s local preference.
Claude Code therefore supports several layers.
Managed layer
The managed layer contains organization-level policies.
It may include rules such as:
Never commit secrets.
Do not send proprietary code to external services.
All database migrations require review.
These instructions are controlled by administrators.
User layer
The user layer contains global personal preferences that apply across projects.
For example:
Use concise commit messages.
Explain unfamiliar frontend concepts using backend analogies.
Do not add a summary after every response.
Project layer
The project layer contains repository-specific rules.
It is generally committed to version control so that all team members share it.
Examples include:
Use pnpm instead of npm.
Run integration tests before submitting changes.
The backend follows a hexagonal architecture.
Local layer
The local layer contains project-specific instructions that should not be shared with the team.
It can be used for local environment details or individual workflows.
Auto-memory layer
The automatic memory layer contains project-level preferences learned by Claude Code during interactions.
Unlike the previous layers, these memories are written by the Agent.
Team-memory layer
The team-memory layer allows automatically learned preferences to be shared with other team members when the corresponding functionality is enabled.
These layers are additive rather than mutually exclusive.
Claude Code combines the relevant instructions and injects them into the system prompt.
8. Includes and Conditional Rules
Static instructions can grow quickly, especially in large repositories.
Claude Code provides mechanisms to prevent every rule from being loaded all the time.
File inclusion
A CLAUDE.md file can reference another file.
Conceptually, it works like an include directive:
@~/company/security-rules.md
This allows multiple projects to reuse the same company policies without duplicating them.
A robust implementation must also protect against issues such as:
- Circular references
- Path traversal
- Recursive loading
- Missing files
Path-based conditional rules
Rules inside .claude/rules/ can be loaded only when the current file matches a path pattern.
For example:
---
name: Frontend conventions
description: Rules for React and Tailwind files
paths:
- "**/*.tsx"
- "**/*.jsx"
---
The rule is only relevant when the Agent is working with matching frontend files.
This avoids wasting context tokens on React instructions while editing backend Python code.
The broader design principle is important:
Instructions should be injected when they become relevant, not merely because they exist.
9. Protecting the Context Window
Any file that is automatically injected into the system prompt can become a context-window risk.
Limiting only the number of lines is not sufficient.
A file may contain fewer than 200 lines but still be extremely large because one line contains a huge string.
A safer design uses two independent limits:
const MAX_ENTRYPOINT_LINES = 200;
const MAX_ENTRYPOINT_BYTES = 25_000;
The content is truncated as soon as either limit is reached.
The system should also tell the model that truncation occurred, so the model knows that the loaded index may be incomplete.
This is a useful general rule for Agent systems:
Any user-controlled content entering the system prompt should be limited by both structural size and byte size.
10. Dynamic Memory: Learning From Interaction
Static instructions have one major limitation: someone must write them.
Suppose a user repeatedly tells the Agent:
Do not use mocks in integration tests.
The ideal system should recognize this as a durable preference and remember it automatically.
That is the role of dynamic memory.
The dynamic layer allows the Agent to:
Learn
→ Write
→ Retrieve
→ Apply
→ Verify
Claude Code implements this using structured files rather than unrestricted conversation storage.
11. The Four Memory Types
Claude Code restricts automatic memory to four categories:
const MEMORY_TYPES = [
"user",
"feedback",
"project",
"reference"
] as const;
This restriction is one of the most important parts of the architecture.
The Agent cannot simply store anything that appears interesting. It must decide which category the information belongs to.
11.1 User memory
User memory describes who the user is.
Examples:
The user has ten years of Go experience.
The user is new to React.
The user prefers explanations with practical code examples.
This allows the Agent to adapt its communication style.
An experienced backend engineer learning React does not need the same explanation as a complete programming beginner.
11.2 Feedback memory
Feedback memory describes behavioral preferences or confirmed working patterns.
For example:
Do not use mocked databases in integration tests.
A useful feedback memory should also include why the rule exists and when it applies:
Integration tests must connect to a real database.
**Why:** A mocked test previously passed while the production migration failed.
**How to apply:** Apply this rule to all tests classified as integration tests.
The explanation matters.
Without the Why, the Agent may apply the rule mechanically even in situations where an exception is reasonable.
Without the How to apply, the Agent may not understand the rule’s scope.
11.3 Project memory
Project memory records changing project facts and decisions.
Examples include:
The mobile release enters code freeze on March 5, 2026.
The payment migration must be completed before the April release.
The authentication redesign has been postponed.
Project memories should also include their reasoning and expected effect.
Relative dates should be converted into absolute dates.
Instead of storing:
The release freezes next Thursday.
the system should store:
The release freezes on March 5, 2026.
Relative dates lose meaning over time. Absolute dates remain interpretable.
11.4 Reference memory
Reference memory tells the Agent where information can be found.
For example:
Pipeline incidents are tracked in the Linear INGEST project.
Database runbooks are stored in the internal operations repository.
API contracts are documented in the platform workspace.
The Agent does not need to copy the external information into memory. It only needs to remember the correct pointer.
12. What Should Not Be Stored
A disciplined memory system needs exclusion rules.
Claude Code avoids storing information that can be obtained from a more authoritative source.
Examples include:
- Code structure
- File paths
- Function locations
- Recent Git changes
- Commit history
- Debugging steps
- Temporary task status
- Information already present in
CLAUDE.md - Facts that can be discovered with repository search
The principle is simple:
Only remember information that cannot be reliably reconstructed from the current system.
Code is alive. Memory is a snapshot.
If a memory says that AuthService is located in a particular file, but the code has since been refactored, the memory becomes misleading.
The repository itself should remain the source of truth for repository facts.
Similarly:
- Git history should come from Git.
- Current task state should come from the active conversation.
- Project rules already written in
CLAUDE.mdshould not be duplicated. - File locations should be confirmed through search.
This greatly reduces stale and redundant memory.
13. One File per Memory
Each memory is stored as an individual Markdown file.
A memory might look like this:
---
name: Avoid mocked integration databases
description: Integration tests should connect to a real database
type: feedback
---
Integration tests must connect to a real database.
**Why:** A mocked test previously passed while the production migration failed.
**How to apply:** Apply this to all tests classified as integration tests.
The frontmatter acts as the memory’s identity card.
It contains:
name: a human-readable identifierdescription: a concise explanation used during selectiontype: one of the supported memory categories
Using separate files provides several benefits:
- Memories are human-readable.
- Individual memories can be edited or deleted.
- Version control can track changes.
- Debugging is straightforward.
- The system can read metadata without loading full content.
14. Index Always Loaded, Content Loaded on Demand
Suppose an Agent has accumulated one hundred memories.
Loading every complete memory into the system prompt would consume too many tokens.
Loading none of them would make the memories invisible.
Claude Code solves this with an index file:
MEMORY.md
The system uses a two-stage strategy:
MEMORY.md index
→ Always available
Individual memory files
→ Loaded only when relevant
The index contains enough metadata for the Agent to know which memories exist.
It acts like the table of contents of a reference book.
You do not need to keep every chapter in working memory. You only need to know which chapters are available and open the relevant one when necessary.
This pattern is useful far beyond memory systems.
It can also be applied to:
- Large knowledge bases
- Tool catalogs
- Historical pull requests
- Runbooks
- Long technical documents
- Repository documentation
Whenever the total content is large but only a small subset is needed, use:
Persistent index
+ On-demand expansion
15. Memory Extraction Runs Separately
One possible implementation would be to ask the main Agent to decide whether to write a memory during every response.
That creates two problems.
The main Agent becomes distracted
The Agent must simultaneously:
- Solve the user’s task
- Decide whether something should be remembered
- Classify the memory
- Check for duplicates
- Write the file
This can reduce the quality of the main response.
Memory instructions consume repeated tokens
If every prompt includes instructions about extracting and writing memory, the same tokens are repeatedly processed.
Claude Code instead performs memory extraction using a separate process after the main query loop has completed.
The extraction Agent receives the relevant conversation context and evaluates whether anything deserves long-term storage.
Its responsibilities include:
- Inspecting user corrections, feedback, and durable facts.
- Comparing them with existing memories.
- Rejecting temporary or reconstructable information.
- Selecting one of the four memory types.
- Writing a structured memory file.
- Avoiding duplicate writes.
This reflects an important architectural principle:
Memory creation should be treated as a separate task, not as a side effect of every main response.
16. Using an LLM as a Memory Selector
When a new query arrives, Claude Code must determine which memories are relevant.
Instead of calculating embedding similarity, it lets a language model choose from the candidate list.
The process is roughly:
Step 1: Read memory metadata
The system scans only the beginning of each memory file.
This is enough to retrieve:
- Name
- Description
- Type
It does not need to load the full body.
Step 2: Build the candidate list
The selector receives something like:
Query:
How should I implement this integration test?
Available memories:
- user_backend_experience.md
Experienced Go developer, new to React
- feedback_no_mock.md
Integration tests must not use mocked databases
- project_release_freeze.md
Release freeze begins on March 5, 2026
Step 3: Select only highly relevant memories
The selector returns a small number of filenames, such as the top five.
The selection instruction is intentionally conservative:
Only choose memories that are clearly useful.
Do not select a memory merely because it is loosely related.
This matters because a false positive can be more damaging than a false negative.
Failing to retrieve one useful memory may produce a generic answer.
Injecting an incorrect memory can distort the entire response.
17. Why LLM Selection Can Beat Vector Search
Embedding similarity answers a mathematical question:
Which texts occupy nearby positions in vector space?
An LLM selector answers a semantic decision question:
Which of these memories would actually help answer the current request?
Those are not the same question.
A vector score such as 0.87 does not explain why a memory should be used. It still requires thresholds and ranking rules.
A language model can evaluate:
- The current task
- The memory description
- The memory type
- Existing conversation context
- Whether the information is already available
- Whether the memory may introduce noise
For a candidate collection of a few hundred memories, a small language model may be simpler and more accurate than maintaining a full vector-search pipeline.
This does not mean vector search is always wrong.
Vector retrieval remains valuable when:
- The candidate set contains millions of documents.
- Full semantic search is required.
- The system has no concise metadata.
- Approximate nearest-neighbor search is necessary for scale.
But for a small, structured, human-readable memory collection, LLM selection can be a better engineering trade-off.
18. Context-Aware Filtering
Memory retrieval should consider not only relevance, but also what is already present in the current context.
Claude Code applies filters such as:
Already surfaced memories
If a memory was already shown during the previous interaction, it does not need to consume another selection slot immediately.
This encourages the selector to consider new candidates.
Recently used tool references
If the Agent is already using a tool, loading an additional memory describing basic tool usage may be redundant.
However, warnings and known issues related to the tool may still be valuable.
This illustrates a broader principle:
Retrieval should depend on both the query and the information already available in the context.
19. Memory Injection and Staleness Warnings
Selected memories are not inserted as if the user had just written them.
They are wrapped as system-provided contextual information.
Conceptually:
<system-reminder>
This memory was saved 5 days ago.
Verify that it is still accurate before acting on it.
[Memory content]
</system-reminder>
The age of the memory is explicitly communicated to the model.
Recent memories may be used normally.
Older memories receive a warning reminding the Agent that they represent historical information.
This prevents a memory from automatically becoming permanent ground truth.
The Agent should treat memory as:
A historical snapshot
rather than:
The current state of reality
20. Verify Before Acting
When a memory references something that may have changed, the Agent should verify it using the current source of truth.
Examples:
- If a memory mentions a file path, confirm that the file still exists.
- If it mentions a function, search the repository.
- If it mentions a feature flag, inspect the current configuration.
- If it describes a project decision, check whether a newer decision exists.
- If the user is about to take action, verify before recommending the action.
The governing principle is:
A memory saying that something exists does not prove that it still exists.
This turns memory into a hint for investigation rather than unquestionable truth.
21. The Complete Memory Lifecycle
Claude Code’s dynamic memory system can be summarized as a loop.
Writing side
Conversation completes
→ Extraction Agent analyzes the interaction
→ Durable information is identified
→ Existing memories are checked
→ Information is classified
→ A structured Markdown file is written
→ MEMORY.md is updated
Reading side
New user query arrives
→ Memory metadata is scanned
→ Candidate memories are listed
→ An LLM selects relevant memories
→ Full memory files are loaded
→ Age warnings are added
→ Memories are injected into the context
→ The main Agent verifies them before acting
This creates a complete learning cycle:
Learn
→ Store
→ Discover
→ Select
→ Apply
→ Verify
→ Update
The architecture does not require an embedding pipeline or vector database.
It relies on structured files and model-based selection.
22. Four Design Principles Worth Reusing
Claude Code’s implementation suggests several general principles for building Agent memory.
Principle 1: Structured memory is better than unrestricted text
A free-form memory collection eventually becomes difficult to manage.
Requiring each memory to follow a schema forces the Agent to make a classification decision before storing anything.
A basic schema might include:
interface AgentMemory {
name: string;
description: string;
type: "user" | "feedback" | "project" | "reference";
content: string;
createdAt: string;
updatedAt?: string;
}
Additional fields may include:
interface AgentMemory {
name: string;
description: string;
type: "user" | "feedback" | "project" | "reference";
content: string;
reason?: string;
application?: string;
createdAt: string;
updatedAt?: string;
expiresAt?: string;
confidence?: number;
source?: string;
}
Even a small amount of structure is much better than an unrestricted memory log.
Principle 2: Keep the index available and load details on demand
Loading every memory wastes context.
Loading no memory prevents discovery.
An index provides the middle ground:
Small metadata index
→ Always visible
Detailed content
→ Loaded only when selected
This pattern is effective whenever a system contains many optional resources.
Principle 3: Use a language model for bounded selection problems
When the candidate set is small, retrieval can be framed as a classification or ranking task.
Instead of asking:
Which memory has the highest vector similarity?
ask:
Which memories are clearly useful for answering this query?
Language models are often strong at this kind of bounded semantic selection.
A possible selection prompt could be:
Given the current query and the available memory descriptions,
return at most five memory IDs.
Select only memories that are clearly useful.
Do not select memories based only on keyword overlap.
Return an empty list if none are relevant.
Principle 4: Memory must be time-aware and verifiable
Long-term memory should never be treated as timeless truth.
Every memory should ideally include:
- Creation time
- Last update time
- Optional expiration time
- Source
- Confidence
- Verification instructions
When a memory becomes old, the system should warn the Agent.
When the information can be checked against a live source, the Agent should verify it.
23. A Practical Architecture for Your Own Agent
A lightweight memory system inspired by these principles might use the following directory structure:
.agent/
├── AGENT.md
├── rules/
│ ├── frontend.md
│ ├── backend.md
│ └── testing.md
└── memory/
├── MEMORY.md
├── user_backend_experience.md
├── feedback_no_mock_tests.md
├── project_release_freeze.md
└── reference_pipeline_issues.md
The memory index might contain:
# Available Memories
- `user_backend_experience.md`
Experienced backend engineer who is new to React.
- `feedback_no_mock_tests.md`
Integration tests should connect to a real database.
- `project_release_freeze.md`
The project enters release freeze on March 5, 2026.
- `reference_pipeline_issues.md`
Pipeline incidents are tracked in the Linear INGEST project.
The runtime flow could then be:
async function retrieveMemories(
query: string
): Promise<AgentMemory[]> {
const candidates = await readMemoryMetadata();
const selectedIds = await selectMemoriesWithLLM({
query,
candidates,
maxResults: 5
});
const memories = await loadMemoryFiles(selectedIds);
return memories.map(addStalenessMetadata);
}
After the main response completes:
async function extractMemories(
conversation: Conversation
): Promise<void> {
const existingMemories = await readMemoryMetadata();
const proposedMemories = await extractWithLLM({
conversation,
existingMemories,
allowedTypes: [
"user",
"feedback",
"project",
"reference"
]
});
const validatedMemories =
proposedMemories
.filter(isDurable)
.filter(isNotReconstructable)
.filter(isNotDuplicate);
await writeMemoryFiles(validatedMemories);
await rebuildMemoryIndex();
}
This approach remains understandable without requiring specialized storage infrastructure.
24. How to Explain Agent Memory in an Interview
When asked how an Agent memory system works, saying only:
We store embeddings in a vector database and retrieve the top-K results.
is incomplete.
A stronger explanation should cover the whole lifecycle.
You could answer:
LLMs are stateless, so an Agent memory system must explicitly manage what information survives across requests and sessions. I separate short-term context from long-term memory.
For long-term memory, I avoid storing unrestricted conversation history. Memories are classified into structured types such as user profile, behavioral feedback, project state, and external references.
I keep a lightweight metadata index in the Agent’s context and load full memory content only when needed. For a relatively small candidate set, an LLM can act as a semantic selector instead of relying entirely on vector similarity.
Memory extraction is handled separately from the main Agent task, which improves response quality and makes deduplication easier.
Finally, memories include timestamps and are treated as historical snapshots. If a memory refers to code, configuration, or a project state, the Agent verifies it against the current source of truth before acting.
This answer demonstrates more than familiarity with retrieval.
It shows that you understand:
- Memory extraction
- Memory classification
- Storage
- Retrieval
- Context management
- Staleness
- Verification
- Operational trade-offs
Conclusion
The most interesting part of Claude Code’s memory architecture is not that it avoids a vector database.
The important part is how deliberately it controls the entire memory lifecycle.
It does not allow the Agent to store arbitrary text.
It distinguishes user information from feedback, project facts, and external references.
It keeps a lightweight index available while loading detailed memories only when needed.
It treats retrieval as a semantic selection task.
It isolates memory extraction from the main Agent workflow.
Most importantly, it assumes that memories can become outdated.
That leads to a simple but powerful rule:
Memory is not truth. Memory is a historical snapshot that may need verification.
Claude Code’s approach reflects a broader lesson in Agent engineering: sophisticated behavior does not always require sophisticated infrastructure.
Sometimes, a structured file system, a clear schema, and a carefully designed LLM workflow are enough to outperform a much more complicated retrieval stack.