Files
mem0/integrations/mem0-agent/README.md
T
Deshraj YadavandClaude Fable 5 e11d2a4a06 fix(mem0-agent): emit the Claude Code manifest at hooks/hooks.json
Claude Code auto-discovers a plugin's hooks at <plugin>/hooks/hooks.json. The
generator was writing to hooks/generated/, so the manifest existed but was never
loaded and no hook would have fired on install.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-29 01:49:27 -07:00

141 lines
6.0 KiB
Markdown

# mem0-agent
Coding memory for Claude Code and friends, built on the [Mem0](https://mem0.ai) platform.
It remembers the things that change how an assistant should behave next time — your
preferences, the decisions you made and why, the team conventions that live nowhere in
the repo, the gotchas you root-caused, the procedures you verified. It deliberately does
not remember what you did today.
Zero runtime dependencies (stdlib only; `keyring` is optional). Every hook fails open —
if the API is down, your session is unaffected.
## Install
```bash
pip install 'mem0-agent[keyring]' # keyring extra stores the API key in the OS keychain
mem0-agent onboard # asks for a key, picks a memory mode, pushes project config
```
Onboarding never reads your shell rc files and never writes a key into a `.env`. The key
comes from `MEM0_API_KEY` or the OS keychain; a key you type at the prompt goes to the
keychain and nowhere else. Get one at <https://app.mem0.ai/dashboard/api-keys>.
To wire the hooks into Claude Code, point your plugin/settings config at the generated
manifest:
```
hooks/hooks.json
```
Non-interactive install (CI, dotfiles, provisioning):
```python
from mem0_agent.onboard import run_onboard
run_onboard(interactive=False, memory_mode="dual", capture="conservative")
```
## The two memory modes
Chosen once per project at onboard, stored per project in `~/.mem0/v2/settings.json`.
The default is DUAL when the repo already has memory files (`CLAUDE.md`, `AGENTS.md`,
`.cursorrules`, `MEMORY.md`, `.claude/memory/`), FULL when it has none.
| | DUAL | FULL |
|---|---|---|
| Repo memory files | authoritative for repo-local notes | not used |
| mem0 holds | durable, cross-machine, cross-repo knowledge | everything |
| MEMORY.md write-blocker | off | on |
| Native auto-memory | leave it on | turn it off |
DUAL is the honest default for a repo that already documents itself: two memory layers
that each know their job. FULL is for people who want one place to look, and it installs
a write gate so the assistant stops appending to `MEMORY.md` behind your back.
Change it later:
```bash
mem0-agent config set memory_mode dual|full
```
## The two aggressiveness dials
```bash
mem0-agent config set capture conservative|balanced|aggressive
mem0-agent config set retrieval conservative|balanced|aggressive
```
- **capture** — how eagerly a moment becomes a candidate memory. `conservative` stores
only explicit "remember this" style signals; `aggressive` also stores inferred
decisions and conventions.
- **retrieval** — how much context is injected at session start (roughly 600 / 1500 /
2500 characters) and how confident an error match must be before it is surfaced.
`conservative` disables error assist entirely.
## How the write gate works
Nothing is stored just because it happened. A candidate has to survive three gates:
1. **Trigger** — a local, network-free detector on `UserPromptSubmit` decides whether the
moment is even a candidate. This runs on the hot path of every turn, so it is
local-only by contract and enforced with `MEM0_LOCAL_ONLY=1` in the generated hook.
2. **Turn boundary** — candidates are buffered and judged at `Stop`, `PreCompact` and
`SessionEnd`, when it is finally clear how the turn ended. One turn costs at most one
write, and all three writes are backgrounded so they are never on your critical path.
3. **Platform policy** — the project's custom instructions are the real gate. They name
the six types (`preference`, `decision`, `convention`, `insight`, `runbook`,
`session_state`) and explicitly exclude progress updates, status heartbeats, file and
commit lists, repo file contents, session-only facts, one-off instructions and
secrets. `mem0-agent onboard` pushes them and verifies the round-trip; the policy
version is stamped into every memory's metadata so a quality regression can be traced
back to the revision that caused it.
Reads are pinned to the project and always `latest_only`, so a superseded memory never
comes back beside the one that replaced it.
## Hooks are generated, not hand-written
`hooks/hooks.spec.yaml` is the single source of truth. It declares each hook's event,
matcher, command, timeout, background/blocking flags, local-only contract, and one line
of *why*.
```bash
python3 hooks/generate.py # write hooks/hooks.json
python3 hooks/generate.py --check # exit 1 if the committed manifest drifted (run in CI)
```
| Event | Matcher | Command | Behavior |
|---|---|---|---|
| SessionStart | `startup\|resume\|compact` | `context` | blocking, injects project knowledge + open threads |
| UserPromptSubmit | — | `observe --source prompt` | blocking, **local-only, no network** |
| PostToolUse | `Bash` | `assist-error` | detached; a hit lands in the session buffer |
| Stop | — | `flush` | detached |
| PreCompact | — | `flush --reason precompact` | detached |
| SessionEnd | — | `flush --reason end` | detached |
Cursor, Codex and Antigravity are declared in the spec as unsupported rather than
deleted, so the gap stays visible instead of turning back into a hand-maintained file.
## Why v2
v1 wrote roughly **98 memories a day**, and almost all of it was heartbeat spam: "started
task X", "80% complete", "modified 3 files", "opened PR #123" — activity you can already
get from git, restated in a memory store where it drowned out the things you actually
wanted back. Retrieval got worse the longer you used it.
v2 targets **under 15 memories a day**, all durable knowledge. The changes that get it
there:
- The write gate above, validated against the real polluted v1 corpus.
- Writes at turn boundaries in batches, instead of one write per tool call.
- No network call on the per-prompt hot path.
- Session state per session ID under `~/.mem0/v2/`, not `/tmp` keyed by `$USER`, so
concurrent sessions stop corrupting each other's counters.
- Project and org pinned in the request body, so coding memories can no longer leak into
whatever project the API key happens to default to.
- One hook spec, generated manifests, drift caught by CI.
## License
Apache-2.0