Agent Cerebro
Persistent two-tier memory for AI agents. Battle-tested across 134 sessions with 10 agent roles.
Short-term (markdown files, always loaded) + Long-term (SQLite + OpenAI embeddings, searched on-demand).
Cerebro Hosted (managed memory) — same two-tier memory, but the long-term store is hosted and shared across machines and agents. No SQLite file to sync, no embeddings key to manage. Join the waitlist →
Install
pip install agent-cerebro
Zero required dependencies. SQLite is Python stdlib.
Optional semantic search:
pip install agent-cerebro[embeddings]
export OPENAI_API_KEY="sk-..."
Quick Start
CLI
# Initialize
cerebro init
# Store a memory (auto-dedup via cosine similarity >0.92)
cerebro store coder gotchas "kamal app exec spawns new container, use docker exec"
cerebro store social exhausted_stories "blue-green deploy order loss" --tags deploy,sqlite
# Search (semantic + keyword fallback)
cerebro search coder gotchas "kamal file not found"
cerebro search coder gotchas "deploy issue" --tag critical
cerebro search coder gotchas "deploy issue" --show-id
# Correct stale memories explicitly; history is preserved
cerebro invalidate 42 --reason "Kamal behavior changed in v2"
cerebro supersede 57 "Use docker exec for live-container queries" --reason "Old command spawned a new container"
cerebro supersede 61 "Current deployment rule" --tags deploy,current
# List categories
cerebro list coder
# Timeline — chronological view of all memories
cerebro timeline coder
cerebro timeline coder --last 7d
cerebro timeline coder --last 2w --category gotchas
cerebro timeline coder --show-id
cerebro timeline coder --include-invalidated --show-id
# Export — dump all memories for a role
cerebro export coder --format md > coder_memories.md
cerebro export coder --format json > coder_memories.json
cerebro export coder --format json --category gotchas
cerebro export coder --format json --include-invalidated > coder_audit.json
# Lossless backup — all roles, embeddings, and lifecycle history, offline
cerebro backup memory-backup.sqlite3
cerebro backup memory-backup.sqlite3 --db /path/to/memory.sqlite3
# Open the snapshot directly, including on another machine
cerebro search coder gotchas "query" --db memory-backup.sqlite3
# Stats — storage metrics and category breakdown
cerebro stats
cerebro stats coder
# Garbage collection — find and remove near-duplicates
cerebro gc coder --dry-run
cerebro gc coder --apply
cerebro gc coder --threshold 0.85 --category gotchas
# Check health
cerebro check --all
Python API
For a lossless long-term database snapshot:
from agentrecall import backup_database
backup_database("memory-backup.sqlite3", db_path="/path/to/memory.sqlite3")
backup captures committed data through SQLite's online backup API, including
uncheckpointed WAL writes, every role, stable IDs, embeddings, tags, and invalidated
or superseded history. It requires no API key and leaves the source schema unchanged.
The destination must be a new file in an existing directory; existing files and
symlinks are never overwritten. The snapshot is checked before publication and
created with owner-only permissions (0600 on POSIX). A missing or invalid source
fails instead of creating an empty database. CLI failures exit 2.
Use --db memory-backup.sqlite3 to read or continue using the snapshot, or copy it
to a new memory home's memory.sqlite3 while no processes use that destination.
Keep the original until you have verified the copy. This backs up long-term
SQLite memory only; copy short-term markdown files separately. Markdown/JSON
export remains a readable view and does not contain embeddings. The backup is
unencrypted, so protect it like the source database.
from agentrecall import (
MemoryExport,
MemoryGC,
MemoryLifecycle,
MemorySearch,
MemoryStats,
MemoryStore,
MemoryTimeline,
)
# Store
store = MemoryStore()
entry = store.store(
"coder", "gotchas", "kamal spawns new container", tags=["kamal", "docker"]
)
another_entry = store.store(
"coder", "gotchas", "use kamal app exec for live queries", tags=["kamal"]
)
# Search (with optional tag filter)
search = MemorySearch()
results = search.search("coder", "gotchas", "kamal file not found")
results = search.search("coder", "gotchas", "deploy issue", tag="critical")
# search() remains list[str]; search_records() adds stable IDs and metadata
records = search.search_records("coder", "gotchas", "deploy issue")
# Explicit lifecycle changes preserve history
lifecycle = MemoryLifecycle()
lifecycle.invalidate(entry["id"], "Kamal behavior changed in v2")
transition = lifecycle.supersede(
another_entry["id"],
"Use docker exec for live-container queries",
reason="Old command spawned a new container",
)
# → {old_id, new_id, replacement}
# Timeline
timeline = MemoryTimeline()
entries = timeline.timeline("coder", last="7d")
audit_entries = timeline.timeline("coder", include_invalidated=True)
# Export
export = MemoryExport()
markdown = export.export("coder", fmt="md")
json_str = export.export("coder", fmt="json", category="gotchas")
audit_json = export.export("coder", fmt="json", include_invalidated=True)
# Stats
stats = MemoryStats()
metrics = stats.stats(role="coder")
# → {total_entries, total_with_embeddings, embedding_coverage_pct, db_size_bytes, ...}
# Garbage collection
gc = MemoryGC()
result = gc.gc("coder", dry_run=True)
# → {found: 3, removed: 0, duplicates: [...]}
result = gc.gc("coder", dry_run=False) # actually delete
How It Works
Two-Tier Design
Short-term (memory/<role>.md) |
Long-term (SQLite + embeddings) |
|---|---|
| Active learnings, mistakes, feedback | Growing lists (exhausted topics, defect patterns) |
| Max 80 lines, pruned regularly | Auditable history; invalidated entries hidden by default |
| Read in full at session start | Searched on-demand per query |
Semantic Dedup
Every store call embeds the text via OpenAI text-embedding-3-small and checks cosine similarity against active entries in the same role/category. Similarity > 0.92 blocks the store (raises DuplicateError); it does not silently replace either entry.
Without an API key, falls back to exact text matching.
Memory Lifecycle
Search with --show-id to address a stable entry. invalidate soft-invalidates a
known-stale belief. supersede inserts a corrected entry in the same role/category
and links the invalidated original to it in one transaction. Omitting --tags on
supersede preserves the original tags; supplying it replaces them.
Normal search, timeline, export, dedup, and active counts ignore invalidated entries.
Use timeline --include-invalidated or export --include-invalidated for an audit
view with timestamps, reasons, and superseded_by linkage. Cerebro never interprets
a duplicate write as a truth change: two similar memories can both be valid, so
supersession is always explicit.
Opening an existing 0.4.x SQLite database automatically adds the lifecycle columns in place. Existing rows and IDs are preserved; no manual migration command is needed.
Search
- Embed the query
- Compute cosine similarity against all active entries with embeddings
- Return entries above threshold (0.75), sorted by similarity
- If no embedding matches: keyword fallback (>=50% keyword match)
- No API key (or embeddings unavailable): keyword-only search
- Optional
--tagfilter narrows results to entries with a specific tag - Optional
--limit Ncaps output to the top-N results (keeps agent context tight)
Garbage Collection
cerebro gc finds near-duplicate entries within each role/category pair:
- With embeddings: cosine similarity >= threshold (default 0.92)
- Without embeddings: exact text match (case-insensitive)
- Older entry (lower ID) is kept; newer duplicate is removed
--dry-run(default) reports without deleting--applyactually removes duplicates
Graceful Degradation
Works fully offline without an OpenAI API key:
- Store: exact text dedup (case-insensitive)
- Search: keyword matching (>=50% of query words must appear)
- GC: exact text match dedup only
Network Resilience
Embedding calls are wrapped in a retry loop with exponential backoff + jitter.
Transient failures (timeouts, dropped connections, HTTP 429/5xx) are retried;
HTTP 429 honors the Retry-After header. After exhausting retries — or on a
non-retryable error (e.g. 401) — store/search print a warning and fall back
to keyword/exact-match instead of crashing mid-session. Auth/4xx errors are not
retried (no point burning attempts on a bad key).
Tune via CEREBRO_EMBED_MAX_RETRIES (default 3) and CEREBRO_EMBED_TIMEOUT
(seconds, default 30).
Agent Skills
Copy skill/agent-recall/ into your project's skills directory for use with Claude Code, Codex, Cursor, Copilot, Cline, or Goose.
cp -r skill/agent-recall/ .claude/skills/agent-recall/
Configuration
Environment variables:
| Variable | Default | Description |
|---|---|---|
AGENT_CEREBRO_HOME |
~/.agent-cerebro |
Memory storage directory |
OPENAI_API_KEY |
(none) | OpenAI API key for embeddings |
UT_OPENAI_API_KEY |
(none) | Preferred over OPENAI_API_KEY |
CEREBRO_EMBED_MAX_RETRIES |
3 |
Retries on transient embedding-API failures |
CEREBRO_EMBED_TIMEOUT |
30 |
Per-request embedding timeout (seconds) |
CLI Reference
cerebro store <role> <category> "text" [--tags t1,t2] [--db path]
cerebro search <role> <category> "query" [--tag tagname] [--limit N] [--show-id] [--db path]
cerebro invalidate <entry_id> --reason "why it is stale" [--db path]
cerebro supersede <entry_id> "replacement" [--tags t1,t2] [--reason "why"] [--db path]
cerebro list <role> [--db path]
cerebro timeline <role> [--last 7d] [--category cat] [--limit N] [--show-id] [--include-invalidated] [--db path]
cerebro export <role> [--format md|json] [--category cat] [--include-invalidated] [--db path]
cerebro backup <new-file> [--db source-path]
cerebro stats [role] [--db path]
cerebro gc <role> [--dry-run] [--apply] [--threshold 0.92] [--category cat] [--db path]
cerebro check [--fix] [--long-term] [--all] [--dir path] [--db path]
cerebro init [--dir path]
cerebro migrate [--dry-run] [--rebuild] [--dir path] [--db path]
agentrecall and agentmemory also work as CLI aliases.
Exit codes: 0 = success/found, 1 = not-found/validation-fail, 2 = input error.
Migration from JSONL
If you have existing JSONL memory files:
cerebro migrate --dir /path/to/memory/
cerebro migrate --rebuild # Re-embed entries missing embeddings
Related Tools
Part of the Ultrathink Agent Suite:
- Agent Architect Kit — Multi-agent starter kit that uses Cerebro for cross-session memory
- Agent Orchestra — Task queue + orchestration CLI for spawning and managing agents
- AgentBrush — Image editing toolkit for AI agents
Built by an AI-run dev shop. Read how →
License
MIT
Metadata
Release files for agent-cerebro 0.6.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| agent_cerebro-0.6.0.tar.gz | 48.4 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| agent_cerebro-0.6.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 84.8 kB
Release files / agent_cerebro-0.6.0.tar.gz
| Download URL | agent_cerebro-0.6.0.tar.gz |
|---|---|
| Size | 48.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
25c165f4ea805093ba6388592820c6ead75984f1680a4ea54c2209fa535fddde
|
|
BLAKE2b-256 checksum How to use checksums |
6fa6d4b4b18a6a53647072008e3521b09a357f3fdd9f108eeba7436aff21bac1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.12
|
Release files / agent_cerebro-0.6.0-py3-none-any.whl
| Download URL | agent_cerebro-0.6.0-py3-none-any.whl |
|---|---|
| Size | 36.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
5fccb44226de8768fe71aeef7fe1e4e6b13d0ad28f50baec269c95de8b12672d
|
|
BLAKE2b-256 checksum How to use checksums |
614d898730dc3cd448965f923adab6f2d91cde5f39e4c89442982c6ee130558c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.12
|
Security for agent-cerebro 0.6.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.