Adding Persistent Memory to Mastra Agents
Free · Open source (MIT) · Works with LangChain, CrewAI, AutoGen · No signup
Your Mastra agent forgets everything between runs. Variables reset, conversation context vanishes, and learned preferences disappear. This happens because Mastra agents are stateless by default — they only remember what you explicitly persist. Here's how to add permanent memory that survives restarts, deployments, and crashes.
The Problem: Stateless Agents Lose Context
TypeScript AI agents built with Mastra run in isolated execution contexts. When your agent process ends — whether from a restart, deployment, or crash — all in-memory state disappears. Variables reset to their initial values, user preferences are forgotten, and conversation history vanishes.
This creates jarring user experiences. Your agent might ask the same questions repeatedly, lose track of ongoing tasks, or forget user preferences that were explicitly set. For production agents, this stateless behavior breaks continuity and makes agents feel broken rather than intelligent.
The core issue is that Mastra focuses on agent orchestration and workflow, not persistence. You need to layer on a memory system that survives process boundaries while staying simple enough to not complicate your agent logic.
The Fix: Add BotWire Memory
Install BotWire to add persistent key-value memory to any Mastra agent:
pip install botwire
Here's a working TypeScript agent with persistent memory:
// mastra-agent.ts
import { spawn } from 'child_process';
class MastraAgentWithMemory {
private memoryNamespace: string;
constructor(namespace: string) {
this.memoryNamespace = namespace;
}
private async setMemory(key: string, value: any): Promise<void> {
return new Promise((resolve, reject) => {
const python = spawn('python', ['-c', `
from botwire import Memory
m = Memory("${this.memoryNamespace}")
m.set("${key}", "${JSON.stringify(value)}")
`]);
python.on('close', (code) => code === 0 ? resolve() : reject());
});
}
private async getMemory(key: string): Promise<any> {
return new Promise((resolve) => {
const python = spawn('python', ['-c', `
from botwire import Memory
m = Memory("${this.memoryNamespace}")
result = m.get("${key}")
print(result if result else "null")
`]);
let output = '';
python.stdout.on('data', (data) => output += data);
python.on('close', () => {
try {
resolve(JSON.parse(output.trim()));
} catch {
resolve(null);
}
});
});
}
async processMessage(userId: string, message: string): Promise<string> {
// Load user context
const userContext = await this.getMemory(`user:${userId}`) || {
name: null,
preferences: {},
conversationCount: 0
};
userContext.conversationCount++;
// Your Mastra agent logic here
let response = `Message ${userContext.conversationCount}: ${message}`;
if (userContext.name) {
response = `Hi ${userContext.name}! ${response}`;
}
// Persist updated context
await this.setMemory(`user:${userId}`, userContext);
return response;
}
}
How Persistent Memory Works
The code above creates a memory layer that survives process restarts. Each Memory() instance is scoped to a namespace — think of it as a dedicated key-value store for your agent. Data persists across runs because BotWire stores everything remotely at https://botwire.dev.
The memory API is intentionally simple: set(key, value) writes data, get(key) reads it back. Keys are strings, values can be any JSON-serializable data. Memory operations are synchronous from Python's perspective but require async handling in TypeScript since we're spawning Python processes.
For cross-process coordination, multiple agent instances can share the same namespace:
# Agent instance A
from botwire import Memory
shared_memory = Memory("my-agent-cluster")
shared_memory.set("active_tasks", ["task1", "task2"])
# Agent instance B (different process/machine)
from botwire import Memory
shared_memory = Memory("my-agent-cluster")
tasks = shared_memory.get("active_tasks") # ["task1", "task2"]
You can list all keys in a namespace, delete specific keys, or clear entire namespaces when needed. Memory has no built-in TTL, so data persists until explicitly deleted.
Integration Patterns
For production Mastra agents, create a dedicated memory client class that handles the Python bridge:
// memory-client.ts
export class AgentMemory {
constructor(private namespace: string) {}
async remember(key: string, value: any, ttl?: number): Promise<void> {
const data = { value, expiresAt: ttl ? Date.now() + ttl : null };
// Python bridge code here (shortened for brevity)
}
async recall(key: string): Promise<any> {
const stored = await this.getFromPython(key);
if (!stored) return null;
// Check TTL
if (stored.expiresAt && Date.now() > stored.expiresAt) {
await this.forget(key);
return null;
}
return stored.value;
}
async forget(key: string): Promise<void> {
// Delete from memory
}
async listMemories(): Promise<string[]> {
// Return all keys in namespace
}
}
This pattern lets you add TTL logic, memory cleanup, and other agent-specific features while keeping the core persistence simple.
When NOT to Use BotWire
BotWire isn't the right choice for:
• Vector search or embeddings — it's key-value storage, not a semantic search engine. Use Pinecone or Weaviate for similarity matching. • High-throughput applications — the free tier caps at 1000 writes/day per namespace. For heavy workloads, consider Redis or self-hosting. • Sub-millisecond latency — HTTP API calls add network overhead. Use in-memory caches for ultra-low latency requirements.
FAQ
Why not just use Redis? Redis requires server setup, authentication, and infrastructure management. BotWire works immediately with zero configuration and includes a generous free tier.
Is this actually free? Yes, 1000 writes/day per namespace forever, with unlimited reads. No credit card or signup required. You can self-host the MIT-licensed version if needed.
What about data privacy? Data is stored on BotWire's servers. For sensitive data, use the self-hosted version (single FastAPI + SQLite service) or encrypt values before storage.
Get Started
Add persistent memory to your Mastra agents in under 5 minutes. Your users will notice the difference immediately — agents that remember context feel significantly more intelligent and useful.
pip install botwire
Full documentation and examples at botwire.dev.