Welcome to Chapter 5!
In Chapter 4: Dynamic Prompt Engineering, we learned how to assemble a "Mission Briefing" for our agent. We gave it instructions based on its role and tools.
However, there was a hidden flaw in that system: Amnesia. Every time you closed AgentTool and opened it again, the agent forgot everything you taught it.
In this chapter, we will explore Persistent Agent Memory.
Imagine hiring a contractor to renovate your kitchen. On Monday, you tell them: "Please take your shoes off before entering." They comply.
On Tuesday, they come back, but they have forgotten everything. You have to tell them again: "Please take your shoes off." You have to do this every single day. This is inefficient and frustrating.
In AI development, we often teach agents lessons like:
.env."Without Persistent Memory, the agent is a blank slate every time a new session starts.
We want our "BugHunter" agent (from Chapter 1) to remember a specific rule: "Always add comments to fixed code."
We want this rule to stick, whether we run the agent today, tomorrow, or whether a teammate runs it on their computer.
To solve this, AgentTool gives agents a virtual "Physical Notebook." But since different information belongs in different places, we have three types of notebooks (Scopes):
~/.claude/agent-memory/)Analogy: A personal diary.
.claude/agent-memory/)Analogy: The job site logbook.
Jest for testing.".claude/agent-memory-local/)Analogy: Sticky notes on your monitor.
root."MEMORY.md FileSo, how does the agent actually "remember"? It's surprisingly simple.
BugHunter).MEMORY.md.MEMORY.md are read and injected into the System Prompt (from Chapter 4).Input: You tell the agent: "Remember that we strictly use TypeScript interfaces, not types."
System Action:
The agent writes to .claude/agent-memory/BugHunter/MEMORY.md:
# Learned Memories
- User prefers TypeScript interfaces over type aliases.
Next Session: When you run BugHunter again, the Runtime reads this file and whispers to the AI: "By the way, the user prefers interfaces."
Let's visualize how the system fetches these memories before the agent starts working.
Let's look at the code that manages these files. We will examine agentMemory.ts and agentMemorySnapshot.ts.
First, we need to know where on the hard drive to look. This depends entirely on the scope variable.
From agentMemory.ts:
// simplified from agentMemory.ts
export function getAgentMemoryDir(agentType: string, scope: AgentMemoryScope): string {
const dirName = sanitizeAgentTypeForPath(agentType)
switch (scope) {
case 'project':
// Shared with team (in Git)
return join(getCwd(), '.claude', 'agent-memory', dirName)
case 'user':
// Global user settings (Home dir)
return join(getMemoryBaseDir(), 'agent-memory', dirName)
case 'local':
// Project specific, but private
return getLocalAgentMemoryDir(dirName)
}
}
Explanation: This function acts as a traffic director. If you ask for 'project' memory, it points to the current working directory (getCwd). If you ask for 'user' memory, it points to the global system folder.
We don't just dump the text file into the chat. We give the agent instructions on how to use the memory.
From agentMemory.ts:
// simplified from agentMemory.ts
export function loadAgentMemoryPrompt(agentType, scope) {
const memoryDir = getAgentMemoryDir(agentType, scope)
// 1. Make sure the folder exists so the agent doesn't crash trying to write
ensureMemoryDirExists(memoryDir)
// 2. Return a text block telling the AI where its memory is
return buildMemoryPrompt({
displayName: 'Persistent Agent Memory',
memoryDir: memoryDir,
// Add guidelines like "Keep learnings general" for User scope
})
}
Explanation: This function ensures the "Notebook" exists (creating the folder if needed) and then generates a prompt telling the AI: "You have a memory file located at [path]. Read it to recall context."
This is the most complex part. Since Project Memory is shared via Git, what happens if your teammate updates the memory and you pull their changes?
We use a "Snapshot" system to detect updates.
From agentMemorySnapshot.ts:
// simplified from agentMemorySnapshot.ts
export async function checkAgentMemorySnapshot(agentType, scope) {
// 1. Read the "Snapshot" (The state from Git)
const snapshotMeta = await readJsonFile(getSnapshotJsonPath(agentType))
// 2. Read our local sync state
const syncedMeta = await readJsonFile(getSyncedJsonPath(agentType, scope))
// 3. Compare timestamps
if (snapshotMeta.updatedAt > syncedMeta.syncedFrom) {
// The project memory is newer than what we have!
return { action: 'prompt-update' }
}
return { action: 'none' }
}
Explanation:
snapshot.json.prompt-update, asking you if you want to import the new team memories.In this chapter, we learned about Persistent Agent Memory.
MEMORY.md) injected into the prompt.Now our agent knows who it is, what to do, and remembers past lessons. But what happens if the task is too big for one agent? It might need to split the work into parallel timelines.
Next Chapter: Context Forking Mechanism
Generated by Code IQ