Project memory for coding agents. Single binary, cargo install mempal, find past decisions with citations in seconds.
Agent writes code → commits → mempal saves the decision context
Next session (any agent) → mempal search → finds the decision with source citation
- Hybrid search: BM25 keyword matching + vector semantic search, merged via Reciprocal Rank Fusion
- Knowledge graph: subject-predicate-object triples with temporal validity (valid_from/valid_to)
- Cross-project tunnels: automatic discovery when the same room appears in multiple wings
- Self-describing protocol: MEMORY_PROTOCOL embedded in MCP ServerInfo teaches any agent how to use mempal — no system prompt configuration required
- Multilingual: model2vec-rs (BGE-M3 distilled) as default embedder, zero native dependencies
- Single file: everything lives in
~/.mempal/palace.db(SQLite + sqlite-vec)
cargo install --path crates/mempal-cli --locked
mempal init ~/code/myapp
mempal ingest ~/code/myapp --wing myapp
mempal search "auth decision clerk"
mempal wake-upWith REST support:
cargo install --path crates/mempal-cli --locked --features restConfig at ~/.mempal/config.toml (optional, defaults work without it):
db_path = "~/.mempal/palace.db"
[embed]
backend = "model2vec" # default, zero native deps
# model = "minishlab/potion-multilingual-128M" # default multilingual model (1024d)Other backends:
# Local ONNX (requires --features onnx)
[embed]
backend = "onnx"
# External API
[embed]
backend = "api"
api_endpoint = "http://localhost:11434/api/embeddings"
api_model = "nomic-embed-text"| Command | Purpose |
|---|---|
mempal init <DIR> [--dry-run] |
Infer wing/rooms from project tree |
mempal ingest <DIR> --wing <W> [--dry-run] |
Chunk, embed, and store |
mempal search <QUERY> [--wing W] [--room R] [--json] |
Hybrid search (BM25 + vector + RRF) |
mempal wake-up [--format aaak] |
Context refresh, sorted by importance |
mempal compress <TEXT> |
AAAK format output |
mempal delete <DRAWER_ID> |
Soft-delete a drawer |
mempal purge [--before TIMESTAMP] |
Permanently remove soft-deleted drawers |
mempal kg add <S> <P> <O> |
Add a knowledge graph triple |
mempal kg query [--subject S] [--predicate P] |
Query triples |
mempal kg timeline <ENTITY> |
Chronological view of an entity |
mempal kg stats |
Knowledge graph statistics |
mempal tunnels |
Cross-wing room links |
mempal taxonomy list / edit |
Manage routing keywords |
mempal reindex |
Re-embed all drawers after model change |
mempal status |
DB stats, schema version, scopes |
mempal serve [--mcp] |
MCP server (+ REST with feature) |
mempal cowork-install-hooks [--global-codex] |
Install UserPromptSubmit hooks for Claude Code (+ optional Codex merge) |
mempal cowork-drain --target <claude|codex> |
Drain inbox messages (for hook use; exits 0 on any failure) |
mempal cowork-status --cwd <PATH> |
Read-only view of both inboxes at <PATH> |
mempal fact-check [PATH|-] [--wing W] [--room R] [--now <UNIX_SECS>] |
Offline contradiction check against KG triples + known entities |
mempal bench longmemeval <FILE> |
LongMemEval retrieval benchmark |
mempal serve --mcp exposes these tools via Model Context Protocol:
| Tool | Purpose |
|---|---|
mempal_status |
State + protocol + AAAK spec (teaches agent on first call) |
mempal_search |
Hybrid search with tunnel hints, citations, and AAAK-derived structured signals |
mempal_ingest |
Store memories with optional importance (0-5) and dry_run; reports lock_wait_ms when concurrent ingest was observed |
mempal_delete |
Soft-delete with audit trail |
mempal_taxonomy |
List or edit routing keywords |
mempal_kg |
Knowledge graph: add/query/invalidate/timeline/stats |
mempal_tunnels |
Cross-wing room discovery |
mempal_peek_partner |
Read partner agent's live session (Claude ↔ Codex), pure read, never writes |
mempal_cowork_push |
Send a short handoff message to partner agent's inbox (at-next-submit delivery) |
mempal_fact_check |
Offline contradiction detection vs KG triples + known entities (similar-name, relation mismatch, stale facts) |
The server embeds MEMORY_PROTOCOL (11 behavioral rules) in the MCP initialize.instructions field. Any MCP client learns the workflow automatically.
mempal teaches agents these rules through self-description:
- FIRST-TIME SETUP — call
mempal_statusto discover wings before filtering - WAKE UP — different clients have different pre-load mechanisms
- VERIFY BEFORE ASSERTING — search before stating project facts
- QUERY WHEN UNCERTAIN — search on "why did we...", "last time we..." 3a. TRANSLATE TO ENGLISH — translate non-English queries before searching
- SAVE AFTER DECISIONS — persist rationale, not just outcomes
- CITE EVERYTHING — reference drawer_id and source_file 5a. KEEP A DIARY — record behavioral observations in wing="agent-diary"
- PARTNER AWARENESS — use
mempal_peek_partnerfor live partner-agent session, not crystallized drawers - DECISION CAPTURE —
mempal_ingestis for firm decisions only; include partner input when peek informed the call - COWORK PUSH — use
mempal_cowork_pushas the SEND primitive in the SEND/READ/PERSIST triad; at-next-submit delivery, not real-time - VERIFY BEFORE INGEST — call
mempal_fact_checkbefore persisting a decision that asserts entity relationships; it catches similar-name typos, relation mismatches against the KG, and stale facts with expiredvalid_to
Two coding agents (Claude Code and Codex) can collaborate on the same repo through a per-project inbox + hook-driven injection channel, on top of mempal_peek_partner (read live partner session) and mempal_cowork_push (send ephemeral handoff).
Install hooks once per repo (run at the repo root):
mempal cowork-install-hooks --global-codexThis writes:
.claude/hooks/user-prompt-submit.sh+ merges a registration entry into.claude/settings.jsonso Claude Code fires the hook on every user prompt.~/.codex/hooks.jsonUserPromptSubmit entry so Codex fires the same drain on every user prompt.
The --global-codex part is optional. The re-run is idempotent and self-heals stale/wrong drain entries — re-installing after a mempal upgrade is always safe.
Delivery is at-next-UserPromptSubmit, not real-time: a push from Claude to Codex becomes visible only when the Codex user submits their next prompt, at which point the hook drains the inbox and prepends the message as additionalContext on that turn.
Check inbox state at any time without draining:
mempal cowork-status --cwd "$PWD"- Codex feature flag dependency: Codex's hooks runtime is gated behind the
codex_hooksfeature flag (currently "under development" in shippedcodex-cli). If the flag is off, Codex silently ignores~/.codex/hooks.json.install-hooksdetects this and prints a warning with the activation command:codex features enable codex_hooks. - Two Claude-side artifacts: Claude Code does not auto-discover hook scripts by filename. Both
.claude/hooks/user-prompt-submit.shand the matching entry in.claude/settings.jsonare required.install-hookswrites both; do not remove either by hand. - TUI restart needed after config changes on the Codex side: Codex reads
config.toml+hooks.jsonat process startup only. After enabling the feature flag or runninginstall-hooks, fully quit and relaunch the Codex TUI before expecting hooks to fire. - MCP server re-spawn: Claude Code spawns the mempal MCP server at client startup. After upgrading the mempal binary (
cargo install ...), restart Claude Code so the MCP server respawns and exposes newly added tools likemempal_cowork_pushormempal_fact_check. - Bidirectional scope:
mempal_cowork_pushcurrently requires an MCP client identifying itself asclaude-codeorcodex(or their aliases). Generic MCP clients cannot push because caller identity is required to fill thefromfield and enforce self-push rejection. This is by design for the Claude ↔ Codex pair.
Two agents writing to the same source simultaneously used to be a TOCTOU race: both would pass the dedup check, both would insert, producing duplicate drawers or mismatched vectors. Since 0.4.0, mempal_ingest and ingest_file_with_options acquire a per-source advisory lock before entering the dedup + insert critical section.
- Lock files live at
~/.mempal/locks/<16-hex>.lock, created lazily, released on guard drop. - 5 s timeout, 50 ms retry + jitter;
LockError::Timeoutsurfaces as aningesterror. - Every non-dry-run response carries
lock_wait_ms: Option<u64>so agents can detect contention. - Dry-run does not acquire the lock (no writes, no race).
- Unix only in 0.4.0. On Windows the lock path is a no-op fallback;
LockFileExsupport is tracked for a follow-up.
mempal_fact_check — and its CLI counterpart mempal fact-check — compare a text blob against the existing KG triples + the entity registry derived from recent drawers. It flags three issue classes, all deterministic and zero-LLM:
| Issue | Trigger |
|---|---|
SimilarNameConflict |
Text mentions a name within Levenshtein distance ≤ 2 of a known entity, and the names are not equal. |
RelationContradiction |
Text asserts a predicate (e.g. brother_of) that's in the incompatibility dictionary against an existing KG triple with the same (subject, object) endpoints. |
StaleFact |
Text asserts a triple whose KG row has valid_to < now (Unix seconds). |
Extracted triples today cover three narrow patterns: "X is Y's ROLE", "X works at / for Y", and "X is [the|a|an] ROLE of Y". Unknown sentence shapes are silently ignored, so the tool errs toward under-reporting rather than false positives.
Protocol Rule 11 guides agents to run this before ingesting a decision that asserts entity relationships. See specs/p9-fact-checker.spec.md for the full contract.
query → BM25 (FTS5) → ranked by keyword match
→ Vector (sqlite-vec) → ranked by semantic similarity
→ RRF Fusion (k=60) → merged ranking
→ Wing/Room filter → scoped results
→ Tunnel hints → cross-project references
mempal kg add "Kai" "recommends" "Clerk"
mempal kg add "Clerk" "replaced" "Auth0" --source-drawer drawer_xxx
mempal kg timeline "Kai"
mempal kg statsTriples support temporal validity — relationships can be invalidated when they expire.
Cross-session behavioral learning — agents record observations, lessons, and patterns:
# Search diary entries
mempal search "lesson" --wing agent-diary
mempal search "pattern" --wing agent-diary --room claudeDiary entries use the existing mempal_ingest tool with wing="agent-diary" and room=agent-name. MEMORY_PROTOCOL Rule 5a teaches agents to write diary entries. Integrates with Claude Code's auto-dream for automatic memory consolidation.
| Format | Auto-detected by |
|---|---|
| Claude Code JSONL | type + message fields |
| ChatGPT JSON | Array or mapping tree |
| Codex CLI JSONL | session_meta + event_msg entries |
| Slack DM JSON | type: "message" + user + text |
| Plain text | Fallback |
Output-only format readable by any LLM without decoding:
mempal compress "Kai recommended Clerk over Auth0 based on pricing and DX"
# V1|manual|compress|1744156800|cli
# 0:KAI+CLK+AUT|kai_clerk_auth0|"Kai recommended Clerk over Auth0..."|★★★★|determ|DECISIONChinese text uses jieba-rs POS tagging for proper word segmentation.
| Crate | Responsibility |
|---|---|
mempal-core |
Types, SQLite schema v4, taxonomy, triples |
mempal-embed |
Embedder trait (model2vec default, ort optional) |
mempal-ingest |
Format detection, normalization, chunking (5 formats) |
mempal-search |
Hybrid search (BM25 + vector + RRF), routing, tunnels |
mempal-aaak |
AAAK encode/decode with BNF grammar + roundtrip tests |
mempal-mcp |
MCP server (9 tools) |
mempal-api |
Feature-gated REST API |
mempal-cli |
CLI entrypoint |
Key design choices:
- model2vec-rs default embedder — zero native deps, multilingual (BGE-M3 distilled)
- ort (ONNX) available behind
onnxfeature flag for max quality - FTS5 for BM25 keyword search — synced via SQLite triggers
- Soft-delete with audit trail —
mempal delete+mempal purge - Importance ranking — drawers have 0-5 importance, wake-up sorts by importance
- Semantic dedup — ingest warns (doesn't block) when similar content exists
cargo test --workspace
cargo test --workspace --all-features
cargo clippy --workspace --all-targets --all-features -- -D warnings
cargo fmt --all --checkAfter changing the embedding model, re-embed existing drawers:
mempal reindex- Design:
docs/specs/2026-04-08-mempal-design.md - Usage guide:
docs/usage.md - AAAK dialect:
docs/aaak-dialect.md - Specs (internal agent-spec contracts, on GitHub): https://github.com/ZhangHanDong/mempal/tree/main/specs
- Plans (internal implementation plans, on GitHub): https://github.com/ZhangHanDong/mempal/tree/main/docs/plans
- Benchmark:
benchmarks/longmemeval_s_summary.md— includes the older 384d baseline and the newer model2vec 256d run
mempal 的设计分析和完整技术叙事,收录在《MemPalace: AI 记忆的第一性原理》Part 10(第 26-30 章):
| 章节 | 内容 |
|---|---|
| 第 26 章 | 为什么用 Rust 重铸 — 触发点、重写判断、语言选择 |
| 第 27 章 | 保留了什么、改变了什么 — 5 维度对比 + 架构图 |
| 第 28 章 | 自描述协议 — MEMORY_PROTOCOL、7 条规则、agent 生命周期 |
| 第 29 章 | 多 Agent 协作 — Claude↔Codex 接力、反模式发现、agent 日记 |
| 第 30 章 | 诚实的差距 — benchmark 数据、6 个 gap |