Long-term Memory
Learn how to extend Deep Agent with persistent memory across conversations
Deep agents come with a local filesystem to offload memory. By default, this filesystem is stored in agent state and is transient to a single thread - files are lost when the conversation ends.
You can extend Deep Agent with long-term memory by using a CompositeBackend that routes specific paths to persistent storage. This enables hybrid storage where some files persist across threads while others remain ephemeral.
Overview
Two Filesystem Types
By default, Deep Agent maintains two separate filesystems:
1. Short-term (Transient) Filesystem
- Stored in the agent's state (via
StateBackend) - Persists only within a single thread
- Files are lost when the thread ends
- Accessed through standard paths:
/notes.txt,/workspace/draft.md
2. Long-term (Persistent) Filesystem
- Stored in a persistent backend (via
PersistentBackend) - Persists across all threads and conversations
- Survives agent restarts
- Accessed through paths prefixed with
/memories/:/memories/preferences.txt
Why Long-term Memory?
| Use Case | Short-term | Long-term |
|---|---|---|
| Temporary calculations | ✅ | ❌ |
| Session notes | ✅ | ❌ |
| User preferences | ❌ | ✅ |
| Project knowledge | ❌ | ✅ |
| Learned conventions | ❌ | ✅ |
| Research findings | ❌ | ✅ |
Setup
Configure Long-term Memory
Use a CompositeBackend that routes the /memories/ path to a PersistentBackend:
import { createDeepAgent } from 'ai-sdk-deep-agent';
import { anthropic } from '@ai-sdk/anthropic';
import { CompositeBackend, StateBackend, PersistentBackend } from 'ai-sdk-deep-agent';
import { InMemoryStore } from 'ai-sdk-deep-agent';
const store = new InMemoryStore();
const backend = new CompositeBackend(
new StateBackend(), // Default: ephemeral
{
'/memories/': new PersistentBackend({ store }),
}
);
const agent = createDeepAgent({
model: anthropic('claude-sonnet-4-5-20250929'),
backend,
systemPrompt: `You have long-term memory at /memories/.
- Read /memories/instructions.txt at the start of conversations
- Save important information to /memories/ for future reference
- Check /memories/ before asking users about their preferences`,
});How It Works
Path Routing
The CompositeBackend routes file operations based on path prefixes:
// Example: Hybrid storage setup
const backend = new CompositeBackend(
new StateBackend(), // Ephemeral
{
'/memories/': new PersistentBackend({ store }),
}
);
// File operations route to correct backend:
await backend.write('/draft.txt', '...'); // → StateBackend (ephemeral)
await backend.write('/memories/prefs.txt', '...'); // → PersistentBackend (persistent)Cross-thread Persistence
Files in /memories/ can be accessed from any thread:
import { v4 as uuidv4 } from 'uuid';
const agent = createDeepAgent({
model: anthropic('claude-sonnet-4-5-20250929'),
backend: compositeBackend,
systemPrompt: `Save user preferences to /memories/user_preferences.txt
and read them at the start of each conversation.`,
});
// Thread 1: Teach preferences
const config1 = { configurable: { thread_id: uuidv4() } };
await agent.generate({
prompt: 'Save my preference: I prefer TypeScript over JavaScript',
}, config1);
// Thread 2: Different conversation, same preferences
const config2 = { configurable: { thread_id: uuidv4() } };
const result = await agent.generate({
prompt: 'What are my language preferences?',
}, config2);
// Agent reads from /memories/user_preferences.txt and responds:
// "You prefer TypeScript over JavaScript"Common Patterns
Pattern 1: User Preferences
Store user preferences that persist across sessions:
const agent = createDeepAgent({
model: anthropic('claude-sonnet-4-5-20250929'),
backend: compositeBackend,
systemPrompt: `User Preferences
You have a file at /memories/user_preferences.txt with user settings.
At the start of each conversation:
1. Read /memories/user_preferences.txt
2. Apply those preferences to your responses
When users tell you their preferences:
1. Update /memories/user_preferences.txt using edit_file
Common preferences to remember:
- Programming languages (TypeScript vs JavaScript)
- Code style (tabs vs spaces, semicolons)
- Framework choices (React vs Vue)
- Communication style (concise vs detailed)`,
});Pattern 2: Self-Improving Instructions
An agent can update its own instructions based on feedback:
const agent = createDeepAgent({
model: anthropic('claude-sonnet-4-5-20250929'),
backend: compositeBackend,
systemPrompt: `You have a file at /memories/instructions.txt with additional
instructions and user feedback.
Process:
1. Read /memories/instructions.txt at the start of conversations
2. Follow those instructions in your responses
When users provide feedback like "please always do X" or "I prefer Y":
1. Update /memories/instructions.txt using edit_file
2. Include the date and context of the feedback
Over time, build up a comprehensive set of customized instructions.`,
});Pattern 3: Knowledge Base
Build up knowledge over multiple conversations:
const agent = createDeepAgent({
model: anthropic('claude-sonnet-4-5-20250929'),
backend: compositeBackend,
systemPrompt: `You are building a knowledge base about the project.
Structure:
/memories/project/architecture.md - System architecture
/memories/project/api-endpoints.md - API documentation
/memories/project/conventions.md - Coding conventions
/memories/project/team-preferences.md - Team choices
When you learn new information:
1. Save it to the appropriate file in /memories/project/
2. Use edit_file to update existing files
When answering questions:
1. Check /memories/project/ for relevant information
2. Use that knowledge in your responses`,
});Pattern 4: Research Projects
Maintain research state across sessions:
const researchAgent = createDeepAgent({
model: anthropic('claude-sonnet-4-5-20250929'),
backend: compositeBackend,
systemPrompt: `You are a research assistant working on long-term projects.
Research storage structure:
/memories/research/sources.txt - List of sources found
/memories/research/notes.txt - Key findings and notes
/memories/research/report.md - Final report draft
/memories/research/citations.bib - Bibliography
Process:
1. When given a research topic, save it to /memories/research/topic.txt
2. As you conduct research, update the files above
3. Each conversation continues where the previous one left off
4. Read existing research files before starting new research`,
});
// Session 1: Start research
await researchAgent.generate({
prompt: 'Research quantum computing applications in drug discovery',
});
// Session 2 (days later): Continue research
await researchAgent.generate({
prompt: 'Continue the research and add more findings',
});
// Agent has all previous research contextStore Implementations
InMemoryStore (Development)
Good for testing and development, but data is lost on restart:
import { InMemoryStore, PersistentBackend } from 'ai-sdk-deep-agent';
const store = new InMemoryStore();
const agent = createDeepAgent({
model: anthropic('claude-sonnet-4-5-20250929'),
backend: new CompositeBackend(
new StateBackend(),
{
'/memories/': new PersistentBackend({ store }),
}
),
});Custom RedisStore (Production)
For production, use a persistent store:
import { Redis } from 'ioredis';
import { PersistentBackend } from 'ai-sdk-deep-agent';
class RedisStore {
constructor(private redis: Redis) {}
async get(namespace: string[], key: string) {
const redisKey = [...namespace, key].join(':');
const data = await this.redis.get(redisKey);
return data ? JSON.parse(data) : undefined;
}
async put(namespace: string[], key: string, value: any) {
const redisKey = [...namespace, key].join(':');
await this.redis.set(redisKey, JSON.stringify(value));
}
async delete(namespace: string[], key: string) {
const redisKey = [...namespace, key].join(':');
await this.redis.del(redisKey);
}
async list(namespace: string[]) {
const pattern = namespace.join(':') + ':*';
const keys = await this.redis.keys(pattern);
const values = await Promise.all(
keys.map(async (key) => {
const value = await this.redis.get(key);
return {
key: key.split(':').pop()!,
value: JSON.parse(value!),
};
})
);
return values;
}
}
// Usage
const redis = new Redis({
host: 'localhost',
port: 6379,
});
const redisStore = new RedisStore(redis);
const agent = createDeepAgent({
model: anthropic('claude-sonnet-4-5-20250929'),
backend: new CompositeBackend(
new StateBackend(),
{
'/memories/': new PersistentBackend({ store: redisStore }),
}
),
});Best Practices
1. Use Descriptive Paths
Organize persistent files with clear paths:
// ✅ Good: Organized structure
/memories/user_preferences.txt
/memories/research/topic_a/sources.txt
/memories/research/topic_a/notes.txt
/memories/project/requirements.md
/memories/project/api-conventions.md
// ❌ Bad: Flat namespace
/memories/prefs1.txt
/memories/data.txt
/memories/stuff.txt2. Document the Memory Structure
Tell the agent what's stored where:
const agent = createDeepAgent({
systemPrompt: `Persistent memory structure:
User Preferences:
- /memories/user/preferences.txt - General user settings
- /memories/user/code-style.txt - Coding preferences
Project Knowledge:
- /memories/project/architecture.md - System design
- /memories/project/api.md - API documentation
- /memories/project/conventions.md - Team conventions
Research:
- /memories/research/active.md - Current research topics
- /memories/research/archive/ - Past research
Always check these locations before asking the user.`,
});3. Read Before Write
Encourage the agent to check existing memory before updating:
const agent = createDeepAgent({
systemPrompt: `Before saving information to /memories/:
1. Check if the file already exists (read_file)
2. If it exists, use edit_file to update it
3. If it doesn't exist, use write_file to create it
This preserves accumulated knowledge over time.`,
});4. Regular Summarization
Periodically summarize and consolidate memory:
await agent.generate({
prompt: `Review all files in /memories/ and create a consolidated summary.
1. Read all files in /memories/
2. Identify key information
3. Create /memories/summary.md with consolidated knowledge
4. Keep individual files for detail, but use summary for quick reference`,
});5. Namespace Isolation
For multi-tenant scenarios, use namespaced stores:
// Option 1: Separate stores per user
const userBackend = new CompositeBackend(
new StateBackend(),
{
'/memories/': new PersistentBackend({
store: new RedisStore(redis, `user:${userId}:`),
}),
}
);
// Option 2: Paths per user
const multiUserBackend = new CompositeBackend(
new StateBackend(),
{
'/memories/user1/': new PersistentBackend({ store: sharedStore }),
'/memories/user2/': new PersistentBackend({ store: sharedStore }),
}
);Examples
Example 1: Personal Assistant
import { createDeepAgent } from 'ai-sdk-deep-agent';
import { anthropic } from '@ai-sdk/anthropic';
import { CompositeBackend, StateBackend, PersistentBackend, InMemoryStore } from 'ai-sdk-deep-agent';
const store = new InMemoryStore();
const agent = createDeepAgent({
model: anthropic('claude-sonnet-4-5-20250929'),
backend: new CompositeBackend(
new StateBackend(),
{
'/memories/': new PersistentBackend({ store }),
}
),
systemPrompt: `You are a personal assistant with long-term memory.
Memory structure:
- /memories/profile.txt - User's profile information
- /memories/preferences.txt - User's likes and dislikes
- /memories/tasks.txt - Ongoing tasks and projects
- /memories/relationships.txt - Important people and connections
Workflow:
1. On conversation start, read all memory files
2. Use this context in your responses
3. When you learn new information, update memory files
4. Keep memory files organized and up-to-date`,
});
// Teach the agent about yourself
await agent.generate({
prompt: `My name is Alex. I'm a software engineer who loves TypeScript and hates meetings.
Save this to my profile.`,
});
// Weeks later, the agent remembers
const result = await agent.generate({
prompt: 'What do you know about me?',
});
// Agent reads from /memories/profile.txt and respondsExample 2: Project Documentation Agent
const docAgent = createDeepAgent({
model: anthropic('claude-sonnet-4-5-20250929'),
backend: new CompositeBackend(
new StateBackend(),
{
'/memories/docs/': new PersistentBackend({ store: docStore }),
}
),
systemPrompt: `You maintain project documentation.
Documentation structure:
- /memories/docs/overview.md - Project overview
- /memories/docs/api.md - API documentation
- /memories/docs/guides/ - Tutorial guides
- /memories/docs/changelog.md - Change log
When you make changes:
1. Always read existing documentation first
2. Use edit_file to update existing docs
3. Add entries to changelog.md with dates
4. Keep documentation consistent and accurate`,
});
// Session 1: Initial documentation
await docAgent.generate({
prompt: 'Create initial documentation for the project API',
});
// Session 2: Update documentation
await docAgent.generate({
prompt: 'The API added a new endpoint /users/:id. Update the docs.',
});
// Agent reads existing /memories/docs/api.md and updates itExample 3: Learning Agent
const learningAgent = createDeepAgent({
model: anthropic('claude-sonnet-4-5-20250929'),
backend: new CompositeBackend(
new StateBackend(),
{
'/memories/learned/': new PersistentBackend({ store: learningStore }),
}
),
systemPrompt: `You are a learning agent that builds knowledge over time.
Process:
1. Before answering, check /memories/learned/ for relevant information
2. After learning something new, save it to /memories/learned/
3. Organize knowledge by topic
Knowledge structure:
- /memories/learned/concepts/ - Concepts and definitions
- /memories/learned/patterns/ - Design patterns
- /memories/learned/best-practices/ - Best practices
- /memories/learned/troubleshooting/ - Solutions to problems
When you learn something:
1. Determine which category it belongs to
2. Save it to the appropriate file
3. Include context and examples`,
});
// Teach the agent over multiple sessions
await learningAgent.generate({
prompt: 'Teach me about React hooks, especially useEffect and useState',
});
// Agent learns and saves to /memories/learned/concepts/react-hooks.md
// Later, the agent uses what it learned
const result = await learningAgent.generate({
prompt: 'What are common React hooks patterns?',
});
// Agent reads from /memories/learned/patterns/react-hooks.mdTroubleshooting
Memory Not Persisting
Problem: Files saved to /memories/ are lost between conversations.
Solutions:
- Check backend configuration:
// ❌ Wrong: No persistent backend
const backend = new StateBackend();
// ✅ Correct: Composite backend with persistent storage
const backend = new CompositeBackend(
new StateBackend(),
{
'/memories/': new PersistentBackend({ store: myStore }),
}
);- Verify store is working:
// Test the store directly
await store.put(['test'], 'key', { data: 'test' });
const result = await store.get(['test'], 'key');
console.log(result); // Should return { data: 'test' }Agent Not Reading Memory
Problem: Agent doesn't access files in /memories/.
Solution: Explicitly instruct the agent to read memory:
const agent = createDeepAgent({
systemPrompt: `IMPORTANT: At the start of EVERY conversation:
1. Read /memories/instructions.txt
2. Read /memories/context.txt
3. Use this information in your responses
Do not wait for the user to remind you.`,
});Memory Getting Cluttered
Problem: /memories/ becomes disorganized over time.
Solution: Implement periodic cleanup:
await agent.generate({
prompt: `Clean up and reorganize /memories/:
1. Read all files in /memories/
2. Identify outdated or duplicate information
3. Consolidate related information
4. Create a clear organizational structure
5. Delete unnecessary files
Propose a new structure before making changes.`,
});Advanced Patterns
Pattern: Hierarchical Memory
const agent = createDeepAgent({
backend: new CompositeBackend(
new StateBackend(),
{
// Short-term session memory (1 day)
'/memories/session/': new PersistentBackend({
store: sessionStore,
ttl: 86400, // 24 hours
}),
// Medium-term project memory (1 week)
'/memories/project/': new PersistentBackend({
store: projectStore,
ttl: 604800, // 7 days
}),
// Long-term knowledge (permanent)
'/memories/knowledge/': new PersistentBackend({
store: knowledgeStore,
ttl: null, // Never expires
}),
}
),
systemPrompt: `Memory hierarchy:
- /memories/session/ - Current conversation context (cleared daily)
- /memories/project/ - Project-specific information (cleared weekly)
- /memories/knowledge/ - Permanent knowledge (never cleared)
Save information to the appropriate level based on its longevity.`,
});Pattern: Memory Versioning
await agent.generate({
prompt: `When updating /memories/important.txt:
1. Read the current content
2. Save a backup to /memories/archive/important_YYYYMMDD_HHMMSS.txt
3. Update the main file
4. Add a changelog entry to /memories/changelog.md
This provides version history for important memory files.`,
});Summary
Long-term memory provides:
| Feature | Benefit |
|---|---|
| Cross-session persistence | Information survives conversation restarts |
| Knowledge accumulation | Agent learns and improves over time |
| Personalization | Remembers user preferences and context |
| Hybrid storage | Ephemeral workspace + persistent knowledge |
| Flexible backends | Choose storage based on your needs |
| Path-based routing | Easy to organize different types of memory |
Next Steps
- Backends Documentation - Learn about storage options
- Agent Harness - Understand filesystem tools
- Customization - Configure agents for your use case