Caretaker — Universal Agent Memory Layer
Local-first · Agent-agnostic · Cloud-backed · CLI-managed
Caretaker is a persistent memory system for AI agents. Every conversation you have — with Claude, ChatGPT, Gemini, or any MCP-compatible agent — gets captured, compressed, and stored locally. The next time any agent talks to you, it already knows who you are, what you are building, and what you care about.
One memory. Every agent. Forever.
How It Works
You talk to any AI agent
↓
Agent calls caretaker_get_context() ← memory injected before response
Agent responds with full continuity
↓
Agent calls caretaker_save_message() ← message captured after response
↓
Memory stored locally (SQLite + ChromaDB)
↓
Encrypted backup to Supabase (nightly)
No session boundaries. No forgetting. No re-introducing yourself.
Phases Completed
| Phase | Title | Status |
|---|---|---|
| 1 | Core Memory MVP | ✅ Complete |
| 2 | Intelligence Layer | ✅ Complete |
| 3 | Multi-Agent + CLI + Cloud | ✅ Complete |
| 4 | Production Polish | 🔜 Next |
Requirements
- Windows, macOS or Linux
- Python 3.12+
- uv package manager
- An MCP client: Claude Desktop, Claude Code, Cursor, VS Code, or any other MCP-compatible agent
- Optional: Anthropic API key (only if you choose Haiku compression)
- Optional: Supabase account (only for encrypted cloud backup)
Your data stays on your device
Caretaker stores everything locally in one folder:
| How you run it | Config file | Data folder |
|---|---|---|
Installed (uv tool install, uvx, pip) |
~/.caretaker/config.json |
~/.caretaker/ |
| From a source checkout (developing Caretaker) | <project>/config.json |
<project>/public/ |
<data folder>/
data/caretaker.db ← SQLite memory store
data/chromadb/ ← vector index
logs/ ← caretaker.log (MCP server), maintenance.log
exports/ ← default location for `caretaker export`
cache/ ← downloaded models (Hugging Face, sentence-transformers, torch)
Nothing leaves your machine unless you turn it on:
- Compression defaults to
"local"(spaCy + TextRank, on-device). Settingcompression_modelto"claude-haiku-4-5-20251001"sends memory text to Anthropic's API for better summaries. - Cloud backup only runs if you configure Supabase, and everything is encrypted on your device first.
To store data somewhere else, set data_dir in config.json (absolute, or relative to the config file's folder), or set the CARETAKER_DATA_DIR environment variable, which takes priority. CARETAKER_CONFIG points Caretaker at a different config file. Changing the location doesn't move existing data: copy the old folder over if you want to keep it.
Installation
Option A — Install the tool (recommended)
From PyPI (once published) or straight from a local checkout:
uv tool install "caretaker-mcp[semantic]" # from PyPI
uv tool install "C:\path\to\caretaker[semantic]" # from a local checkout
This puts two commands on your PATH: caretaker (CLI and dashboard) and caretaker-mcp (the MCP server). You can also run the server without installing: uvx caretaker-mcp.
Pick the features you want. The core install is small and covers the MCP server, CLI, dashboard and keyword search. Heavier features are extras:
| Extra | Adds | Notes |
|---|---|---|
semantic |
Vector search (ChromaDB + sentence-transformers) | Recommended for better recall. Large: pulls in PyTorch |
nlp |
spaCy for better on-device summaries | Then run python -m spacy download en_core_web_sm |
anthropic |
Summaries by Claude Haiku | Sends memory text to Anthropic's API |
cloud |
Encrypted backup to Supabase | |
all |
Everything above |
Combine them like caretaker-mcp[semantic,nlp]. Without semantic, Caretaker uses keyword search.
Option B — Develop from a source checkout
cd caretaker
uv sync # installs every extra plus the test tools
Run the server with uv run caretaker-mcp (or uv run caretaker serve). In a checkout, config lives in <project>/config.json and data in <project>/public/. Copy config.example.json to config.json to start.
Optional — spaCy model for better local compression
uv run python -m spacy download en_core_web_sm
Without it, local compression still works with a simpler fallback.
Configuration
Config is optional — Caretaker runs with sensible defaults. Set values with the CLI (creates the config file if needed):
caretaker config set user_handle "Your Name"
caretaker config show
Or set them in your MCP client's env block, which overrides the file:
| Environment variable | Setting |
|---|---|
CARETAKER_USER_HANDLE |
user_handle |
CARETAKER_COMPRESSION_MODEL |
compression_model (local or a Claude model id) |
CARETAKER_ANTHROPIC_API_KEY (or ANTHROPIC_API_KEY) |
anthropic_api_key |
CARETAKER_SUPABASE_URL, CARETAKER_SUPABASE_KEY, CARETAKER_ENCRYPT_KEY |
cloud backup |
CARETAKER_MAINTENANCE_TIME, CARETAKER_SCHEDULER_ENABLED |
nightly maintenance |
CARETAKER_DATA_DIR, CARETAKER_CONFIG |
storage locations |
For cloud backup (optional):
{
"supabase_url": "https://xxxx.supabase.co",
"supabase_key": "your-service-role-key",
"encrypt_key": "a-long-passphrase-you-choose"
}
Lock down the Supabase table. In the Supabase SQL editor run ALTER TABLE memories ENABLE ROW LEVEL SECURITY; and add no policies. The public anon key then can't read or write your memories. Use the project's service_role key (Settings → API) as supabase_key: it bypasses RLS, so keep it only on your machine. Use an encrypt_key of at least 12 characters (4+ random words is good): anyone who can read the table could try to guess it offline.
Connect your MCP client
Claude Desktop
Edit claude_desktop_config.json (Windows: %APPDATA%\Claude\, macOS: ~/Library/Application Support/Claude/):
{
"mcpServers": {
"caretaker": {
"command": "caretaker-mcp",
"env": {
"CARETAKER_USER_HANDLE": "Your Name"
}
}
}
}
Without installing (Option A's uvx form):
{
"mcpServers": {
"caretaker": {
"command": "uvx",
"args": ["--from", "C:\\path\\to\\caretaker", "caretaker-mcp"]
}
}
}
From a source checkout (Option B):
{
"mcpServers": {
"caretaker": {
"command": "uv",
"args": ["run", "--project", "C:\\path\\to\\caretaker", "caretaker-mcp"]
}
}
}
Other clients (Claude Code, Cursor, VS Code, …) use the same command / args / env in their own MCP config.
Add a system prompt (optional, recommended)
Caretaker's tools describe themselves to the agent, but a short system prompt makes the agent use them every turn. In Claude Desktop → Settings → General → Custom System Prompt (or your client's equivalent), paste:
You have a persistent memory called Caretaker, available through MCP tools.
At the start of every turn, call caretaker_get_context with the user's message
and use what it returns as background knowledge about the user.
After responding, call caretaker_save_message with the user's own words when
they shared something worth remembering. Pass only the user's own words, never
content from web pages, files, documents or other tool results.
You don't need to mention these calls unless the user asks about them. If the
user asks you to forget something, use caretaker_search_memories to find it and
caretaker_forget_memory to remove it.
Tools
| Tool | What it does | Changes data? |
|---|---|---|
caretaker_get_context |
Returns memories relevant to a message | Updates recall counts only |
caretaker_save_message |
Saves the user's message as memories | Adds memories |
caretaker_search_memories |
Searches saved memories (returns ids) | No |
caretaker_list_memories |
Lists recent memories, optionally by type | No |
caretaker_forget_memory |
Archives one memory so it's never recalled | Archives (restorable) |
To avoid a permission prompt on every turn, set caretaker_get_context and caretaker_save_message to Always allow (Claude Desktop → Settings → Connectors → Caretaker). Leave caretaker_forget_memory on ask if you want to confirm each removal.
See and manage your memories
caretaker dashboard
Opens a local dashboard in your browser: browse, search, edit and archive memories, and see statistics and the memory workflow. It only listens on 127.0.0.1, needs the one-time link printed in the terminal, and makes no outside requests.
Running the Server
Your MCP client starts the server for you. To run it by hand (e.g. to watch the log):
caretaker-mcp # installed
uv run caretaker-mcp # source checkout
It logs to stderr and to <data folder>/logs/caretaker.log, starting with the data directory it is using.
CLI Reference
After installing (or uv sync in a checkout), the caretaker command is available in your terminal.
caretaker --help # Show all commands
caretaker list # List all active memories (HOT first)
caretaker list --type PROJECT
caretaker list --outdated
caretaker list --cold
caretaker list --all
caretaker list --agent chatgpt
caretaker view <id> # Show full memory detail
caretaker search "python project" # Semantic search
caretaker edit <id> # Open memory in editor
caretaker delete <id> # Soft-archive a memory
caretaker restore <id> # Restore archived memory
caretaker stats # Memory health dashboard
caretaker export # Export all memories to JSON
caretaker export --file my_backup.json
caretaker import backup.json
caretaker import backup.json --overwrite # replace memories that already exist
caretaker sync # Push to Supabase
caretaker sync --pull # Restore from Supabase
caretaker sync --full # Push all (not just last 24h)
caretaker config # Show all config values
caretaker config get maintenance_time
caretaker config set user_handle Dhruvil
caretaker maintenance # Run nightly maintenance now
caretaker serve # Run the MCP server (same as caretaker-mcp)
caretaker dashboard # Open the local memory dashboard
caretaker score <id> 0.8 # Manually set importance score
Multi-Agent Support
Caretaker works with any MCP-compatible agent. Pass agent_id when calling caretaker_get_context:
| Agent | agent_id value | Format Style |
|---|---|---|
| Claude Desktop | claude |
Directive system prompt |
| ChatGPT | chatgpt or gpt-4o |
Context block header |
| Gemini | gemini or vertex |
XML <context> tags |
| Cursor IDE | cursor |
Code comment style |
| GitHub Copilot | copilot |
Block comment style |
| Any other | any string | Neutral plain text |
The context presented to each agent never reveals which other agent had previous conversations. Each agent receives neutral user history and responds with natural continuity.
Memory System
Memory Types
| Type | Fact Type | Example | Conflict Behaviour |
|---|---|---|---|
| PROJECT | REPLACEABLE | "Building FastAPI project" | New replaces old |
| PREFERENCE | REPLACEABLE | "Prefer Python over JS" | New replaces old |
| PROBLEM | ADDITIVE | "Getting 404 on /api/users" | Both kept |
| DECISION | ADDITIVE | "Decided to use Supabase" | Both kept |
| LEARNING | ADDITIVE | "Learning transformer models" | Both kept |
| PERSONAL | REPLACEABLE | "My name is Dhruvil" | New replaces old |
| EMOTION | ADDITIVE | "Excited about the progress" | Both kept |
| CORRECTION | REPLACEABLE | "Actually meant PostgreSQL" | New replaces old |
Temperature Tiers
| Temperature | Score Condition | Retrieval |
|---|---|---|
| PRIORITY_HOT | importance > 0.7 | Always fetched first |
| HOT | score > 0.5 | Fetched in standard retrieval |
| WARM | 0.2 ≤ score ≤ 0.5 | Fetched only if semantically relevant |
| COLD | score < 0.2 | Never fetched — skipped in search |
| ARCHIVED | Manual or score < 0.2 | Never fetched — Supabase cold store |
Token Budget (Smart Auto)
| Level | Signal | Budget | Memory Form |
|---|---|---|---|
| L0 | "hi", "hello", "hey" | 80 tokens | Core identity only |
| L1 | "quick", "list", "simple" | 200 tokens | Core only |
| L2 | "explain", "what is", "help" | 350 tokens | Core + recent SHORT |
| L3 | "code", "debug", "implement" | 500 tokens | Core + relevant SHORT |
| L4 | "architecture", "design", "full flow" | 650 tokens | Core + relevant FULL |
| L5 | "remember everything about" | 800 tokens | All relevant FULL |
Nightly Maintenance
Runs automatically every night at maintenance_time (default 02:00 UTC).
Trigger manually anytime:
caretaker maintenance
Pipeline runs 8 tasks in order:
- Batch Decay — HOT → WARM after 7 days idle, WARM → COLD after 14 days
- ChromaDB Sync — Remove OUTDATED and COLD entries from vector index
- Stale Cleanup — Archive memories with score < 0.2
- Deduplication — Merge near-identical memories (>70% keyword overlap)
- Importance Boost — +0.02 per retrieval above threshold (max +0.15)
- Cloud Sync — Encrypt + push last 24h updates to Supabase
- ChromaDB Reindex — Re-add any ACTIVE memories missing from vector index
- Stats Report — Write health summary to
<data_dir>/logs/maintenance.log
Storage Architecture
LOCAL (primary) — all under data_dir (default: public/):
data/caretaker.db ← SQLite: all memory records, source of truth
data/chromadb/ ← ChromaDB: SHORT embeddings for semantic search (HOT + WARM only)
logs/ ← server log + maintenance reports
exports/ ← JSON exports
cache/ ← model downloads
config.json ← user settings (project root)
CLOUD (backup):
Supabase PostgreSQL ← encrypted full memory dump, nightly sync
All data that leaves the local machine is encrypted with AES-256-GCM before upload. Supabase never stores plaintext.
Project Structure
The package lives under src/caretaker/ (PEP 517 src/ layout, built with hatchling). python -m caretaker and the caretaker CLI both resolve to src/caretaker/cli/main.py.
caretaker/
├── src/
│ └── caretaker/
│ ├── __init__.py
│ ├── paths.py # Where all data lives (data_dir → db, chromadb, logs, exports, cache)
│ ├── __main__.py # Enables `python -m caretaker`
│ ├── mcp_server/
│ │ ├── server.py # FastMCP entry point (imports stdout_guard first)
│ │ ├── stdout_guard.py # Routes ALL output to stderr (protects JSON-RPC)
│ │ ├── tools.py # caretaker_get_context + caretaker_save_message
│ │ ├── injector.py # Builds whisper context string
│ │ └── agent_adapter.py# Formats whisper per agent type (Phase 3)
│ ├── capture/
│ │ ├── capture_engine.py # Main capture pipeline
│ │ ├── entity_extractor.py # Pulls facts, tools, names from message
│ │ ├── type_classifier.py # Assigns TYPE + SUBTYPE + FACT_TYPE
│ │ └── long_message_handler.py # Splits/compresses messages >400 tokens
│ ├── retrieval/
│ │ ├── retrieval_engine.py # Main retrieval controller
│ │ ├── topic_detector.py # Message complexity L0–L5
│ │ ├── keyword_extractor.py# Key term extraction
│ │ ├── budget_engine.py # Smart token budget calculator
│ │ ├── memory_selector.py # Picks SHORT or FULL per memory
│ │ └── semantic_searcher.py# ChromaDB semantic search
│ ├── memory/
│ │ ├── conflict_checker.py # REPLACEABLE vs ADDITIVE conflict resolution
│ │ ├── temperature_engine.py # HOT/WARM/COLD tier assignment
│ │ └── importance_scorer.py# Initial importance score on capture
│ ├── compression/
│ │ ├── compressor.py # Haiku API — generates SHORT + KEYWORDS
│ │ ├── local_compressor.py # FREE offline spaCy+TextRank compression
│ │ ├── templates.py # Type-specific compression prompts
│ │ └── keyword_generator.py# Extract keywords from SHORT
│ ├── storage/
│ │ ├── local_db.py # SQLite CRUD — source of truth
│ │ ├── vector_db.py # ChromaDB handler
│ │ ├── cloud_sync.py # Supabase upload + restore (Phase 3)
│ │ ├── encrypt.py # AES-256-GCM encryption (Phase 3)
│ │ └── migrations/
│ │ └── v001_initial.sql
│ ├── scheduler/
│ │ ├── scheduler.py # APScheduler nightly job (Phase 3)
│ │ ├── nightly_maintenance.py # 8-task maintenance pipeline (Phase 3)
│ │ ├── maintenance.py # Phase 2 async maintenance runner
│ │ └── compression_queue.py# Async background compression
│ ├── dashboard/ # Local web dashboard (`caretaker dashboard`)
│ │ ├── app.py # Starlette app + JSON API (127.0.0.1 only, token-protected)
│ │ └── static/ # index.html, app.js, app.css (no external requests)
│ └── cli/
│ ├── main.py # Click entry point (`caretaker` command)
│ ├── formatters.py # ANSI terminal formatting
│ └── commands/
│ ├── list_cmd.py
│ ├── view_cmd.py
│ ├── search_cmd.py
│ ├── edit_cmd.py
│ ├── delete_cmd.py
│ ├── restore_cmd.py
│ ├── stats_cmd.py
│ ├── export_cmd.py
│ ├── import_cmd.py
│ ├── sync_cmd.py
│ └── config_cmd.py
├── tests/
│ ├── conftest.py # Shared pytest fixtures + asyncio auto-mode
│ ├── fixtures/fixtures.py # Shared test data
│ ├── phase1/ # Core pipeline (capture, classify, db, mcp, retrieval)
│ ├── phase2/ # Intelligence layer (compression, retrieval, decay)
│ └── phase3/ # Multi-agent + CLI + cloud + maintenance
├── public/ # Default data_dir: db, vector index, logs, exports, cache (gitignored)
├── config.example.json # Template config (copy → config.json)
├── config.json # System configuration (gitignored)
├── pyproject.toml # Dependencies + hatchling build + CLI entry point
├── LICENSE # MIT
├── .github/workflows/ # CI: tests on Windows, macOS, Linux + core-install check
├── uv.lock # Locked dependency versions
└── README.md
Tests run against
src/:pyproject.tomlsetspythonpath = ["src"]andtestpaths = ["tests"], sopytest tests/imports the realcaretakerpackage fromsrc/.
Running Tests
# From the project root (pytest auto-discovers via pyproject config)
pytest tests/ -v
# Specific phase
pytest tests/phase1/ -v
pytest tests/phase2/ -v
pytest tests/phase3/ -v
# Cloud tests require Supabase credentials in config.json
# They auto-skip if not configured — safe to run anywhere
Expected: 200+ tests passing across all three phases. Phase 3 cloud tests skip automatically when Supabase is not configured.
Troubleshooting
MCP not showing in Claude Desktop
Check claude_desktop_config.json paths. All backslashes must be doubled (\\). Restart Claude Desktop after any config change.
ChromaDB index empty after restart
Run caretaker maintenance to trigger a reindex. Or send a message — Phase 2 compression queue will re-embed on next server start.
Compression not working
Check anthropic_api_key in config.json. Haiku API key must be valid. The system falls back to storing raw text if Haiku fails — no crash. For zero-config operation, set "compression_model": "local" in config.json to use the built-in spaCy + TextRank summarizer (no API key, fully offline).
Cloud sync failing
Run caretaker sync and read the error. Most common causes: empty supabase_url, wrong supabase_key, or encrypt_key not set. Cloud sync is optional — system runs fully offline without it.
caretaker command not found
Run uv pip install -e . from the project root. Then open a new terminal.
Tests failing with import errors
Make sure you are running from the project root: cd packages/caretaker before pytest tests/.
Tech Stack
| Technology | Purpose | Phase |
|---|---|---|
| Python 3.12+ | Core language | 1 |
| FastMCP | MCP server framework | 1 |
| Pydantic | Tool schemas / config models | 1 |
| SQLite | Local memory database | 1 |
| spaCy | NLP entity extraction | 1 |
| sentence-transformers | Local embeddings | 2 |
| ChromaDB | Vector search index | 2 |
| Anthropic Haiku | Memory compression | 2 |
| APScheduler | Nightly maintenance | 3 |
| Click | CLI framework | 3 |
| cryptography | AES-256-GCM encryption | 3 |
| Supabase | Cloud backup | 3 |
| pytest | Test framework | All |
| hatchling | Build backend (src/ layout) |
All |
| uv | Package manager | All |
License
MIT — see LICENSE.
Phase 3 complete. Memory cave now has fire, tools, and tribe support. 🦣🔨🔥
Metadata
Release files for caretaker-mcp 0.4.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 | Actions |
|---|---|---|---|---|
| caretaker_mcp-0.4.0.tar.gz | 411.1 kB | Without provenance | Details for caretaker_mcp-0.4.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| caretaker_mcp-0.4.0-py3-none-any.whl | Python 3 | none | any | Details for caretaker_mcp-0.4.0-py3-none-any.whl |
Total release size: 548.8 kB
Release files / caretaker_mcp-0.4.0.tar.gz
| Download URL | caretaker_mcp-0.4.0.tar.gz |
|---|---|
| Size | 411.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
1058cef1b88ac6cb3b90d329399d5543b0d1f7b34758b414e899f47ed4f429a1
|
|
BLAKE2b-256 checksum How to use checksums |
8142e5931feda42072d6be134957451693cc6afc4f30e04a046d19af27295af5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.6 {"installer":{"name":"uv","version":"0.12.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / caretaker_mcp-0.4.0-py3-none-any.whl
| Download URL | caretaker_mcp-0.4.0-py3-none-any.whl |
|---|---|
| Size | 137.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
bca694f1e7fd5311ad029e3deab32768c64c5441bc8c8bdfe052edbea128f921
|
|
BLAKE2b-256 checksum How to use checksums |
2295568feb34ed305157be844e58cf3e91a1ee845a46adb225fc4d51b033da77
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.6 {"installer":{"name":"uv","version":"0.12.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Security for caretaker-mcp 0.4.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.