mempal 0.6.2

Project memory for coding agents. Single binary, hybrid search, knowledge graph.
Documentation
# mempal

Coding agent 的项目记忆工具。单二进制,`cargo install mempal`,10 秒内带出处找回历史决策。

## 做什么

```
Agent 写代码 → 提交 → mempal 保存决策上下文
下一个 session(任何 agent)→ mempal search → 带出处找回决策
```

- **混合检索**:BM25 关键词匹配 + 向量语义搜索,通过 RRF(Reciprocal Rank Fusion)融合
- **知识图谱**:subject-predicate-object 三元组,支持时态验证(valid_from/valid_to)
- **跨项目隧道**:自动发现多个 Wing 中同名 Room 的链接
- **自描述协议**:MEMORY_PROTOCOL 嵌入 MCP ServerInfo,任何 agent 连接后自动学会使用方式——无需系统提示配置
- **多语言**:model2vec-rs(BGE-M3 蒸馏)作为默认嵌入器,零原生依赖
- **单文件**:所有数据在 `~/.mempal/palace.db`(SQLite + sqlite-vec)

## 快速开始

```bash
cargo install --path crates/mempal-cli --locked

mempal init ~/code/myapp
mempal ingest ~/code/myapp --wing myapp
mempal search "auth decision clerk"
mempal wake-up
```

启用 REST 支持:

```bash
cargo install --path crates/mempal-cli --locked --features rest
```

## 配置

配置文件 `~/.mempal/config.toml`(可选,不存在时使用默认值):

```toml
db_path = "~/.mempal/palace.db"

[embed]
backend = "model2vec"                          # 默认,零原生依赖
# model = "minishlab/potion-multilingual-128M" # 默认多语言模型
```

其他后端:

```toml
# 本地 ONNX(需要 --features onnx)
[embed]
backend = "onnx"

# 外部 API
[embed]
backend = "api"
api_endpoint = "http://localhost:11434/api/embeddings"
api_model = "nomic-embed-text"
```

## 命令一览

| 命令 | 用途 |
|------|------|
| `mempal init <DIR> [--dry-run]` | 从项目目录推断 wing/room |
| `mempal ingest <DIR> --wing <W> [--dry-run]` | 分块、嵌入、存储 |
| `mempal search <QUERY> [--wing W] [--room R] [--json]` | 混合检索(BM25 + 向量 + RRF) |
| `mempal wake-up [--format aaak]` | 上下文刷新,按重要性排序 |
| `mempal compress <TEXT>` | AAAK 格式输出 |
| `mempal delete <DRAWER_ID>` | 软删除 |
| `mempal purge [--before TIMESTAMP]` | 永久清除已软删除的记忆 |
| `mempal kg add <S> <P> <O>` | 添加知识图谱三元组 |
| `mempal kg query [--subject S] [--predicate P]` | 查询三元组 |
| `mempal kg timeline <ENTITY>` | 实体的时间线视图 |
| `mempal kg stats` | 知识图谱统计 |
| `mempal tunnels` | 跨 Wing room 链接 |
| `mempal taxonomy list / edit` | 管理路由关键词 |
| `mempal reindex` | 切换模型后重新嵌入所有 drawer |
| `mempal status` | 数据库统计、schema 版本、scope 分布 |
| `mempal serve [--mcp]` | MCP 服务器(+ REST) |
| `mempal cowork-install-hooks [--global-codex]` | 一键安装 Claude Code + Codex 的 UserPromptSubmit hook |
| `mempal cowork-drain --target <claude\|codex>` | 排空 inbox(供 hook 调用,任意错误均 exit 0) |
| `mempal cowork-status --cwd <PATH>` | 只读查看双方 inbox 当前状态 |
| `mempal fact-check [PATH\|-] [--wing W] [--room R] [--now <UNIX_SECS>]` | 离线矛盾检查(对照 KG 三元组 + 已知 entity) |
| `mempal bench longmemeval <FILE>` | LongMemEval 检索 benchmark |

## MCP 服务器(10 个工具)

`mempal serve --mcp` 通过 Model Context Protocol 暴露:

| 工具 | 用途 |
|------|------|
| `mempal_status` | 状态 + 协议 + AAAK spec(首次调用即教会 agent) |
| `mempal_search` | 混合检索 + tunnel 提示 + 引用 + P7 的 AAAK 结构化 signals |
| `mempal_ingest` | 存记忆(可选 importance 0-5 + dry_run);并发写入时返回 `lock_wait_ms` |
| `mempal_delete` | 软删除 + 审计 |
| `mempal_taxonomy` | 路由关键词管理 |
| `mempal_kg` | 知识图谱:add/query/invalidate/timeline/stats |
| `mempal_tunnels` | 跨 Wing room 发现 |
| `mempal_peek_partner` | 读 partner agent 当前 session(Claude ↔ Codex),纯只读 |
| `mempal_cowork_push` | 向 partner agent inbox 投递短消息(at-next-submit 交付) |
| `mempal_fact_check` | 离线矛盾检测(相似名 / 关系对立 / 时态失效,纯本地无 LLM) |

服务器在 MCP `initialize.instructions` 中嵌入 MEMORY_PROTOCOL(11 条行为规则),任何 MCP 客户端自动接收。

## 记忆协议

mempal 通过自描述教 agent 这些规则:

0. **首次设置** — 调用 `mempal_status` 发现 wing 名称
1. **唤醒** — 不同客户端有不同的预加载机制
2. **断言前验证** — 陈述项目事实前先搜索
3. **不确定时查询** — "我们为什么..."、"上次我们..."
3a. **翻译为英文** — 非英文查询先翻译再搜索
4. **决策后保存** — 保存理由,不仅是结果
5. **引用一切** — 引用 drawer_id 和 source_file
5a. **记日记** — session 结束时在 `wing="agent-diary"` 下记行为观察
8. **Partner 感知** — 问 partner 当前状态用 `mempal_peek_partner`(live session),问已沉淀决策才用 `mempal_search`
9. **决策沉淀**`mempal_ingest` 只存已达成的硬决策;partner 参与时要把 partner 的关键贡献带进 drawer 正文
10. **COWORK PUSH**`mempal_cowork_push` 是 SEND 原语,at-next-submit 交付、非实时;别用它做该 ingest 的事
11. **入库前校验** — 在 ingest 含 entity 关系断言的决策前调 `mempal_fact_check`,它抓相似名拼错、KG 关系矛盾、以及 `valid_to` 已过期的 stale fact

## 并发 Ingest 安全(P9-B)

两个 agent 同时向同一个 source 写入以前是 TOCTOU race:两边都通过 dedup 检查、都 insert,结果重复 drawer 或 vector 错配。从 0.4.0 起 `mempal_ingest` 和 `ingest_file_with_options` 在进入 dedup + insert 临界区前获取 per-source 建议锁。

- 锁文件 `~/.mempal/locks/<16-hex>.lock`,懒建,guard drop 时 OS 自动释放
- 默认 5s 超时,50ms 重试 + jitter;超时返回 `LockError::Timeout`
- 非 dry-run 的 ingest response 携带 `lock_wait_ms: Option<u64>`,agent 可据此察觉并发
- dry-run 不占锁(零写入,零 race)
- 0.4.0 仅覆盖 Unix(`flock` 内联 extern,不引 libc crate);Windows 暂为 no-op 占位,后续用 `LockFileEx` 补齐

## 离线事实核查(P9-A)

`mempal_fact_check`(以及 CLI `mempal fact-check`)对一段文本在现有 KG `triples` + 最近 drawer 聚合的 entity registry 上做比对,标记三类确定性问题(不调 LLM、不走网络):

| 问题类型 | 触发条件 |
|----------|---------|
| `SimilarNameConflict` | 文本中的名字与已知 entity Levenshtein 距离 ≤ 2 且不相等 |
| `RelationContradiction` | 文本断言的 predicate 与 KG 中同 `(subject, object)` 的现存 triple 在不兼容字典中 |
| `StaleFact` | 文本断言的三元组在 KG 中 `valid_to < now`(Unix 秒) |

文本 → 三元组当前支持三种窄模式:"X is Y's ROLE"、"X works at / for Y"、"X is [the|a|an] ROLE of Y"。不认得的句型静默返回空,倾向少报不多报。协议 Rule 11 指导 agent 在 ingest 含实体关系断言的决策前跑一次。完整契约见 `specs/p9-fact-checker.spec.md`。

## 检索架构

```
query → BM25 (FTS5)         → 关键词排序
      → Vector (sqlite-vec) → 语义相似度排序
      → RRF 融合 (k=60)     → 合并排序
      → Wing/Room 过滤      → 范围限定
      → Tunnel 提示         → 跨项目引用
```

## 知识图谱

```bash
mempal kg add "Kai" "recommends" "Clerk"
mempal kg add "Clerk" "replaced" "Auth0" --source-drawer drawer_xxx
mempal kg timeline "Kai"
mempal kg stats
```

三元组支持时态验证——关系过期后可标记为无效。

## Agent 日记

跨 session 行为学习——agent 记录观察、教训和模式:

```bash
# 搜索日记
mempal search "lesson" --wing agent-diary
mempal search "pattern" --wing agent-diary --room claude
```

日记通过现有的 `mempal_ingest` 工具写入,`wing="agent-diary"`,`room=agent 名字`。MEMORY_PROTOCOL Rule 5a 教 agent 在 session 结束时写日记。可与 Claude Code 的 auto-dream 集成,实现自动记忆整理。

## 导入格式(5 种)

| 格式 | 自动检测方式 |
|------|------------|
| Claude Code JSONL | `type` + `message` 字段 |
| ChatGPT JSON | 数组或 `mapping`|
| Codex CLI JSONL | `session_meta` + `event_msg` 条目 |
| Slack DM JSON | `type: "message"` + `user` + `text` |
| 纯文本 | 兜底 |

## AAAK 压缩

输出格式化器,任何 LLM 无需解码即可阅读:

```bash
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|DECISION
```

中文文本使用 jieba-rs 词性标注进行分词。

## 架构

| Crate | 职责 |
|-------|------|
| `mempal-core` | 类型、SQLite schema v4、taxonomy、triples |
| `mempal-embed` | Embedder trait(model2vec 默认,ort 可选) |
| `mempal-ingest` | 格式检测、归一化、分块(5 种格式) |
| `mempal-search` | 混合检索(BM25 + 向量 + RRF)、路由、tunnel |
| `mempal-aaak` | AAAK 编解码(BNF 语法 + 往返验证) |
| `mempal-mcp` | MCP 服务器(7 工具) |
| `mempal-api` | REST API(feature-gated) |
| `mempal-cli` | CLI 入口 |

关键设计:
- **model2vec-rs** 默认嵌入——零原生依赖,多语言(BGE-M3 蒸馏)
- **ort (ONNX)** 通过 `onnx` feature flag 可选启用
- **FTS5** BM25 关键词搜索——通过 SQLite 触发器同步
- **软删除** + 审计日志——`mempal delete` + `mempal purge`
- **重要性排序**——drawer 有 0-5 重要性评分,wake-up 按重要性排序
- **语义去重**——ingest 时检测相似内容,warning 但不阻塞

## 开发

```bash
cargo test --workspace
cargo test --workspace --all-features
cargo clippy --workspace --all-targets --all-features -- -D warnings
cargo fmt --all --check
```

切换嵌入模型后重建向量:

```bash
mempal reindex
```

## 文档

- 设计文档:[`docs/specs/2026-04-08-mempal-design.md`]docs/specs/2026-04-08-mempal-design.md
- 使用指南:[`docs/usage.md`]docs/usage.md
- AAAK 方言:[`docs/aaak-dialect.md`]docs/aaak-dialect.md
- Spec 体系(仓库内部 agent-spec 合约,GitHub 查看):<https://github.com/ZhangHanDong/mempal/tree/main/specs>
- 实现计划(仓库内部实现计划,GitHub 查看):<https://github.com/ZhangHanDong/mempal/tree/main/docs/plans>
- Benchmark:[`benchmarks/longmemeval_s_summary.md`]benchmarks/longmemeval_s_summary.md