{
  "markdown": "# agent-recall\n\n[![Tests](https://github.com/mnardit/agent-recall/actions/workflows/tests.yml/badge.svg)](https://github.com/mnardit/agent-recall/actions/workflows/tests.yml)\n[![PyPI](https://img.shields.io/pypi/v/agent-recall)](https://pypi.org/project/agent-recall/)\n[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)\n[![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue.svg)](https://pypi.org/project/agent-recall/)\n\n**Persistent memory for AI coding agents.** Your agent forgets everything between sessions — names, decisions, preferences, context. agent-recall fixes this.\n\nBuilt from production: extracted from a real system running **30+ concurrent AI agents** at a digital agency. Not a prototype — every feature exists because something broke in production.\n\n```\nBefore:  \"Who is Alice?\" (every single session)\nAfter:   Agent starts with: \"Alice — Lead Engineer at Acme, prefers async,\n         last discussed the API migration on Feb 12\"\n```\n\n**MCP-native** — designed for MCP-compatible clients. Tested configs included for Claude Code, Cursor, Windsurf, and Cline. Battle-tested daily with Claude Code (30+ agents in production). [PRs and issue reports welcome!](https://github.com/mnardit/agent-recall/issues)\n\n### Why agent-recall?\n\nOther memory solutions exist (Mem0, Zep/Graphiti, LangMem). Here's what makes agent-recall different:\n\n- **Scope hierarchy** — not flat memory. The same person can have different roles in different projects. agent-recall is built around scope chains with inheritance — designed for agents working across multiple clients, projects, and nested contexts.\n- **AI briefings** — raw data dumps don't work. agent-recall uses an LLM to summarize hundreds of facts into structured, actionable context injected at session start.\n- **Local-first** — single SQLite file. No cloud, no vector DB, no Docker, no Neo4j. Your data stays on your machine.\n- **MCP-native** — 9 memory tools with proactive-saving instructions. Tested configs for Claude Code, Cursor, Windsurf, and Cline.\n- **Bitemporal** — old values are archived, not deleted. Query what was true at any point in time.\n- **Minimal dependencies** — just `pyyaml` + `click`. MCP and Anthropic SDK are optional extras.\n\n---\n\n## How It Works\n\n```\n┌─────────────────────────────────────────────────────────────────────┐\n│                         SESSION 1                                   │\n│                                                                     │\n│  You: \"Alice from Acme called. She wants the API done by Friday.\"   │\n│                           │                                         │\n│                           ▼                                         │\n│  Agent saves automatically via MCP tools:                           │\n│    create_entities: Alice (person), Acme (client)                   │\n│    add_observations: \"wants API done by Friday\"                     │\n│    create_relations: Alice → works_at → Acme                        │\n│                           │                                         │\n│                           ▼                                         │\n│  Stored in local SQLite ─────► ~/.agent-recall/frames.db            │\n└─────────────────────────────────────────────────────────────────────┘\n                            │\n                     (session ends)\n                            │\n┌─────────────────────────────────────────────────────────────────────┐\n│                         SESSION 2                                   │\n│                                                                     │\n│  Agent starts and receives a briefing:                              │\n│    \"Alice (Lead Engineer, Acme) — wants API done by Friday.         │\n│     Acme is a client. Last discussed Feb 12.\"                       │\n│                           │                                         │\n│                           ▼                                         │\n│  Agent already knows who Alice is, what's urgent, and what to do.   │\n└─────────────────────────────────────────────────────────────────────┘\n```\n\n**Why does the agent save facts automatically?** The MCP server includes behavioral instructions that tell the agent to proactively save people, decisions, and context as it encounters them. No special prompting needed — the agent receives these instructions when it connects to the memory server.\n\n---\n\n## Setup\n\n### Step 1: Install\n\n```bash\npip install 'agent-recall[mcp]'\nagent-recall init\n```\n\nThis creates the SQLite database at `~/.agent-recall/frames.db`.\n\n> `agent-recall[mcp]` installs with MCP server support. Use `pip install agent-recall` if you only need the Python API/CLI.\n\n#### Step 2: Add MCP server to your editor\n\nThis gives your agent the memory tools (`create_entities`, `add_observations`, `search_nodes`, etc.) and the instructions to use them proactively.\n\n<details open>\n<summary><strong>Claude Code</strong> ✅ Production-tested</summary>\n\nAdd to `.mcp.json` in your project root:\n\n```json\n{\n  \"mcpServers\": {\n    \"memory\": {\n      \"command\": \"python3\",\n      \"args\": [\"-m\", \"agent_recall.mcp_server\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><strong>Cursor</strong></summary>\n\nAdd to `.cursor/mcp.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"memory\": {\n      \"command\": \"python3\",\n      \"args\": [\"-m\", \"agent_recall.mcp_server\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><strong>Windsurf</strong></summary>\n\nAdd to `~/.codeium/windsurf/mcp_config.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"memory\": {\n      \"command\": \"python3\",\n      \"args\": [\"-m\", \"agent_recall.mcp_server\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><strong>Cline</strong></summary>\n\nAdd to `cline_mcp_settings.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"memory\": {\n      \"command\": \"python3\",\n      \"args\": [\"-m\", \"agent_recall.mcp_server\"]\n    }\n  }\n}\n```\n</details>\n\n#### Step 3: (Claude Code) Add hooks for automatic context injection\n\nHooks make the agent receive its memory briefing at the start of every session, and keep caches fresh after writes. **This step is optional but strongly recommended for Claude Code users.**\n\nAdd to `.claude/settings.json` (project or global):\n\n```json\n{\n  \"hooks\": {\n    \"SessionStart\": [\n      {\n        \"hooks\": [\n          {\n            \"type\": \"command\",\n            \"command\": \"agent-recall-session-start\"\n          }\n        ]\n      }\n    ],\n    \"PostToolUse\": [\n      {\n        \"matcher\": \"mcp__memory__.*\",\n        \"hooks\": [\n          {\n            \"type\": \"command\",\n            \"command\": \"agent-recall-post-tool-use\"\n          }\n        ]\n      }\n    ]\n  }\n}\n```\n\n| Hook | What it does |\n|------|-------------|\n| `SessionStart` | Injects AI briefing (or raw context) into the agent's system prompt when a session starts |\n| `PostToolUse` | After the agent writes to memory (matched by `mcp__memory__.*`), invalidates stale caches and regenerates vault files |\n\n> **Other editors:** Hooks are Claude Code-specific. For other clients, use the [CLI](#cli) (`agent-recall generate`) or [Python API](#python-api) to generate and serve briefings.\n\n#### Step 4: Verify it works\n\nStart a new session with your agent and look for:\n- The agent should have memory tools listed (e.g., `create_entities`, `search_nodes`)\n- If hooks are set up, the agent shows a \"Memory is empty\" message on first run\n- Mention a person or make a decision — the agent should save it automatically\n- Start another session — the agent should know about the person/decision\n\n---\n\n## Quick Start\n\nGet a working memory system in 3 minutes:\n\n```bash\n# Install\npip install 'agent-recall[mcp]'\n\n# Initialize the database\nagent-recall init\n\n# Set your agent identity\nexport AGENT_RECALL_SLUG=my-project\n\n# Add to your .mcp.json (Claude Code example)\ncat > .mcp.json << 'EOF'\n{\n  \"mcpServers\": {\n    \"memory\": {\n      \"command\": \"python3\",\n      \"args\": [\"-m\", \"agent_recall.mcp_server\"]\n    }\n  }\n}\nEOF\n\n# Start Claude Code — memory tools are now available!\n# The agent can create_entities, add_observations, search_nodes, etc.\n\n# Generate an AI briefing from stored knowledge\nagent-recall generate my-project\n```\n\nThat's it! Your agent now has persistent memory across sessions. The MCP server\nexposes 9 tools for reading and writing the knowledge graph. See [Configuration](#configuration)\nfor customization options.\n\n---\n\n## What Happens Under the Hood\n\nHere's the full lifecycle:\n\n```\n1. CONNECT\n   Agent connects to MCP server\n   └─► Server sends instructions: \"Proactively save people, decisions, facts...\"\n   └─► Agent receives 9 memory tools with descriptions explaining when to use each\n\n2. SAVE (during conversation)\n   Agent encounters important information\n   └─► search_nodes(\"Alice\")           — check if entity exists\n   └─► create_entities([{...}])        — create if new\n   └─► add_observations([{...}])       — add facts to existing entity\n   └─► create_relations([{...}])       — link entities together\n   All stored in ~/.agent-recall/frames.db (SQLite, scoped per project)\n\n3. NOTIFY (PostToolUse hook, Claude Code only)\n   After each memory write\n   └─► Marks affected agent caches as stale\n   └─► Regenerates Obsidian vault files (if configured)\n\n4. BRIEFING (SessionStart hook or CLI)\n   Next session starts\n   └─► Reads cached AI briefing (if fresh)\n   └─► Or assembles raw context from database\n   └─► Or generates new briefing via LLM (if stale + adaptive mode)\n   └─► Injects into agent's system prompt\n\n5. AGENT KNOWS\n   Agent starts with structured context:\n   └─► Key people, their roles, preferences\n   └─► Current tasks, blockers, deadlines\n   └─► Recent decisions and their rationale\n```\n\n---\n\n## Key Concepts\n\n| Concept | Description |\n|---------|-------------|\n| **Entity** | A named thing: person, client, project. Has a type and unique name. |\n| **Slot** | A key-value pair on an entity (e.g., `role: \"Engineer\"`). Scoped and bitemporal — old values are archived, not deleted. |\n| **Observation** | Free-text fact attached to an entity (e.g., \"Prefers async communication\"). Scoped. |\n| **Relation** | Directed link between two entities (e.g., Alice —works_at→ Acme). |\n| **Scope** | Namespace for data isolation. Slots and observations belong to a scope (e.g., `\"global\"`, `\"acme\"`, `\"proj-a\"`). |\n| **Scope chain** | Ordered list of scopes from general to specific: `[\"global\", \"acme\", \"proj-a\"]`. Local overrides parent for the same slot. |\n| **Tier** | Agent importance level: 0 = no context, 1 = minimal, 2 = full (default), 3 = orchestrator (sees everything). |\n| **Briefing** | AI-generated summary of raw memory data, injected into agent's system prompt at startup. Cached and invalidated adaptively. |\n\n---\n\n## Features\n\n### Scoped Memory\n\nNot a flat key-value store. Memory is **scoped** — the same person can have different roles in different projects:\n\n```\nAlice:\n  role (global)     = \"Engineer\"\n  role (acme)       = \"Lead Engineer\"    ← Agent working on Acme sees this\n  role (beta-corp)  = \"Consultant\"       ← Agent working on Beta sees this\n```\n\nScoping keeps context clean across projects and prevents data from leaking between workstreams.\n\n### AI Briefings\n\nRaw data dumps don't work. Thousands of facts is noise, not context.\n\nagent-recall uses an LLM to **summarize** what matters into a structured briefing:\n\n```\nRaw (what's in the database):\n  147 slots across 34 entities, 89 observations, 23 relations...\n\nBriefing (what the agent actually sees):\n  ## Key People\n  - Alice (Lead Engineer, Acme) — prefers async, owns the API migration\n  - Bob (PM) — on vacation until Feb 20\n\n  ## Current Tasks\n  - API migration: blocked on auth module (Alice working on it)\n  - Dashboard redesign: waiting for Bob's review\n\n  ## Recent Decisions\n  - Team agreed to use GraphQL on Feb 10 call\n  - Next client meeting: Feb 19\n```\n\nGenerate briefings via CLI (`agent-recall generate my-agent`) or let the SessionStart hook handle it automatically.\n\n### Multi-Agent Ready\n\nBuilt for systems with multiple agents sharing one knowledge base but seeing different slices:\n\n```\nglobal → acme-agency → client-a      (client-a sees: global + acme + client-a)\n                     → client-b      (client-b sees: global + acme + client-b)\n       → personal → side-project     (side-project sees: global + personal + side-project)\n```\n\nEach agent reads and writes within its scope chain. The MCP server enforces this automatically.\n\n### Adaptive Cache\n\nWhen one agent saves new facts, caches for affected agents are marked stale. Next time those agents start a session, their briefings regenerate automatically.\n\n---\n\n## Configuration\n\nFor a single agent with defaults, no config file is needed. By default, agent-recall auto-discovers project files (`CLAUDE.md`, `README.md`, `.cursorrules`, `.windsurfrules`) in the current directory and includes them in the data sent to the LLM for briefing generation. This means new agents get useful briefings from day one, even with an empty database. Disable with `auto_discover: false` in the briefing config.\n\nFor multiple agents or custom settings, create `memory.yaml` in your project root or `~/.agent-recall/memory.yaml`:\n\n```yaml\n# Database location (default: ~/.agent-recall/frames.db)\ndb_path: ~/.agent-recall/frames.db\ncache_dir: ~/.agent-recall/context_cache\n\n# Scope hierarchy — which agents see which data\nhierarchy:\n  acme-agency:\n    - client-a\n    - client-b\n\n# Tier 0 = no context injection, Tier 2 = full\ntiers:\n  0: [infra-bot]\n  2: [acme-agency, client-a, client-b]\n\n# AI briefing settings\nbriefing:\n  backend: cli          # \"cli\" = claude -p (free on subscription), \"api\" = Anthropic SDK (needs API key)\n  model: opus           # LLM model for generating briefings\n  timeout: 300          # LLM timeout in seconds\n  adaptive: true        # Auto-regenerate stale caches\n  min_cache_age: 1800   # Minimum 30 min between regenerations\n\n# Per-agent overrides\nagents:\n  coordinator:\n    model: opus\n    output_budget: 12000\n  dashboard:\n    model: haiku\n    template: system\n```\n\n<details>\n<summary><strong>All per-agent options</strong></summary>\n\n| Key | Type | Description |\n|-----|------|-------------|\n| `model` | string | LLM model for this agent's briefings |\n| `timeout` | int | LLM timeout in seconds |\n| `output_budget` | int | Target output size in characters |\n| `template` | string | Builtin type name or inline text |\n| `enabled` | bool | Disable briefing generation (default: true) |\n| `context_files` | list | Extra files to include in context |\n| `context_budget` | int | Max chars for context files (default: 8000) |\n| `extra_context` | string | Static text appended to raw context |\n| `adaptive` | bool | Per-agent adaptive cache override |\n| `min_cache_age` | int | Min seconds between regenerations |\n\n</details>\n\n**Environment variables:**\n\n| Variable | Description |\n|----------|-------------|\n| `AGENT_RECALL_SLUG` | Explicit agent identifier (defaults to current directory name) |\n\n---\n\n## LLM Backend\n\nAI briefings need an LLM to generate summaries. Two built-in backends:\n\n| Backend | Config | Install | Cost | Notes |\n|---------|--------|---------|------|-------|\n| `cli` (default) | `backend: cli` | Claude Code installed | Free on Claude Pro/Team subscription | Creates a session file per call |\n| `api` | `backend: api` | `pip install 'agent-recall[api]'` | Pay per token | Clean, no side effects, needs `ANTHROPIC_API_KEY` |\n\nSwitch in `memory.yaml`:\n```yaml\nbriefing:\n  backend: api    # uses Anthropic SDK instead of claude CLI\n  model: opus\n```\n\n### Bring Your Own LLM\n\nFor other providers, pass a callable matching `(prompt, model, timeout) -> str`:\n\n```python\nfrom agent_recall import generate_briefing, LLMResult\n\ndef my_llm(prompt: str, model: str, timeout: int) -> LLMResult:\n    result = call_my_api(prompt, model)\n    return LLMResult(text=result.text, input_tokens=result.usage.input,\n                     output_tokens=result.usage.output)\n\ngenerate_briefing(\"my-agent\", llm_caller=my_llm, force=True)\n```\n\nFull examples: [OpenAI](examples/llm_openai.py) | [Anthropic SDK](examples/llm_anthropic.py) | [Ollama](examples/llm_ollama.py)\n\nBy default, briefing generation uses the `claude` CLI (`claude -p --model <model>`). If you don't use Claude, pass your own `llm_caller`.\n\n---\n\n## CLI\n\n```bash\nagent-recall init                          # Create database\nagent-recall status                        # Database stats\nagent-recall set Alice role Engineer       # Set slot (existing entity)\nagent-recall set Alice role Engineer --type person  # Create new entity + set slot\nagent-recall get Alice role                # Get slot value\nagent-recall entity Alice                  # Show entity details + observations\nagent-recall entity Alice --scope global --scope acme  # Scoped slot resolution\nagent-recall entity Alice --json           # JSON output\nagent-recall list                          # List all entities\nagent-recall list --type person            # Filter by type\nagent-recall search \"engineer\"             # Search entities\nagent-recall history Alice role            # Bitemporal slot history\nagent-recall log Alice \"Joined the team\"   # Add log entry\nagent-recall log Alice \"Update\" --author human  # Log with custom author\nagent-recall logs Alice                    # Show log entries\nagent-recall generate my-agent --force     # Generate AI briefing\nagent-recall refresh --force               # Refresh all briefings\nagent-recall observe Alice \"Prefers async\"   # Add observation to entity\nagent-recall delete Alice                    # Delete entity\nagent-recall templates                       # List briefing templates\nagent-recall rename-scope old-name new-name  # Migrate data between scopes\n```\n\n## Python API\n\n```python\nfrom agent_recall import MemoryStore, ScopedView\n\nwith MemoryStore() as store:\n    # Create entities\n    alice = store.resolve_entity(\"Alice\", \"person\")\n    acme = store.resolve_entity(\"Acme Corp\", \"client\")\n\n    # Scoped slots — same key, different values per scope\n    store.set_slot(alice, \"role\", \"Engineer\", scope=\"global\")\n    store.set_slot(alice, \"role\", \"Lead Engineer\", scope=\"acme\")\n    store.add_observation(alice, \"Prefers async communication\", scope=\"acme\")\n    store.add_relation(alice, acme, \"works_at\")\n\n    # Scoped view — local overrides parent\n    view = ScopedView(store, [\"global\", \"acme\"])\n    entity = view.get_entity(\"Alice\")\n    print(entity[\"slots\"][\"role\"])  # \"Lead Engineer\" (acme overrides global)\n\n    # Search across all entities\n    results = store.search(\"engineer\")\n    print(results)  # [{\"name\": \"Alice\", \"type\": \"person\", ...}]\n\n    # Bitemporal history — see all past values\n    store.set_slot(alice, \"role\", \"Staff Engineer\", scope=\"acme\")\n    history = store.get_slot_history(alice, \"role\")\n    # Returns: all values with valid_from/valid_to timestamps\n\n    # Atomic operations\n    with store.transaction():\n        bob = store.resolve_entity(\"Bob\", \"person\")\n        store.set_slot(bob, \"role\", \"PM\")\n        store.add_relation(bob, acme, \"works_at\")\n```\n\nSee [`examples/quickstart.py`](examples/quickstart.py) for a runnable version.\n\n---\n\n## Troubleshooting\n\n<details>\n<summary><strong>Agent doesn't save facts automatically</strong></summary>\n\nThe MCP server includes instructions that tell the agent to proactively save. If it's not working:\n1. Verify the MCP server is connected: your agent should list `create_entities`, `search_nodes` etc. as available tools\n2. Check the server is running: `python3 -m agent_recall.mcp_server` should start without errors\n3. Some agents need a nudge — mention \"save this to memory\" in your prompt\n</details>\n\n<details>\n<summary><strong>Briefings are empty or generation fails</strong></summary>\n\n1. Check you have data: `agent-recall status` should show entities\n2. The default `cli` backend needs Claude Code installed (`claude -p`). If you don't use Claude, configure the `api` backend with `ANTHROPIC_API_KEY`, or pass your own `llm_caller` (see [LLM Backend](#llm-backend))\n3. Run with force: `agent-recall generate my-agent --force`\n4. Check cache dir exists: `ls ~/.agent-recall/context_cache/`\n</details>\n\n<details>\n<summary><strong>Windows: <code>python3</code> not found</strong></summary>\n\nOn Windows, Python is usually `python` not `python3`. Update your MCP config:\n```json\n{\n  \"mcpServers\": {\n    \"memory\": {\n      \"command\": \"python\",\n      \"args\": [\"-m\", \"agent_recall.mcp_server\"]\n    }\n  }\n}\n```\n</details>\n\n---\n\n## Born in Production\n\nagent-recall was extracted from a live system managing real client projects at a digital agency — 30+ agents, 15+ clients, hundreds of scoped facts.\n\nWhy specific features exist:\n- **Scope isolation** — two agents wrote conflicting data to the same entity\n- **Adaptive caching** — briefings went stale during busy hours\n- **AI summaries** — agents couldn't make sense of raw data dumps with hundreds of entries\n- **Proactive saving instructions** — agents ignored memory tools until explicitly told to use them\n- **Bitemporal slots** — needed to track what was true *when*, not just what's true now\n\n### agent-recall vs Claude Code Auto-Memory\n\n| Feature | agent-recall | CC Auto-Memory |\n|---------|-------------|----------------|\n| **Storage** | SQLite knowledge graph | Markdown files |\n| **Structure** | Entities, relations, observations, scopes | Flat key-value in MEMORY.md |\n| **Multi-agent** | Shared DB with scope isolation | Per-project, single-agent |\n| **Search** | Full-text across entities, slots, observations | File-based |\n| **AI Briefings** | LLM-summarized context at session start | Raw memory injected |\n| **Scope control** | Hierarchical (global → parent → child) | Per-project directory |\n| **Best for** | Teams of agents, complex projects | Single agent, simple projects |\n\nThey can work together: use auto-memory for quick preferences and agent-recall\nfor structured knowledge that spans agents and sessions.\n\n---\n\n## Development\n\n```bash\ngit clone https://github.com/mnardit/agent-recall.git\ncd agent-recall\npip install -e \".[dev]\"\npytest\n```\n\n388 tests covering store, config, hierarchy, context assembly, AI briefings, vault generation, hooks, dedup, MCP bridge, FTS search, and migrations.\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.\n\n## License\n\nMIT\n",
  "bytes": 22231,
  "sha": "18c216bef8080c5fa79d05e5cf9c8e0d46737b5b2b4f21c0399585f633685b18",
  "repo_slug": "mnardit/agent-recall",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/plg_mnardit_agent_recall_agent_recall_56cebae1/readme"
}