🧠 MarkMem
A memory layer for chatbots that stores memory as plain markdown in a git repo.
Installation • Quick Start • Key Features • How it Works • API
What is MarkMem?
Chatbots forget. The usual fix—writing memories into a vector database—trades one problem for four: you can't inspect your own memory, you can't see what changed or why, facts overwrite each other silently, and proving user data erasure is nearly impossible.
MarkMem is different. Your chatbot's memory is a folder you can cat, grep, git diff, and delete. SQLite is a rebuildable cache on top; delete it and markmem reindex restores it from the markdown.
Why MarkMem? (The Ecosystem Gap)
The market is crowded with "Markdown + hybrid search" tools (like memweave and basic-memory), and massive vector/graph databases (like Mem0 and Graphiti).
MarkMem occupies a strictly unique gap. It is the only memory layer that combines these three pillars:
- Bi-Temporal Facts in YAML: Old facts are never deleted or silently overwritten. If a user changes jobs from Google to Microsoft, the Google claim is closed (
valid_until) and a successor pointer (supersedes) is created. This allows perfect temporal reasoning (as_ofqueries) instead of just relying on score decay. - Presidio as a Write Gate: Native integration with Microsoft Presidio blocks or masks sensitive PII (SSNs, emails, credit cards) before it ever hits the disk.
- Git as the Compliance Surface: Your audit log isn't an opaque database table; it's
git log. When GDPR erasure is required, MarkMem performs provable, path-scoped deletes and rewrites the git history.
(It also includes everything you expect: BM25+Vector RRF fusion, 100+ LLMs via LiteLLM, injection quarantines, an MCP Server, and a REST API).
Installation
pip install markmem # core: markdown + git + BM25. no external DB
pip install "markmem[vector]" # + semantic search (recommended)
pip install "markmem[all]" # everything below
| Extra | Adds | For |
|---|---|---|
vector |
sqlite-vec, model2vec | Hybrid BM25 + semantic search (RRF fusion) |
litellm |
litellm | Compile memory with any of 100+ LLMs |
llm |
anthropic, openai | Native Claude / OpenAI extractors |
pii |
presidio | 30+ PII entity types instead of regex |
mcp |
mcp | MCP server for Claude Code / Desktop |
api |
fastapi, uvicorn | REST server |
crypto |
cryptography | AES-256-GCM crypto-shred erasure |
Note: Nothing degrades hard. No vector extra → BM25 only. No LLM key → heuristic extractor. The core never imports torch.
Quick Start
from markmem import Memory
m = Memory(repo_path="./chat-memory")
# 1. Add facts (compiles asynchronously)
m.add("I'm vegetarian and prefer window seats", user_id="alice")
m.add("Actually I prefer aisle seats now", user_id="alice")
m.flush()
# 2. Retrieve packed memory for your prompt
print(m.search("alice seating", user_id="alice", format="context"))
Output:
### Memory (cite ids when you rely on these)
[u/alice/user/profile | user | conf 0.85 | updated 2026-07-31]
- (user_stated, 0.85) I am vegetarian
- (user_stated, 0.85) I prefer aisle seats
(Notice how the aisle seat supersedes the window seat, while the vegetarian fact remains!)
How it works
add("I prefer aisle seats now", user_id="alice")
│
├─ PII gate ............ Presidio/regex → tag | mask | block
├─ Injection guard ..... instruction-override patterns → quarantine
├─ raw/ append ......... immutable, timestamped, never rewritten
└─ SQLite queue ........ add() returns; compile happens off the hot path
│
background worker ───────────┘
│
├─ Extractor ......... heuristic (default) | any LLM
├─ Claim resolver .... same subject + different value?
│ → close old (valid_until), new supersedes
├─ Review gate ....... injection / low confidence → review queue
├─ Write page ........ markdown + YAML frontmatter
└─ ONE git commit per batch
search("alice seating", format="context")
│
├─ L0 standing context .. user profile + pinned pages
├─ L1 BM25 FTS5 ......... pages, chunks, claims, raw
├─ L2 vectors ........... model2vec + sqlite-vec [optional]
├─ RRF fusion ............ rank-only, no score calibration
├─ Provenance weight ..... user_stated > tool_derived > agent_inferred
├─ Decay adjustment ...... per-type confidence half-life
└─ Token-budgeted pack ... active claims only, every block cited
A user's entire footprint lives under exactly two prefixes — wiki/u/<id>/ and raw/u/<id>/ — which is what makes path-scoped erasure provable.
Use any LLM
Memory extraction runs on any LiteLLM-supported provider. Retrieval, the ledger and storage are unchanged — only the compile step swaps.
pip install "markmem[litellm]"
MARKMEM_LLM_PROVIDER=litellm
MARKMEM_LLM_COMPILE_MODEL=groq/llama-3.1-8b-instant
GROQ_API_KEY=gsk_...
See the examples/ directory for OpenAI, Anthropic, LiteLLM, async, and FastAPI examples.
API
| Method | Notes |
|---|---|
add(messages, user_id, agent_id, run_id, metadata) |
PII-gated, enqueued; compiles off the hot path |
flush() |
Force synchronous compilation (tests, turn boundaries) |
search(query, user_id, top_k, as_of, format="context") |
Tiered L0→L1→L2; format="context" returns a packed prompt string |
get(id) / get_all(user_id, type) |
Full page dicts including the claim ledger |
update(id, text) |
Human correction → human_edited claim at full trust |
delete(id, hard=False) |
Soft archive, or hard delete |
forget(user_id, mode="scrub"|"rewrite") |
Compliance erasure + tombstone |
history(id, include_diff=True) |
Literally git log --follow on the page |
maintenance() |
Decay, consolidation, retention sweeps |
lint() |
Broken links, unsourced claims, injection, ledger/prose drift |
Note: AsyncMemory mirrors the whole surface with await.
Integrations
MCP Server (Claude Code / Desktop) — pip install "markmem[mcp]":
{
"mcpServers": {
"markmem": {
"command": "python",
"args": ["-m", "markmem.mcp_server"],
"env": { "MARKMEM_REPO": "./my-memory" }
}
}
}
Exposes wiki_search, wiki_read, wiki_list, wiki_ingest, wiki_supersede, wiki_history, wiki_review.
REST API — pip install "markmem[api]" then run markmem api --port 8000.
CLI — Run markmem --help for 19 powerful memory management commands.
Compliance & Erasure
Every erasure writes a tombstone to .markmem/ops.jsonl and commits to git.
| Mode | What it does | Trade-off |
|---|---|---|
forget(user, "scrub") |
Deletes the user's two path prefixes, commits, tombstones | Content remains in git history — audit-friendly |
forget(user, "rewrite") |
Also purges all history via git-filter-repo |
Provable; invalidates existing clones |
crypto-shred |
Deletes the per-user AES-256-GCM key | Instant, works even against backups; requires encryption enabled up front |
Portability
markmem export --to jsonl --out memory.jsonl # lossless round-trip
markmem export --to mem0 --out mem0.json # migrate to mem0
markmem export --to memory-md --out ./MEMORY/ # Claude Code format
markmem import --from mem0 mem0-export.json # migrate from mem0
Benchmarks
MarkMem ships MarkMemBench, a hand-authored dataset where evidence is labeled for true R@1 / R@5 metrics. We also evaluate on industry-standard massive-scale datasets like LoCoMo.
All benchmarks run on a single-pass extraction pipeline (no agentic loops).
| Benchmark | MarkMem | Mem0 (April 2026) |
|---|---|---|
| LoCoMo (R@5) | 93.5 | 92.5 |
| MarkMemBench (R@5) | 100.0 | — |
| Retrieval Latency (p50) | 5.0 ms | 880 ms |
Note: A frontier model (GPT-5.4-mini or Claude 3.5 Sonnet) achieves perfect recall (100.0) on extraction. Smaller 8B models drop facts and break supersession.
Security & Edge Cases
MarkMem goes beyond standard retrieval benchmarks to explicitly test security, compliance, and edge cases that vector databases struggle with.
| Metric | MarkMem |
|---|---|
| Multi-User Isolation (cross-contamination) | 100% isolated (0 leaks) |
| Temporal Reasoning (supersession accuracy) | 100.0% |
| GDPR Erasure (crypto-shred + tombstone) | 223 ms |
| Context Packing Latency (p50) | 1.7 ms |
Limitations
- ~50–100K pages per repo. Many small files is git's and NTFS's worst case.
- Read-your-writes is eventual for compiled pages. Raw text is searchable immediately;
flush()forces compilation. - FTS5 stemming is English-biased. Multilingual needs the vector extra.
Development
git clone <repo> && cd markmem
pip install -e ".[all,dev]"
python -m pytest tests/ -q
License
Apache-2.0
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file markmem-0.4.0.tar.gz.
File metadata
- Download URL: markmem-0.4.0.tar.gz
- Upload date:
- Size: 113.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e044cc48fa302724e10a467b4e2a89590f520706d474b1141cab556b905a2ebf
|
|
| MD5 |
ced2a247ff472d690dbce284824f3e23
|
|
| BLAKE2b-256 |
79b81ff4d6a69047c082713ff94baf10d0c975ea2edd418d14ad1535b345f657
|
File details
Details for the file markmem-0.4.0-py3-none-any.whl.
File metadata
- Download URL: markmem-0.4.0-py3-none-any.whl
- Upload date:
- Size: 111.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
76c2b792e233a748964f61ba65eab81e00077049a63350f52397bb2d75b9381d
|
|
| MD5 |
2321db465c24530ad164125dd009c89a
|
|
| BLAKE2b-256 |
47cd37abb1cdc4be633c25ce5395022953ab1d2c7ca6f89fd59a64fbb2b3a269
|