mem0ry4ai
Persistent, local-first memory for coding agents. Your AI assistant finally remembers your projects between sessions.
Built for Claude Code — and usable from any MCP client
(Gemini CLI, Cursor, OpenCode…) through a built-in MCP server.
Python stdlib + PHP 8 · no Docker, no vector DB, no API keys · GPL-2.0
See it work
One session saves a lesson. A later one asks in plain words, “why were requests timing
out?”, and gets that earlier lesson back, then picks the project up exactly where it
stopped. No cloud, no vector database: a CLI over markdown files your agent reads at the
start of every session.
What is mem0ry4ai?
Coding agents like Claude Code forget everything between sessions —
every trap you debugged together, every decision you made, every "where was I?" when
you return to a project after a month. mem0ry4ai fixes that: it stores durable
knowledge (gotchas, decisions, facts, commands, preferences, todos, project status)
in plain markdown versioned by git, and injects the relevant slice
automatically at the start of every session — scoped to the project you are in.
We surveyed the existing landscape first (claude-mem, basic-memory, mem0, Letta/MemGPT,
Graphiti, the official MCP memory server) and designed against the failure modes we
found: models that forget to call save tools, fragile vector databases, memory that
silently rots, and over-confident auto-extraction.
Use it from any agent (MCP)
mem0ry4ai ships a built-in MCP server (Model Context Protocol), so the same
memory store works with any MCP-capable agent — not just Claude Code.
One command, python3 mem.py mcp, exposes your memory over stdio JSON-RPC; point
Claude Code, Gemini CLI, Cursor, OpenCode or any other MCP client at
it and they recall and save durable knowledge on demand.
- Eight tools
memory_search, memory_get, memory_list, memory_resume, memory_add, memory_note/memory_promote (working memory) and session_search — recall by hybrid search, browse, get a “where was I?” briefing, write new memories (secrets auto-redacted), jot scratch notes, and search your raw past conversations.
- Push and pullClaude Code gets memories pushed at SessionStart via the hook; every other agent pulls them on demand via MCP. One store, two delivery paths.
- Hand-rolled, zero-dependencyThe server is pure Python stdlib — no SDK, no
pip install. Guidance for the model rides the protocol's own instructions field.
- Write toggle
memory_add is on by default; set MEM_MCP_WRITE=0 to make a client read-only — handy when several agents share one store.
Setup is one line — register python3 mem.py mcp as an MCP server in your client
(claude mcp add …, or an mcpServers entry in its config). The
README
has the exact commands per client.
Features
- Markdown + git = source of truthAuditable, diffable, human-editable. The SQLite FTS5 index is derived and disposable — delete it and it regenerates.
- Works with any MCP agentA built-in MCP server exposes the store to Claude Code, Gemini CLI, Cursor, OpenCode and more — recall and save from whatever agent you use, on demand.
- Deterministic session hooksClaude Code hooks inject relevant memories at SessionStart — no relying on the model to remember to recall.
- Supersede, never deleteOutdated facts are marked superseded with a link to their replacement. History stays; git keeps everything.
- Trust-gated captureThe in-context agent writes directly; optional local-LLM extraction (Ollama) goes through a human review queue — we measured small models at ~1.0 confidence on everything.
- "Where was I?" built inFirst-class
todo and status types, pinned first in injection and on each project's page.
- Ranked searchFTS5 (bm25) from both the CLI and the web UI; optional hybrid semantic search via a tiny local embedder (Ollama) when you want it.
- Search past conversations
session_search searches your raw transcript history — "what did we discuss weeks ago?" — over a derived FTS5 index, at zero LLM cost. Secrets stripped before indexing; the index stays owner-only and never leaves your machine.
- Injection-aware writesBecause a stored memory is re-injected into the agent's context every session, writes are flagged when they carry prompt-injection-like phrasing — a non-blocking guard across the CLI, MCP and web, plus an audit command.
- Web UI with live updatesSystem dashboard with health checks, per-project pages, bulk operations, supersede-chain navigation, review queue. Bilingual EN/RO.
- "What Claude sees"A transparency page that renders the exact injection your agent receives, with its size in bytes and tokens.
- Zero heavy dependenciesPython stdlib + PHP 8 + git. The web UI runs on a bundled
php -S launcher, auto-started by the session hook.
Measured impact
Real numbers from the author's monorepo (30 sub-projects, 217 active memories) —
before and after migrating a monolithic CLAUDE.md into mem0ry4ai:
- Before: 242,956 bytes (1,832 lines) of context loaded at every session start ≈ ~61k tokens.
- After: ~29KB at the repo root (≈ ~7.3k tokens) or ~19KB inside a sub-project (≈ ~4.8k tokens) — an 88–92% reduction, scoped to what is actually relevant.
- Overhead: the SessionStart hook costs 69 ms; the live-update poll costs 1–4 ms when nothing changed.
- At the author's measured pace (34 session starts/day) that is roughly 1.8M tokens/day of context that no longer gets loaded — while recall got better, not worse.
Honest caveats: tokens estimated at ~4 chars/token; prompt caching makes billed savings smaller than the raw numbers; one user's setup, not a controlled study.
Screenshots
The dashboard: stat cards, health checks, recent activity with source attribution, live counters.
The Links page: semantic suggested links (closest unlinked pairs, each confirmed or dismissed by hand) above a force-directed graph of every related-to / blocked-by edge — nodes colored by type and sized by degree, related solid, blocked dashed with an arrow. No external libraries.
Projects: every project at a glance — memory count, open todos, current status. Click one to open its page.
The per-project "where was I?" page — status and todo (ready vs blocked) pinned first.
The review queue. Note the junk candidate at confidence 0.95 — exactly why nothing auto-writes.
"What Claude sees": the exact SessionStart injection, with its cost in bytes and tokens.
Git history: the memory timeline — per-commit diffs, commit-from-the-UI. All screenshots use demo data.
Install
Requirements: Python 3.9+ and git — nothing else. No PHP, no Docker, no pip install.
Runs natively on macOS, Linux and Windows.
- Clone the repo:
git clone https://github.com/cremenescu/mem0ry4ai.git
cd mem0ry4ai
- Wire it into Claude Code (registers the hooks with your Python interpreter):
# macOS / Linux
python3 hooks/install.py --target user
# Windows (PowerShell)
py hooks\install.py --target user
then restart Claude Code (or /clear). Every session now starts with your memories injected,
and the web UI auto-starts at http://127.0.0.1:8841/.
- Run things yourself anytime — web UI:
./mem.py serve (py mem.py serve on Windows);
CLI: ./mem.py add / list / search / resume.
Full Windows walkthrough — real install transcript (username shown as xxxxx)
On a clean Windows 11 box with neither Python nor git, install both with winget, then
close and reopen PowerShell (PATH only refreshes in new windows):
PS C:\WINDOWS\system32> winget install -e --id Python.Python.3.12
Found Python 3.12 [Python.Python.3.12] Version 3.12.10
Successfully installed
PS C:\WINDOWS\system32> winget install -e --id Git.Git
Found Git [Git.Git] Version 2.54.0
Successfully installed
PS C:\WINDOWS\system32> py --version
Python 3.12.10
PS C:\WINDOWS\system32> git --version
git version 2.54.0.windows.1
PS C:\WINDOWS\system32> cd $env:USERPROFILE
PS C:\Users\xxxxx> git clone https://github.com/cremenescu/mem0ry4ai.git
Cloning into 'mem0ry4ai'...
Receiving objects: 100% (368/368), 4.01 MiB | 6.30 MiB/s, done.
Resolving deltas: 100% (211/211), done.
PS C:\Users\xxxxx> cd mem0ry4ai
PS C:\Users\xxxxx\mem0ry4ai> py hooks\install.py --target user
installed in C:\Users\xxxxx/.claude/settings.json
Restart Claude Code (or /clear) so the hooks get loaded.
If winget is unavailable (older Windows), install Python from python.org
— tick “Add python.exe to PATH” — and git from git-scm.com,
then continue from the version checks.
If Claude Code then shows “Git is required for local sessions” — it was
running before git was installed, so it doesn't know where bash.exe is. Point it at
git-bash and fully restart:
# confirm the path (default install location)
Test-Path "C:\Program Files\Git\bin\bash.exe"
# if it returns True:
[Environment]::SetEnvironmentVariable("CLAUDE_CODE_GIT_BASH_PATH", "C:\Program Files\Git\bin\bash.exe", "User")
# if git is elsewhere, resolve bash.exe dynamically:
$bash = Join-Path (Split-Path (Split-Path (Get-Command git).Source)) "bin\bash.exe"
[Environment]::SetEnvironmentVariable("CLAUDE_CODE_GIT_BASH_PATH", $bash, "User")
Then close Claude Code completely (check the system tray and Task Manager — it reads
the variable only at startup) and reopen it. The hooks load on the next session and the web UI comes up at
http://127.0.0.1:8841/.
Windows is first-class — no WSL, no PHP. The clone + install.py path registers the
hooks with your interpreter, so they run without a python3 on PATH. (The one-line plugin
install — claude plugin install mem0ry4ai@mem0ry4ai — is the quickest route on macOS/Linux/WSL.)
Your data stays yours. Everything lives in store/*.md on your machine,
versioned by your local git. No cloud, no telemetry, no API keys.
What's not yet there
- Multi-machine sync — sharing one memory store across several computers (designed, not yet built).
- Authentication on the web UI (designed for localhost use).
- Automatic push-injection at session start for agents other than Claude Code — they pull on demand through the MCP server instead, but there is no SessionStart auto-inject for them yet.
License & credits
mem0ry4ai is released under GPL-2.0-or-later.
Built with Python and SQLite FTS5 — and a healthy distrust of over-confident language models.
Changelog
Highlights from the GitHub releases — newest first. See GitHub for every point release.
Memory hygiene — the housekeeping a store that has been growing for months actually needs.
- Consolidation, review-gated —
mem.py consolidate clusters near-duplicate memories and proposes the merge on a separate mem-consolidation git branch. Nothing on main is rewritten until you read the diff and merge it yourself.
- Scheduled maintenance — a local launchd job rebuilds the index, re-embeds what changed, reports stale scratch notes and commits the store while you are not looking. Report-only by default; pruning is opt-in and git-reversible.
- Access-aware injection — the memories you actually reach for float to the top of the session budget, and a per-record cap stops one long note from eating the whole injection.
- Session provenance — every memory records the conversation that wrote it, so “where did this claim come from?” is still answerable months later.
- HTTP ingestion —
POST /api/propose lets agents and scripts that speak neither MCP nor the CLI propose a memory: queue-only, redacted and scanned, never straight into the store.
v0.15.1
· 2026-07-22
— block stored memory-injection
Hardening — a stored memory can no longer forge a trusted rule.
- Stored memory-injection blocked — a memory's body or summary could previously smuggle the store's own record delimiters or a fake section heading, letting a low-trust write (e.g. an agent's
memory_add) forge a second record, or escalate its own, to priority: critical and have it injected at the top of every session. Writes now neutralize those delimiters, and an injected body can no longer forge a ## Critical rules section in the SessionStart context. Ordinary markdown in your notes is left untouched.
v0.15.0
· 2026-07-03
— session search + injection scan on write
Search your past conversations — and a guard against poisoned memories.
- Session search — a new
session_search tool (and mem.py sessions) searches your raw conversation history, not just the distilled store: “what did we actually discuss weeks ago?” over a derived FTS5 index of the transcripts, at zero LLM cost. Secrets are stripped before indexing; the index is owner-only and gitignored. Brings the MCP server to eight tools.
- Injection scan on write — a memory is flagged if it contains prompt-injection-like phrasing (“ignore your instructions and…”), since a stored memory is re-injected into the agent's context every session. A non-blocking, write-time authoring aid across the CLI, MCP and web add paths, plus
mem.py audit.
v0.12.0
· 2026-06-18
— a power-user settings page
A power-user settings page — and config that finally reaches every process.
- Settings page in the web UI — 20 tunable knobs (injection budget & thresholds, search ranking, the duplicate guard, embeddings, safety toggles) grouped, validated and clamped, each with a plain-English description, an “applies when” badge and reset-to-defaults. No more editing source to change a constant.
- Cross-process config — settings persist to
.mem-local.env and are now read by the hook, the CLI and the MCP server, not just the web server. So changing the injection budget actually changes what gets injected; a value exported in your shell still takes precedence on load.
v0.11.0
· 2026-06-17
— MCP server: use your memory from any agent
- Built-in MCP server (
mem.py mcp) — the store is now reachable from any MCP client (Gemini CLI, Cursor, OpenCode, …), not just Claude Code. Five tools (memory_search / get / list / resume / add), hand-rolled on the Python stdlib (no SDK, no pip install), with model guidance delivered through the protocol's own instructions field. Read tools are always on; writes are gated by MEM_MCP_WRITE.
- Cross-writer file locking — every store writer (CLI, web UI, MCP, multiple agents) now serializes through one reentrant lock with a PID-liveness stale-steal, so concurrent writes can't interleave or lose an append.
v0.10.3
· 2026-06-17
— RRF search fusion + phrase-match rerank
- The keyword (bm25 + recency) and semantic rankings are now fused with Reciprocal Rank Fusion (k=60) instead of an ad-hoc 0.5/0.5 score blend — robust to the bm25-vs-cosine scale mismatch. A light rerank lifts an exact summary-phrase match toward the top. Tunable via
MEM_RRF_K.
v0.10.0
· 2026-06-17
— set the link-suggestion threshold from the UI
- The Links page gained a Threshold control for “suggested links”, read live (no server reload) and persisted to
.mem-local.env so it survives restarts. (v0.10.1–v0.10.2 polished its styling.)
v0.9.0
· 2026-06-17
— “About me” profile + redaction on every write path
- About me — a
profile memory type and a web page where you describe yourself; it is injected first at every SessionStart so the assistant tailors its help to you.
- Redaction on every write path —
update_memory now redacts secrets too (not just add), so editing a memory can't leak a credential into the store. (v0.9.1 added web-server auto-reload on code change; v0.9.2 shows where the profile is stored.)
v0.8.0
· 2026-06-16
— CLAUDE.md editor + the real fix for web-UI “CSRF”
- Every web-UI mutation returned “CSRF” since the v0.7.0 rewrite: the JS sent the body as
FormData (multipart) but the server parses only urlencoded, so the token was never read. Fixed by sending URLSearchParams.
- CLAUDE.md editor in the web UI — edit your project
CLAUDE.md files with atomic, backed-up writes.
v0.7.0
· 2026-06-16
— Python-only web UI (PHP removed, Windows-native)
The web UI is now pure Python — PHP removed, native on macOS, Linux and Windows.
- Web UI rewritten from PHP to a stdlib
http.server (mem.py serve). Same pages, byte-for-byte, in the browser — only the engine changed. Verified page-by-page against the old PHP UI for 1:1 content parity. Requirements drop to just Python 3.9+ and git: no PHP, no bash, no Docker, no pip install.
- One codebase, one parser — the CLI and the web UI now share a single Python parser + write layer in
mem.py. The second parser (lib.php) and the conformance contract that kept them in sync are deleted — that whole class of drift bug is gone.
- Native Windows — no WSL, no PHP: clone, then
py mem.py serve. The hooks register with your own interpreter, so they run without a python3 on PATH.
v0.6.3
· 2026-06-16
— Project-grouped suggestions, compaction-boundary flush, resume
- Link suggestions grouped by project — the Links page organizes suggested links into per-project bands (two subtle alternating tints, not a rainbow), so you scan one project's overlaps at a time. A band disappears the moment its last suggestion is linked or dismissed.
mem.py resume — a “where was I?” briefing for a scope (latest status + ready/blocked todos + recent knowledge), or a one-line-per-project overview with no --scope. Mirrors what SessionStart injects, from the terminal.
- Flush at the compaction boundary — the auto-commit + auto-embed that ran at session end now also run on PreCompact, so a long session that compacts mid-way loses nothing and search/suggestions stay fresh — without relying on advance notice before compaction.
v0.6.2
· 2026-06-15
— Add-time duplicate warning + auto-embed at session end
- Duplicate warning at write time —
mem.py add now searches semantically before saving and, if a near-duplicate of the same type already exists, prints a warning (it never blocks) with the closest matches and a ready-to-run supersede command. Overlapping memories get merged instead of accumulating. Tunable with MEM_DUP_THRESHOLD; mute with --no-dup-check.
- Auto-embed at session end — the SessionEnd hook refreshes the semantic vectors automatically (detached, non-blocking, incremental), so hybrid search and the Links suggestions reflect memories written this session without running
mem.py embed by hand.
v0.6.1
· 2026-06-15
— Auto-detected search-mode light + semantic-on-no-keyword-match fix
- Search status light — no toggle to remember. The Memories page auto-detects the local embedder and shows what each search actually did: green = Ollama is up, so search is keyword + semantic; gray = it fell back to classic keyword search, with the reason (Ollama off / no vectors) on hover. The dashboard health panel reports the embedder too.
- Fix: semantic search now fires even when nothing keyword-matches — previously search returned empty as soon as the keyword query found no rows, skipping the semantic layer entirely (defeating its whole purpose). It now surfaces semantic matches for queries like
4090 → your GPU notes, mirroring mem.py search.
- Robustness — keyword and semantic stages are now isolated, so a semantic-layer error can never mislabel a good keyword result as “substring”; and an absent vector store is distinguished from an unreadable one.
mem.py search prints the mode it used; --no-semantic forces keyword-only.
v0.6.0
· 2026-06-15
— Procedural type, bi-temporal supersede, hybrid search, link suggestions
- Semantic link suggestions — the Links page now offers the closest unlinked memory pairs as suggested
related-to edges; you confirm or dismiss each one. Nothing is linked automatically.
- Optional hybrid search — with Ollama + a tiny embedder (
all-minilm, ~40 MB), search fuses keyword scores with cosine similarity over locally-stored vectors, so “auth token expiry” finds “JWT TTL”. Retrieval-only — it never decides or writes, so it stays clear of the trust gate; no Ollama means a silent keyword-only fallback.
- Bi-temporal supersede — superseding now keeps when a fact stopped being true (
invalidated) and why (invalid-reason), separate from created. Full “what did we believe, and when” history.
procedural type for reusable runbooks, a files field tying a memory to the paths it concerns (indexed + chips), and recency-weighted ranking so fresher memories win near-ties.
v0.5.1
· 2026-06-15
— A visual relations graph
- Links page — the
related-to / blocked-by edges now render as a force-directed graph: nodes colored by memory type and sized by degree, related edges solid, blocked edges dashed with an arrow. Drag to rearrange, click a node to open its memory, hover to highlight neighbours; a grouped text list sits below.
- No external libraries — a small vanilla-JS + SVG simulation, fully offline (no CDN, no D3), reading the same data as the list so the two can never drift. Reached via a Links stat card and a top-nav entry.
v0.5.0
· 2026-06-15
— Memory relations, ready work, restructured web UI
- Relations — link related memories with
mem.py link (related-to): a gotcha ↔ the decision that caused it, a status ↔ its todos. Deliberate, never keyword-auto-guessed.
- Ready work —
blocked-by on todos + mem.py ready lists what you can tackle now; the per-project page splits ready vs blocked.
- Web UI restructured —
index.php is a dashboard, the list moved to memories.php, a new projects.php summarizes every project. Shared top bar + breadcrumbs everywhere.
v0.4.0
· 2026-06-15
— Self-budgeted injection, secret redaction, plugin install
- Critical rules + injection budget — the SessionStart injection trims itself below the harness threshold instead of being truncated blindly.
priority: critical rules are always injected first; the rest fills MEM_INJECT_BUDGET, and every cut is announced.
- Secret redaction on every write path (8 patterns) — redacted before reaching the local LLM.
mem.py audit reports what is already stored.
- Claude Code plugin —
claude plugin install mem0ry4ai@mem0ry4ai; data lives in ~/.mem0ry4ai. Plus date-filtered search and a live git history page.
v0.3.0
· 2026-06-10
— Automatic end-of-session git checkpoint
- Auto-checkpoint — the SessionEnd hook now commits
store/ by itself; memories written during a session land in git history with no manual action.
- Health panel: an uncommitted store is an informative gray state, not a red error — it is the normal mid-session condition.
- The commit button on the git history page remains for mid-session checkpoints with a custom message.
v0.2.0
· 2026-06-10
— Git history page
- Git history page — the store's timeline in the web UI: every commit touching
store/ with a lazy-loaded, colored diff.
- Commit from the UI — uncommitted store changes are listed, with a button that commits store files only (authored
mem0ry4ai web, no signing, never touches code).
- README: Measured impact section (real before/after numbers) + screenshot gallery with demo data.
v0.1.0
· 2026-06-10
— First public release
- Markdown + git as the source of truth — auditable, supersede-never-delete; the SQLite FTS5 index is derived and disposable.
- Claude Code hooks: inject relevant memories at SessionStart (scoped per project, capped multi-project index from a monorepo root), capture transcript pointers at SessionEnd/PreCompact.
- Trust-gated capture: the in-context agent writes directly; optional offline extraction with a local LLM (Ollama) goes through a human review queue.
- First-class
todo and status types — pinned first in injection and UI.
- Web UI: dashboard with health checks and live updates, per-project pages, FTS5 ranked search, bulk operations, supersede-chain navigation, "What Claude sees" preview, review queue. Bilingual EN/RO.
- Standalone server (
php -S launcher with PHP_CLI_SERVER_WORKERS), auto-started by the session hook. Binaries resolved from PATH with env overrides.