The problem
Your AI agent forgets everything between conversations. Users repeat themselves, context is lost, and the experience feels broken.The solution
Memory gives your agent persistent, searchable storage for facts extracted from conversations. When a user says “I prefer dark mode” or “The client is risk-averse,” those facts are stored and can be retrieved later.How it works
- Add memories - Pass conversation messages, we extract discrete facts
- Search memories - Query by meaning, not just keywords
- Filter by tags - Scope memories using 12 generic indexed tag fields
- Fact extraction (turning “I like X but hate Y” into separate facts)
- Deduplication (updating existing facts instead of creating duplicates)
- Semantic search (finding “investment preferences” when you stored “conservative strategies”)
Quick start
# Add a memory
curl -X POST https://api.case.dev/memory/v1 \
-H "Authorization: Bearer $CASEDEV_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"messages": [
{"role": "user", "content": "Remember that this client prefers conservative investments."}
],
"tag_1": "client_123",
"tag_2": "matter_456",
"category": "preference"
}'
# Search memories
curl -X POST https://api.case.dev/memory/v1/search \
-H "Authorization: Bearer $CASEDEV_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"query": "investment preferences",
"tag_1": "client_123",
"top_k": 5
}'
# Add a memory
casedev memory:v1 create \
--message '{"role": "user", "content": "Remember that this client prefers conservative investments."}' \
--tag-1 client_123 \
--tag-2 matter_456 \
--category preference
# Search memories
casedev memory:v1 search \
--query "investment preferences" \
--tag-1 client_123 \
--top-k 5
import Casedev from 'casedev';
const client = new Casedev({ apiKey: process.env.CASEDEV_API_KEY });
// 1. Store memories from a conversation
const result = await client.memory.add({
messages: [
{ role: 'user', content: 'Remember that this client prefers conservative investments and is risk-averse.' }
],
tag_1: 'client_123', // Your client ID
tag_2: 'matter_456', // Your matter/case ID
category: 'preference'
});
console.log(result.results);
// [
// { id: 'mem_abc', memory: 'Client prefers conservative investments', event: 'ADD' },
// { id: 'mem_def', memory: 'Client is risk-averse', event: 'ADD' }
// ]
// 2. Later, search for relevant memories
const memories = await client.memory.search({
query: 'investment preferences',
tag_1: 'client_123',
top_k: 5
});
console.log(memories.results[0].memory);
// "Client prefers conservative investments"
import casedev
client = casedev.Casedev(api_key=os.environ['CASEDEV_API_KEY'])
# 1. Store memories from a conversation
result = client.memory.v1.create(
messages=[
{'role': 'user', 'content': 'Remember that this client prefers conservative investments and is risk-averse.'}
],
tag_1='client_123', # Your client ID
tag_2='matter_456', # Your matter/case ID
category='preference'
)
print(result.results)
# [
# {'id': 'mem_abc', 'memory': 'Client prefers conservative investments', 'event': 'ADD'},
# {'id': 'mem_def', 'memory': 'Client is risk-averse', 'event': 'ADD'}
# ]
# 2. Later, search for relevant memories
memories = client.memory.v1.search(
query='investment preferences',
tag_1='client_123',
top_k=5
)
print(memories.results[0].memory)
# "Client prefers conservative investments"
// Store memories from a conversation
result, _ := client.Memory.V1.New(ctx, casedev.MemoryV1NewParams{
Messages: casedev.F([]casedev.MemoryV1NewParamsMessage{{
Role: casedev.F("user"),
Content: casedev.F("Remember that this client prefers conservative investments and is risk-averse."),
}}),
Tag1: casedev.F("client_123"),
Tag2: casedev.F("matter_456"),
Category: casedev.F("preference"),
})
fmt.Println(result.Results)
// Later, search for relevant memories
memories, _ := client.Memory.V1.Search(ctx, casedev.MemoryV1SearchParams{
Query: casedev.F("investment preferences"),
Tag1: casedev.F("client_123"),
TopK: casedev.F(int64(5)),
})
fmt.Println(memories.Results[0].Memory)
Tag fields
Memory provides 12 generic indexed tag fields (tag_1 through tag_12) for filtering. You decide what each tag means for your application:
| Use Case | tag_1 | tag_2 | tag_3 | tag_4 |
|---|---|---|---|---|
| Legal | client_id | matter_id | attorney_id | session_id |
| Healthcare | patient_id | encounter_id | provider_id | department |
| E-commerce | customer_id | order_id | product_id | session_id |
| Support | user_id | ticket_id | agent_id | channel |
All tag fields are indexed for fast filtering. Use them for any dimension you need to query by.
Example: Legal application
# Store a memory scoped to client + matter
curl -X POST https://api.case.dev/memory/v1 \
-H "Authorization: Bearer $CASEDEV_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"messages": [
{"role": "user", "content": "The patent filing deadline is March 15th, 2026."}
],
"tag_1": "client_acme_corp",
"tag_2": "matter_patent_2026_001",
"tag_3": "atty_jane_smith",
"category": "deadline"
}'
# Search only this client's deadlines
curl -X POST https://api.case.dev/memory/v1/search \
-H "Authorization: Bearer $CASEDEV_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"query": "upcoming deadlines",
"tag_1": "client_acme_corp",
"category": "deadline",
"top_k": 10
}'
# List all memories for a specific matter
curl "https://api.case.dev/memory/v1?tag_1=client_acme_corp&tag_2=matter_patent_2026_001" \
-H "Authorization: Bearer $CASEDEV_API_KEY"
# Store a memory scoped to client + matter
casedev memory:v1 create \
--message '{role: user, content: "The patent filing deadline is March 15th, 2026."}' \
--tag-1 client_acme_corp \
--tag-2 matter_patent_2026_001 \
--tag-3 atty_jane_smith \
--category deadline
# Search only this client's deadlines
casedev memory:v1 search \
--query "upcoming deadlines" \
--tag-1 client_acme_corp \
--category deadline \
--top-k 10
# List all memories for a specific matter
casedev memory:v1 list \
--tag-1 client_acme_corp \
--tag-2 matter_patent_2026_001
// Store a memory scoped to client + matter
await client.memory.add({
messages: [
{ role: 'user', content: 'The patent filing deadline is March 15th, 2026.' }
],
tag_1: 'client_acme_corp', // Client ID
tag_2: 'matter_patent_2026_001', // Matter ID
tag_3: 'atty_jane_smith', // Attorney ID
category: 'deadline'
});
// Search only this client's deadlines
const deadlines = await client.memory.search({
query: 'upcoming deadlines',
tag_1: 'client_acme_corp',
category: 'deadline',
top_k: 10
});
// List all memories for a specific matter
const matterMemories = await client.memory.list({
tag_1: 'client_acme_corp',
tag_2: 'matter_patent_2026_001'
});
# Store a memory scoped to client + matter
result = client.memory.v1.create(
messages=[
{'role': 'user', 'content': 'The patent filing deadline is March 15th, 2026.'}
],
tag_1='client_acme_corp', # Client ID
tag_2='matter_patent_2026_001', # Matter ID
tag_3='atty_jane_smith', # Attorney ID
category='deadline'
)
# Search only this client's deadlines
deadlines = client.memory.v1.search(
query='upcoming deadlines',
tag_1='client_acme_corp',
category='deadline',
top_k=10
)
# List all memories for a specific matter
matter_memories = client.memory.v1.list(
tag_1='client_acme_corp',
tag_2='matter_patent_2026_001'
)
// Store a memory scoped to client + matter
result, _ := client.Memory.V1.New(ctx, casedev.MemoryV1NewParams{
Messages: casedev.F([]casedev.MemoryV1NewParamsMessage{{
Role: casedev.F(casedev.MemoryV1NewParamsMessagesRoleUser),
Content: casedev.F("The patent filing deadline is March 15th, 2026."),
}}),
Tag1: casedev.F("client_acme_corp"), // Client ID
Tag2: casedev.F("matter_patent_2026_001"), // Matter ID
Tag3: casedev.F("atty_jane_smith"), // Attorney ID
Category: casedev.F("deadline"),
})
// Search only this client's deadlines
deadlines, _ := client.Memory.V1.Search(ctx, casedev.MemoryV1SearchParams{
Query: casedev.F("upcoming deadlines"),
Tag1: casedev.F("client_acme_corp"),
Category: casedev.F("deadline"),
TopK: casedev.F(int64(10)),
})
// List all memories for a specific matter
matterMemories, _ := client.Memory.V1.List(ctx, casedev.MemoryV1ListParams{
Tag1: casedev.F("client_acme_corp"),
Tag2: casedev.F("matter_patent_2026_001"),
})
Categories
Thecategory field is free-form text - you define your own categories. Here are suggested categories for different domains:
Legal categories
| Category | Description | Example |
|---|---|---|
fact | General facts about client/matter | ”Client founded company in 2019” |
preference | Communication or work preferences | ”Client prefers email updates” |
deadline | Filing deadlines, court dates | ”Motion due March 15th” |
decision | Decisions made by client/court | ”Client approved settlement terms” |
contact | Contact information | ”Client’s assistant is Jane (jane@acme.com)“ |
relationship | Relationships between parties | ”Defendant is client’s former business partner” |
court_ruling | Court rulings and precedents | ”Judge denied motion to dismiss” |
procedural | Procedural information | ”Case assigned to Judge Thompson” |
Healthcare categories
| Category | Description |
|---|---|
allergy | Patient allergies |
medication | Current medications |
preference | Treatment preferences |
history | Medical history |
family_history | Family medical history |
social | Social/lifestyle factors |
Filtering by category
# Get only deadline memories for a client
curl "https://api.case.dev/memory/v1?tag_1=client_123&category=deadline" \
-H "Authorization: Bearer $CASEDEV_API_KEY"
# Search preferences only
curl -X POST https://api.case.dev/memory/v1/search \
-H "Authorization: Bearer $CASEDEV_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"query": "communication method",
"tag_1": "client_123",
"category": "preference"
}'
# Get only deadline memories for a client
casedev memory:v1 list --tag-1 client_123 --category deadline
# Search preferences only
casedev memory:v1 search --query "communication method" --tag-1 client_123 --category preference
// Get only deadline memories for a client
const deadlines = await client.memory.list({
tag_1: 'client_123',
category: 'deadline'
});
// Search preferences only
const prefs = await client.memory.search({
query: 'communication method',
tag_1: 'client_123',
category: 'preference'
});
# Get only deadline memories for a client
deadlines = client.memory.v1.list(tag_1='client_123', category='deadline')
# Search preferences only
prefs = client.memory.v1.search(
query='communication method',
tag_1='client_123',
category='preference'
)
// Get only deadline memories for a client
deadlines, _ := client.Memory.V1.List(ctx, casedev.MemoryV1ListParams{
Tag1: casedev.F("client_123"),
Category: casedev.F("deadline"),
})
// Search preferences only
prefs, _ := client.Memory.V1.Search(ctx, casedev.MemoryV1SearchParams{
Query: casedev.F("communication method"),
Tag1: casedev.F("client_123"),
Category: casedev.F("preference"),
})
Listing memories
# List all memories for a client
curl "https://api.case.dev/memory/v1?tag_1=client_123&limit=50" \
-H "Authorization: Bearer $CASEDEV_API_KEY"
# List with multiple filters
curl "https://api.case.dev/memory/v1?tag_1=client_123&tag_2=matter_456&category=deadline&limit=20&offset=0" \
-H "Authorization: Bearer $CASEDEV_API_KEY"
# List all memories for a client
casedev memory:v1 list --tag-1 client_123 --limit 50
# List with multiple filters
casedev memory:v1 list \
--tag-1 client_123 \
--tag-2 matter_456 \
--category deadline \
--limit 20
// List all memories for a client
const all = await client.memory.list({
tag_1: 'client_123',
limit: 50
});
// List with multiple filters
const filtered = await client.memory.list({
tag_1: 'client_123',
tag_2: 'matter_456',
category: 'deadline',
limit: 20,
offset: 0
});
console.log(filtered.results); // Array of memories
console.log(filtered.count); // Total count matching filters
# List all memories for a client
all_memories = client.memory.v1.list(tag_1='client_123', limit=50)
# List with multiple filters
filtered = client.memory.v1.list(
tag_1='client_123',
tag_2='matter_456',
category='deadline',
limit=20,
offset=0
)
print(filtered.results) # Array of memories
print(filtered.count) # Total count matching filters
// List all memories for a client
all, _ := client.Memory.V1.List(ctx, casedev.MemoryV1ListParams{
Tag1: casedev.F("client_123"),
Limit: casedev.F(int64(50)),
})
// List with multiple filters
filtered, _ := client.Memory.V1.List(ctx, casedev.MemoryV1ListParams{
Tag1: casedev.F("client_123"),
Tag2: casedev.F("matter_456"),
Category: casedev.F("deadline"),
Limit: casedev.F(int64(20)),
Offset: casedev.F(int64(0)),
})
fmt.Println(filtered.Results) // Array of memories
fmt.Println(filtered.Count) // Total count matching filters
Deleting memories
Delete a single memory
curl -X DELETE https://api.case.dev/memory/v1/mem_abc123 \
-H "Authorization: Bearer $CASEDEV_API_KEY"
casedev memory:v1 delete --id mem_abc123
await client.memory.delete('mem_abc123');
client.memory.v1.delete('mem_abc123')
client.Memory.V1.Delete(ctx, "mem_abc123")
Bulk delete by tags
curl -X POST https://api.case.dev/memory/v1/delete-many \
-H "Authorization: Bearer $CASEDEV_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'
# Delete all memories for a client
casedev memory:v1 delete-all --tag-1 client_123
# Delete memories for a specific matter
casedev memory:v1 delete-all --tag-1 client_123 --tag-2 matter_456
// Delete all memories for a client
await client.memory.deleteMany({
tag_1: 'client_123'
});
// Delete memories for a specific matter
await client.memory.deleteMany({
tag_1: 'client_123',
tag_2: 'matter_456'
});
# Delete all memories for a client
client.memory.v1.delete_all(tag_1='client_123')
# Delete memories for a specific matter
client.memory.v1.delete_all(tag_1='client_123', tag_2='matter_456')
// Delete all memories for a client
client.Memory.V1.DeleteAll(ctx, casedev.MemoryV1DeleteAllParams{
Tag1: casedev.F("client_123"),
})
// Delete memories for a specific matter
client.Memory.V1.DeleteAll(ctx, casedev.MemoryV1DeleteAllParams{
Tag1: casedev.F("client_123"),
Tag2: casedev.F("matter_456"),
})
Bulk delete removes all matching memories. Use with caution.
Memory events
When you add memories, the API returns what happened to each extracted fact:| Event | Description |
|---|---|
ADD | New memory created |
UPDATE | Existing memory was updated/merged |
DELETE | Contradicting info caused memory deletion |
NONE | Duplicate - memory already exists |
curl -X POST https://api.case.dev/memory/v1/add \
-H "Authorization: Bearer $CASEDEV_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'
casedev memory:v1 create \
--message '{role: user, content: "Actually, the client now prefers phone calls instead of email."}' \
--tag-1 client_123
# Result might show event: UPDATE
# (merged with existing email preference)
const result = await client.memory.add({
messages: [
{ role: 'user', content: 'Actually, the client now prefers phone calls instead of email.' }
],
tag_1: 'client_123'
});
// Result might show:
// { id: 'mem_xyz', memory: 'Client prefers phone calls', event: 'UPDATE' }
// (merged with existing email preference)
result = client.memory.v1.create(
messages=[
{'role': 'user', 'content': 'Actually, the client now prefers phone calls instead of email.'}
],
tag_1='client_123'
)
# Result might show:
# {'id': 'mem_xyz', 'memory': 'Client prefers phone calls', 'event': 'UPDATE'}
# (merged with existing email preference)
result, _ := client.Memory.V1.New(ctx, casedev.MemoryV1NewParams{
Messages: casedev.F([]casedev.MemoryV1NewParamsMessage{{
Role: casedev.F(casedev.MemoryV1NewParamsMessagesRoleUser),
Content: casedev.F("Actually, the client now prefers phone calls instead of email."),
}}),
Tag1: casedev.F("client_123"),
})
// Result might show:
// {ID: "mem_xyz", Memory: "Client prefers phone calls", Event: "UPDATE"}
// (merged with existing email preference)
Direct storage (skip extraction)
To store a fact directly without LLM extraction, setinfer: false:
curl -X POST https://api.case.dev/memory/v1/add \
-H "Authorization: Bearer $CASEDEV_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'
casedev memory:v1 create \
--message '{role: user, content: "Client SSN: 123-45-6789"}' \
--tag-1 client_123 \
--category contact \
--infer false
await client.memory.add({
messages: [
{ role: 'user', content: 'Client SSN: 123-45-6789' }
],
tag_1: 'client_123',
category: 'contact',
infer: false // Store as-is, no extraction
});
result = client.memory.v1.create(
messages=[{'role': 'user', 'content': 'Client SSN: 123-45-6789'}],
tag_1='client_123',
category='contact',
infer=False # Store as-is, no extraction
)
result, _ := client.Memory.V1.New(ctx, casedev.MemoryV1NewParams{
Messages: casedev.F([]casedev.MemoryV1NewParamsMessage{{
Role: casedev.F(casedev.MemoryV1NewParamsMessagesRoleUser),
Content: casedev.F("Client SSN: 123-45-6789"),
}}),
Tag1: casedev.F("client_123"),
Category: casedev.F("contact"),
Infer: casedev.F(false), // Store as-is, no extraction
})
Custom extraction prompts
For domain-specific extraction, provide a custom prompt:curl -X POST https://api.case.dev/memory/v1/add \
-H "Authorization: Bearer $CASEDEV_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'
casedev memory:v1 create \
--message '{role: user, content: "Patient reports headaches and nausea."}' \
--tag-1 patient_123 \
--extraction-prompt "You are a medical memory extraction system. Extract discrete facts about the patient."
await client.memory.add({
messages: conversation,
tag_1: 'patient_123',
extraction_prompt: `You are a medical memory extraction system.
Extract discrete facts about the patient, focusing on:
- Symptoms and conditions
- Medications and dosages
- Allergies and reactions
- Treatment preferences
Output ONLY a valid JSON array with this structure:
[{"content": "fact", "category": "allergy|medication|symptom|preference", "confidence": 0.9}]`
});
result = client.memory.v1.create(
messages=conversation,
tag_1='patient_123',
extraction_prompt="""You are a medical memory extraction system.
Extract discrete facts about the patient, focusing on:
- Symptoms and conditions
- Medications and dosages
- Allergies and reactions
- Treatment preferences
Output ONLY a valid JSON array with this structure:
[{"content": "fact", "category": "allergy|medication|symptom|preference", "confidence": 0.9}]"""
)
result, _ := client.Memory.V1.New(ctx, casedev.MemoryV1NewParams{
Messages: casedev.F(conversation),
Tag1: casedev.F("patient_123"),
ExtractionPrompt: casedev.F(`You are a medical memory extraction system.
Extract discrete facts about the patient, focusing on:
- Symptoms and conditions
- Medications and dosages
- Allergies and reactions
- Treatment preferences
Output ONLY a valid JSON array with this structure:
[{"content": "fact", "category": "allergy|medication|symptom|preference", "confidence": 0.9}]`),
})
Pricing
| Operation | Cost |
|---|---|
| Add memory | $0.001 per operation |
| Search | $0.001 per operation |
| List/Get/Delete | Free |
LLM usage for fact extraction and embeddings is billed separately through the LLM service at standard rates.
Related services
LLMs
Use memories as context for chat completions
Vault
Store documents, use Memory for extracted facts

