Cross-client AI memory hub: agents share one SQLite memory.db via file-level pointers.
Your agent remembers things. Who audits what it remembers?
MemTether is a local-first memory hub for multi-client AI agents. While most memory systems compete on retrieval accuracy, MemTether competes on governance: who wrote each fact, when it took effect, what it superseded, which conflicts a human adjudicated, and a tamper-evident hash chain anyone can verify — no code, no dependencies. Retrieval is provided (SGM deterministic SQL routing + hybrid embedding), but it is not the headline: agent memory that you can audit, correct, and trust is.
Coming from mem0, Zep, or Letta? examples/mem0_migration.py
shows a complete round-trip migration from a mem0 JSON export — no mem0
SDK required.
$ memtether court fact-20261007-abc
+============================================================+
| MEMTETHER MEMORY COURT - CASE FILE |
| 1. CONTENT Clash proxy port is 7897 |
| 2. TEMPORAL valid: 10-05 → present | known: 10-05 → now |
| 3. PROVENANCE #1 remember by=codex → #2 correct by=user |
| 4. CONFLICTS case #3: vs fact-...old verdict=superseded |
| 5. INTEGRITY chain: PASS (3 anchors, 42 entries hashed) |
+============================================================+
python examples/audit_chain_demo.py to see it turn red.Run it yourself:
$ python examples/audit_chain_demo.py
写入 25 条记忆(自动生成 2 个审计锚点)...
篡改前 verify_chain: PASS {'anchors': 2, 'entries_covered': 20}
模拟攻击者直接改库...
篡改后 verify_chain: FAIL {'reason': 'chain hash mismatch'}
✅ 哈希链成功检测到篡改!
> Note: ntries_covered: 20 with 25 writes is expected — the hash chain anchors every 10 audit entries, so the last 5 writes sit in the unanchored tail until the next batch. Tampering with an *anchored* entry is what turns verification red.
Already using mem0? examples/mem0_migration.py
shows a complete round-trip: mem0 JSON export → MemTether Exchange v1 →
live retrieval → back to mem0 format. No mem0 SDK required, bi-temporal
fields honestly marked temporal_source="backfilled".
| Operation | p50 | p95 | p99 |
|---|---|---|---|
| remember (insert) | 28.7ms | 34.6ms | 117.8ms |
| search (SGM entity) | 33.1ms | 39.5ms | 41.6ms |
| search (keyword) | 32.2ms | 35.0ms | 135.0ms |
| correct (supersede) | 50.8ms | 54.7ms | 54.7ms |
Reproduce: python _dev/benchmarks/bench_latency.py --n 200
Under the hood: supersession chains (corrections never delete), bi-temporal timestamps (when facts were true vs when the system learned them), human-adjudicated conflict resolution, and a hash-chained audit log designed with EU AI Act Article 12 record-keeping requirements in mind (not certified compliance) record-keeping requirements.
One physical SQLite database, shared by every AI client via file-level pointers. No cloud. No API fees. No sync daemon. Greppable, git-able, yours — and auditable.
Compared to mem0 (66.6K★), Zep/Graphiti (31.5K★), and agentmemory (29.2K★): those systems either overwrite or delete old values. MemTether's supersession chain preserves the full history with source attribution and Q-Value ranking. EAF retrieval: 75.7% strict on LongMemEval 500Q (paired delta +19.4pp, McNemar p=7.8e-7).
| MemTether | memora (731★) | memtrace (486★) | icarus (290★) | mem0 (66K★) | |
|---|---|---|---|---|---|
| Supersession chains (corrections don't delete) | ✅ enforced | ❌ | ❌ | ✅ | ❌ overwrite |
| Evidence chain (tamper-evident, browser-verifiable) | ✅ court CLI + zip | ❌ | ❌ | ❌ | ❌ |
| Human conflict adjudication (decisions on record) | ✅ conflicts CLI | ❌ | ❌ | ❌ | ❌ |
| Bi-temporal (valid_from ≠ recorded_at) | ✅ 100% coverage on fact rows | ❌ | ✅ on knowledge-graph edges (not per-fact rows) | ❌ | ❌ |
| Source attribution (who wrote it, enforced) | ✅ registry + reject | ❌ | ❌ | ✅ provenance | ❌ |
| Bi-temporal (per-fact rows) | ✅ | ❌ | ❌ | ❌ | ✅ graph edges only |
| Conflict detection (rule-based + human review) | ✅ candidate generator | ❌ | ❌ | ❌ | ❌ |
| MCP server | ✅ | ✅ | ✅ | ❌ | ✅ |
| 23+ client adapters | ✅ auto-detect | ❌ | ❌ | ❌ | ❌ |
| Evaluation integrity framework | ✅ 5 patterns | ❌ | ❌ | ❌ | ❌ |
| CI: 9 jobs / 538 tests | ✅ | ? | ? | ? | ✅ |
| Language | Python | ? | Rust | ? | Python |
'Each cell reflects the feature's presence in the project's public documentation as of 2026-10-07. MemTether's differentiator is not any single feature — it's the combination of all governance dimensions in one local-first deployment.'
Artifact bundle with per-question records.
mcp-name: io.github.lanbass869-cell/memtether
Project page · Install · Docs · Reproduce · 中文文档
pip install memtether -i https://pypi.org/simple/
memtether init # creates DB + connects all detected AI clients
That's it. MemTether detects Claude Code, Cursor, Windsurf, Codex, Gemini CLI and 18 more clients on your machine, writes MCP config, and verifies.
China users: if
pip install memtetherfails withNo matching distribution, the Tsinghua mirror may lag behind PyPI. Use:pip install memtether -i https://pypi.org/simple/
# One client at a time
memtether setup claude-code
memtether setup cursor
memtether setup gemini-cli # run `memtether setup list` for all 23
# With semantic search (local embedding, no cloud):
pip install "memtether[vector]" # 1. deps (chromadb, onnxruntime)
memtether download-models # 2. weights (bge-m3-int8 ~560MB, or --profile bge-small-zh ~46MB)
python -m memsearch --rebuild # 3. build the vector index
# Skip any of these and search gracefully degrades to keyword + BM25.
# With REST API server + web dashboard
pip install "memtether[server]"
memtether dashboard
# Docker
docker-compose up
> **Security note**: the REST API is unauthenticated unless you set MEMTETHER_API_KEY. Only expose port 8080 to trusted networks — on a shared machine, set the key in .env before docker-compose up.
> **`memtether init` caveat**: auto-detection works for clients in standard install paths. Clients in custom locations may be missed or falsely reported — use `memtether connect verify` to confirm, and see docs/ADAPTERS.md for manual MCP config.
# Monday: Claude Code writes
$ memtether remember "Deploy to port 8080" --source claude-code
# Wednesday: you correct it via Cursor
$ memtether correct fact-xxx "Deploy to port 9090" --reason "port changed"
# Friday: another agent searches
$ memtether search "deploy port" --list
1. [fact] Deploy to port 9090 (active) ← current truth
Old "port 8080" is superseded, not deleted.
Full chain: memtether timeline fact-xxx
Every memory has valid_from / valid_to (business time) + recorded_at / invalidated_at (system time). You can query "what did the system know on Tuesday?"
| MemTether | engram | mem0 | agent-memory | |
|---|---|---|---|---|
| Storage | SQLite via file pointers | SQLite (Go binary) | Cloud API | Markdown files |
| Supersession | ✅ bi-temporal, never delete | ❌ | ⚠️ partial | ✅ |
| Source attribution | ✅ every fact tagged | ❌ | ❌ | ❌ |
| Q-Value feedback | ✅ used memories rank higher | ❌ | ❌ | ❌ |
| Poisoning defense | ✅ OWASP LLM01/02/06 | ❌ | ⚠️ faithfulness check | ❌ |
| Cross-client | ✅ file-level pointers (23 adapters) | ✅ MCP | ✅ API | ✅ CLI |
| Cloud required | ❌ | optional | ✅ | ❌ |
| Feature | MemTether | cognee | zep | letta | Engram* |
|---|---|---|---|---|---|
| Local-first | ✅ | ❌ | ❌ | ⚠️ self-hosted | ✅ |
| Zero config | ✅ | ❌ (Neo4j) | ❌ (Docker) | ⚠️ | ✅ |
| Single file DB | ✅ | ❌ | ❌ | ❌ | ✅ |
| REST API | ✅ (12 endpoints) | ✅ | ✅ | ✅ | ❌ |
| MCP server | ✅ | ❌ | ✅ | ✅ | ❌ |
| Web dashboard | ✅ | ❌ | ✅ | ✅ | ❌ |
| Supersession chain | ✅ | ❌ | ❌ | ⚠️ | ❌ |
| Bi-temporal | ✅ | ❌ | ❌ | ❌ | ✅ |
| Source attribution | ✅ | ❌ | ⚠️ | ❌ | ❌ |
| Q-Value ranking | ✅ | ❌ | ❌ | ❌ | ❌ |
| Poisoning defense | ✅ | ❌ | ❌ | ❌ | ❌ |
| Export as markdown | ✅ | ❌ | ❌ | ❌ | ✅ |
| 23 client adapters | ✅ | ❌ | ❌ | ❌ | ❌ |
| Governance layer | ✅ | ❌ | ⚠️ | ❌ | ❌ |
Claude Code ────┐ ┌──── Cursor
│ symlink / │
Codex ──────────┤ junction ├──── Windsurf
│ │
Gemini CLI ─────┤ ├─── WorkBuddy
└───────┬──────────┘
│
▼
┌──────────────────┐
│ memory.db │ ← One physical SQLite
│ (WAL mode) │
├──────────────────┤
│ FTS5 trigram │ ← BM25 full-text
│ ChromaDB + bge-m3│ ← Semantic (optional)
│ RRF fusion │ ← Multi-path merge
│ 4-factor rerank │ ← Z-score + sigmoid
│ Supersession │ ← Never delete
│ Bi-temporal │ ← T-axis + T'-axis
│ Q-Value │ ← Usage-based ranking
│ Hubguard │ ← Concurrent write lock
│ Poisoning guard │ ← OWASP LLM defense
└──────────────────┘
| Component | Technology | Purpose |
|---|---|---|
| Database | SQLite (WAL mode) | Single-file, zero-config, cross-platform |
| Full-text | FTS5 trigram + triggers | O(1) BM25 search, SQL-level sync |
| Vector | ChromaDB + bge-m3 (1024-dim) | Semantic search, local embedding |
| Fusion | Reciprocal Rank Fusion (K=60) | Merge multi-path results |
| Re-ranking | 4-factor (sem .45 + rec .25 + freq .05 + imp .10) | Z-score + sigmoid |
| Governance | Supersession + bi-temporal + conflict detection | Never delete |
| Concurrency | Hubguard (file lock + atomic write) | Cross-process safe |
| Security | memtether_guard (OWASP LLM01/02/06) | Poisoning defense |
| API | FastAPI REST (12 endpoints) + MCP server (4 tools) | Any language |
| Packaging | PyPI + Docker + 23 client adapters | pip install memtether |
# All detected clients (recommended)
memtether init
# One at a time
memtether setup claude-code
memtether setup cursor
memtether setup windsurf
memtether setup codex
Supported (23): Claude Code, Claude Desktop, Cursor, Windsurf, VS Code, Zed, JetBrains, Cline, Roo Code, Kilo Code, Continue, Cody, Amazon Q, Gemini CLI, Neovim, Codex CLI, WorkBuddy (CN + Intl), CodeBuddy, ZCode, DSH, OpenClaw, Agents-Neutral
memtether remember "User prefers dark theme" --source claude-code
memtether search "theme" --list # L0: one-line + uid
memtether search "theme" # Full content
memtether correct <uid> "Updated" # Supersede, never delete
memtether timeline <uid> # Audit chain
memtether stats
memtether export-md --out ./backup # Export as markdown
memtether dashboard # Web UI
| Metric | Score | Notes |
|---|---|---|
| Strict match (global) | 62.6% | 209/334 applicable |
| LLM judge (global) | 55.7% | 264/474 |
| Multi-session strict | 48.8% | 39/80 |
| Multi-session LLM judge | 60.0% | 72/120 |
| EAF | 75.7% | 253/334 — multi-session 32.5%→60.0% |
| Type | n | Strict | LLM Judge |
|---|---|---|---|
| knowledge-update | 78 | 76.6% | 62.5% |
| multi-session | 133 | 48.8% | 60.0% |
| single-session-assistant | 56 | 40.4% | 41.1% |
| single-session-preference | 30 | N/A | 43.3% |
| single-session-user | 70 | 86.4% | 85.7% |
| temporal-reasoning | 133 | 60.7% | 40.5% |
Results use our own harness. Not directly comparable with mem0's reported numbers.
| System | Token F1 (LoCoMo) |
|---|---|
| PropMem | 0.605 |
| OpenClaw | 0.557 |
| Full Context | 0.542 |
| MemTether | 0.523 |
| Hindsight | 0.489 |
| Graphiti | 0.416 |
| Memory-R1 | 0.389 |
| SimpleMem | 0.358 |
| Mem0 | 0.344 |
| MemU | 0.299 |
MemTether ranks 4/10 on token F1 — ahead of Graphiti, mem0, SimpleMem, MemU
and Hindsight, behind proposition-indexed PropMem and chunk-based OpenClaw.
Per-category: multi-hop 0.556, open-domain 0.820, factual 0.357, temporal 0.264,
inferential 0.206. Reproduce: see _dev/memeval/src/agents_memory/systems/memtether.py
(adapter) and scripts/run_full_benchmark.py --systems memtether.
| Test | Result |
|---|---|
| pytest | 538 passed, 4 skipped (CI runs full tests/ directory) |
| hard_bench | 62/62 |
| e2e_verify | 13/13 |
| refuse_bench | 26/26 (wordform gate; 09-25 calibration; known blind spot: same-form-different-attribute) |
| check_packaging | ✅ |
memtether_guard detects prompt injection, code execution, sensitive info (OWASP LLM01/02/06), 12 rulesshared / private / restrictedtether_connect detect may falsely report "not connected" for same-source-different-path configscordis.patch.yml) cannot be safely rewritten — use plan to previewchromadb, onnxruntime) — without them, degrades to keyword searchmemtether dashboard # starts server + opens browser
# or: uvicorn api_server:app --port 8820
12 endpoints: /health /remember /search /stats /correct /retire /list /timeline/{uid} /absorb /qvalue /dashboard
See CONTRIBUTING.md.
If MemTether helps you, please give it a ⭐ on GitHub — it helps other agents find it.
| Symptom | Fix |
|---|---|
no AI client detected after memtether init | Clients in non-standard paths need manual MCP config — see docs/ADAPTERS.md |
database is locked during writes | WAL mode is default; a long reader may hold the lock — retry after 5s (busy_timeout is set) |
source not registered on write | Open-source mode is fail-open; a registry file (agents.json) enforces attribution — add your client to agents.json or set MEM_SOURCE_FALLBACK |
embedding search failed warning | Optional chromadb/bge models missing — install pip install memtether[semantic] or ignore (keyword fallback works) |
| memory chain FAIL after manual edit | Intentional: the audit hash chain detects direct DB modification. Restore from backup or run memtether court <uid> to inspect |
See ROADMAP.md for planned work and explicit non-goals.
Source-derived launch command. Check the maintainer’s required arguments and credentials before running:
uvx memtetherMerge this template into ~/Library/Application Support/Claude/claude_desktop_config.json. Keep existing servers. Add any arguments, credentials, and permissions required by the maintainer; this template has not been install-tested.
{
"mcpServers": {
"io-github-lanbass869-cell-memtether": {
"command": "uvx",
"args": [
"memtether"
]
}
}
}Restart Claude Desktop completely for changes to take effect. Confirm the server appears connected in the client’s tool list, then try a read-only example from its documentation.
Claude Desktop setup referencememtetherpypiio.github.lanbass869-cell/memtether works with any MCP-compatible client. Copy the config snippet from the Configuration section above and add it to the file shown for your client, then restart the application.
~/Library/Application Support/Claude/claude_desktop_config.jsonRestart Claude Desktop completely for changes to take effect.~/.cursor/mcp.jsonRestart Cursor for changes to take effect..vscode/mcp.jsonReload VS Code window for changes to take effect.~/.codeium/windsurf/mcp_config.jsonRestart Windsurf for changes to take effect..mcp.jsonSave at the project root, then start Claude Code in that project and review the MCP server approval prompt. Keep real credentials out of shared files.