Skip to main content

MarkMem Logo

MarkMem

A memory layer for chatbots that stores memory as plain markdown in a git repo.

PyPI version License Python Versions

InstallationQuick StartKey FeaturesHow it WorksAPI

What is MarkMem?

Chatbots forget. They cannot remember anything past the current session. 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:

  1. 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_of queries) instead of just relying on score decay.
  2. 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.
  3. 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 APIpip 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 / Metric MarkMem (Full Run) Mem0 (April 2026) Letta / MemGPT Khoj
LoCoMo (R@5 evidence recall) 83.3% 92.5% 68.5% 83.2%
Search Latency (p50) 1.5 ms 880.0 ms

Security & Edge Cases

MarkMem goes beyond standard retrieval benchmarks to explicitly test security, compliance, and edge cases that vector databases struggle with.

Metric MarkMem Ideal
Multi-User Isolation (cross-contamination) 100% isolated (0 leaks) 100%
Temporal Reasoning (supersession accuracy) 100.0% 100%
GDPR Erasure (crypto-shred + tombstone) 230.5 ms < 1s
Context Packing Latency (p50) 2.0 ms < 10ms

Limitations

  1. ~50–100K pages per repo. Many small files is git's and NTFS's worst case.
  2. Read-your-writes is eventual for compiled pages. Raw text is searchable immediately; flush() forces compilation.
  3. 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

markmem-0.4.4.tar.gz (113.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

markmem-0.4.4-py3-none-any.whl (111.0 kB view details)

Uploaded Python 3

File details

Details for the file markmem-0.4.4.tar.gz.

File metadata

  • Download URL: markmem-0.4.4.tar.gz
  • Upload date:
  • Size: 113.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.7

File hashes

Hashes for markmem-0.4.4.tar.gz
Algorithm Hash digest
SHA256 c6c6604e8ef138a43f07fdd604f9550b97b166f3ca241ca33d6fd03435aa5e4f
MD5 bcdf4a9bf0ec22ee91004273baa18225
BLAKE2b-256 33ea5199e38996b1c90496d8c197b44e26ddf79e11e4607359269d9ae56c06f8

See more details on using hashes here.

File details

Details for the file markmem-0.4.4-py3-none-any.whl.

File metadata

  • Download URL: markmem-0.4.4-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

Hashes for markmem-0.4.4-py3-none-any.whl
Algorithm Hash digest
SHA256 dff1e0d01e606853d30e62b6f2c3224f2cd123e84d3f6928c787c91ecfa196c7
MD5 f490528e6f704aa1327d5e701e5c61bc
BLAKE2b-256 11ed2bd4b7e798d17835f57abdb262194011389f4c8e57db715d4546250ef68e

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page