Why Persistence Matters for AI Agents
In the world of AI development, creating agents that can maintain context over extended interactions is crucial. Imagine an AI assistant that forgets everything after one conversation—frustrating, right? Persistence solves this by enabling long-term memory, allowing agents to recall past decisions, user preferences, and ongoing tasks. This workshop focuses on implementing persistence using Claude's powerful tools, transforming stateless models into reliable, memory-equipped companions.
We'll progress from basic concepts to advanced agent architectures, using real code examples with the Anthropic Claude API. By the end, you'll have a fully functional persistent agent ready for production-like scenarios.
Short-Term vs. Long-Term Memory
AI models like Claude excel at short-term memory within a single conversation, holding context in the prompt window (up to 200K tokens for Claude 3.5 Sonnet). However, this resets on new sessions, limiting real-world utility.
- Short-term memory: In-session recall, fast but volatile.
- Long-term memory: Persistent storage across sessions, slower but enduring.
To bridge this gap, we leverage external storage. Claude's Filesystem API tool allows reading and writing files directly, perfect for JSON-based state management. This approach is:
- Simple: No databases needed initially.
- Scalable: Easy to extend to cloud storage.
- Secure: Controlled access via tools.
Setting Up Your Environment
Start by installing the Anthropic SDK:
go install github.com/anthropic-ai/sdk@latest
Or in Python:
pip install anthropic
You'll need an Anthropic API key from console.anthropic.com. Set it as an environment variable:
export ANTHROPIC_API_KEY=your-key-here
For demos, clone the workshop repository:
This repo contains complete code for a persistent todo agent—fork it and experiment!
Defining Persistence Tools
Claude uses a tools-first approach. Define read_state and write_state tools to handle JSON files.
Here's a Python example:
import json
import os
from anthropic import Anthropic
client = Anthropic()
STATE_FILE = 'agent_state.json'
def read_state():
if os.path.exists(STATE_FILE):
with open(STATE_FILE, 'r') as f:
return json.load(f)
return {}
def write_state(state):
with open(STATE_FILE, 'w') as f:
json.dump(state, f, indent=2)
# Tool definitions for Claude
tools = [
{
"name": "read_state",
"description": "Read the agent's persistent state from JSON file.",
"input_schema": {
"type": "object",
"properties": {},
},
},
{
"name": "write_state",
"description": "Write or update the agent's persistent state to JSON file.",
"input_schema": {
"type": "object",
"properties": {
"state": {
"type": "object",
"description": "The full state dictionary to save.",
}
},
},
},
]
These tools let Claude manage its own memory autonomously.
Building a Basic Persistent Loop
Create an interactive loop where Claude loads state, reasons, acts, and saves.
def agent_loop():
state = read_state()
messages = [{"role": "user", "content": "You are a helpful persistent agent. Use tools to manage your state."}]
while True:
response = client.messages.create(
model="claude-3-5-sonnet-20241022",
max_tokens=1024,
messages=messages,
tools=tools,
)
# Handle tool uses
for content in response.content:
if content.type == 'tool_use':
if content.name == 'read_state':
tool_result = {'state': state}
elif content.name == 'write_state':
new_state = content.input['state']
state.update(new_state)
write_state(state)
tool_result = {'success': True}
messages.append({
"role": "assistant",
"content": [{"type": "text", "text": content.text or ''}],
"tool_use": content,
})
messages.append({
"role": "user",
"content": [{
"type": "tool_result",
"tool_use_id": content.id,
"content": tool_result,
}],
})
else:
print(content.text)
user_input = input("You: ")
if user_input.lower() == 'quit':
break
messages.append({"role": "user", "content": user_input})
How it works:
- Load initial state.
- Send messages with tools.
- Claude decides to read/write state as needed.
- Execute tools server-side.
- Feed results back for continued reasoning.
Test it: Add a todo, quit, restart—the list persists!
Real-World Example: Persistent Todo Agent
Extend to a todo app. State schema:
{
"todos": [],
"user_preferences": {},
"session_count": 0
}
Prompt Claude: "Act as a todo manager. Track tasks in state. Greet returning users."
User interaction example:
You: Add 'Buy milk' to todos.
Agent: (Reads state → Adds task → Writes state) Task added! Your todos: ['Buy milk'].
You: Quit, then restart.
Agent: Welcome back! You have 1 todo: 'Buy milk'.
This demonstrates cross-session recall.
Advanced Techniques
Structured State Management
Use schemas for robust state:
- Todos: List of dicts with id, text, done.
- History: Rolling log of actions (trim to avoid bloat).
- Metadata: User ID, version.
Error Handling
Add retries and validation:
def safe_write_state(state):
try:
write_state(state)
return True
except Exception as e:
print(f"State save failed: {e}")
return False
Claude can check tool results for errors.
Scaling to Multiple Users
Use per-user files: state_{user_id}.json. Pass user_id in prompts.
Integrating Other Tools
Combine with filesystem for logs, or external DBs via custom tools.
Pro Tip: For high-scale, migrate to Redis/Postgres, but start with files for simplicity.
Workshop Challenges
- Beginner: Implement a counter that increments across sessions.
- Intermediate: Build a note-taking agent with search.
- Advanced: Create a multi-agent system sharing state files.
Solutions in the demo repo.
Best Practices
- Minimal State: Only save essentials to reduce latency.
- Versioning: Include 'version' key for migrations.
- Backup: Periodically copy state files off-site.
- Security: Sanitize inputs; use file permissions wisely.
- Monitoring: Log state changes for debugging.
Persistence unlocks agentic workflows like ongoing research, customer support, or personal assistants. Experiment, iterate, and deploy!
Word count: ~1250. Ready to build your first persistent agent?
<div style="text-align: center; margin-top: 2rem;"> <a href="https://www.aihero.dev/workshops/day-2-persistence" target="_blank" rel="noopener noreferrer" class="view-full-resource-btn" style="display: inline-block; background-color: #f97316; color: white; padding: 12px 24px; border-radius: 8px; text-decoration: none; font-weight: 600; transition: background-color 0.2s;">View Full Resource</a> </div>Stay ahead of the AI curve
The most important updates, news, and content — delivered in one weekly newsletter.