KeepM V3
带准入控制、本地优先、无模型依赖的 AI 编码 Agent 长期记忆引擎。
为什么需要 KeepM?
长对话会让重要事实淹没在上下文中间;如果任由 Agent 把自主推断直接写成长期记忆,一次误判又可能持续污染未来会话。
KeepM 在“推理”与“保留”之间建立明确的准入边界:
- Markdown 是唯一真源。 记忆保留在本地,可迁移、可审查,也能用 Obsidian 或任意 Markdown 编辑器直接查看和修改。
- SQLite 是可重建的机器索引。 名称、aliases、tags、description 和正文通过加权 FTS5 渐进检索,WikiLink 提供正向关系与反向链接。
- 三层生命周期隔离污染。 已确认结论、Agent 推断候选和未完成任务状态走不同的准入路径。
- 服务端不隐藏模型。 当前 Agent 负责语义提炼;KeepM 负责 Schema、去重、checksum、短时凭证、内容限制和安全状态流转。
核心原则:Markdown 是唯一真源,SQLite 是可删除、可完整重建的派生索引。
总体架构与数据流
┌──────────────────────────────────────────────────────────────┐
│ Agent 宿主:Codex / Claude Code / 其他 MCP 客户端 │
│ 语义提炼 · 准入分类 · 冲突处理 │
└─────────────────────────────┬────────────────────────────────┘
│ MCP stdio
▼
┌──────────────────────────────────────────────────────────────┐
│ KeepM MCP Server │
│ 格式校验 · 槽位去重 · checksum · 冲突事务 · 生命周期 · 诊断 │
└──────────────────────┬──────────────────────┬────────────────┘
│ 权威写入 │ 派生路由
▼ ▼
┌──────────────────────────────┐ ┌────────────────────────────┐
│ 本地 Markdown │ │ 本地 SQLite │
│ 正式记忆 · Inbox · handoff │ │ FTS5 · aliases · links │
│ 唯一真源 │ │ 可删除、可完整重建 │
└──────────────────────┬───────┘ └────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────┐
│ Obsidian / 任意 Markdown 编辑器(可选的人类界面) │
└──────────────────────────────────────────────────────────────┘
检索采用渐进式流程:memory_context 返回有长度边界的第一层上下文,memory_search 缩小候选范围,memory_read 只打开明确相关的权威笔记。Agent 无需全量扫描 Markdown 目录。
三层记忆生命周期
| 层级 | 存储内容 | 状态 | 是否进入普通检索 |
|---|---|---|---|
| 正式记忆 | 已确认的偏好、决策、约束、修复方法与可复用知识 | active、superseded、archived |
仅 active |
| Inbox Proposal | Agent 推断但尚未确认的高价值候选结论 | pending、promoted、rejected |
否 |
| Handoff | 恢复未完成任务所需的临时状态 | active、completed |
否 |
Handoff 存未完成的“事”,Inbox 存待确认的“候选结论”,正式记忆存已确认、可复用的“果”。
三层内容分别位于 <Markdown 根目录>/Memory/ 下的正式记忆目录、Inbox/ 和 .handoffs/;SQLite 索引与可选审计日志保存在用户数据目录,不会取代 Markdown 真源。
同一个 Markdown 根目录(或 Obsidian Vault)可以供多个已接入项目共用。Memory/global/ 保存跨项目适用的正式记忆,Memory/projects/<project-id>/ 保存项目专属记忆;这两个数据范围与 Agent 的安装范围无关。KeepM 只在明确选择的项目中注册 MCP、策略和 Hook,不提供用户级 Agent 接入。
快速开始
环境要求:Python 3.11+、uv 和一个本机可写的 Markdown 目录。
uvx keepm setup
uvx 会在隔离环境中运行 KeepM,无需永久安装。交互向导会完成最少且完整的接入:
- 指定共用的 Markdown 存储根目录与默认记忆语言(
zh/en); - 选择 Codex、Claude Code 或 pi;
- 指定要接入的项目目录,默认使用当前工作目录;
- 仅在该项目中注册
keepmstdio MCP Server、安装受管理的 Agent 记忆策略,并默认配置SessionStart/StopHook。
三个宓主的接入位置:
| 宓主 | MCP 注册 | Agent 入口 | 生命周期 Hook |
|---|---|---|---|
| Codex | .codex/config.toml |
AGENTS.md |
.codex/hooks.json |
| Claude Code | .mcp.json |
CLAUDE.md |
.claude/settings.json |
| pi | .mcp.json |
AGENTS.md |
无宓主 Hook 文件,报 not-applicable |
pi 与 Claude Code 共用同一份项目 .mcp.json,且两边都把 command 条目视为 stdio,因此一次注册对两个宓主同时生效,不会互相覆盖。写入采用 JSON 合并:其他 MCP Server 和未知顶层字段全部保留;文件格式非法、是符号链接或不是普通文件时直接报错,绝不整体重写。pi 没有 Claude 那种宓主 Hook 配置文件,setup 会在文本和 JSON 中把 lifecycle_hooks 明确报为 not-applicable,而不伪造成功;相同的会话与 checkpoint 指引由受管理的 AGENTS.md 策略承担。
自动化配置:
uvx keepm setup --yes --root /path/to/notes --agent codex --project-dir /path/to/project
--agent 可选 codex、claude 或 pi。
CI、安装脚本或 Agent 还可以请求机器可读的验收摘要:
uvx keepm setup --yes --format json --root /path/to/notes --agent codex --project-dir /path/to/project
文本和 JSON 输出都会分别汇总 Vault 可访问性、MCP 注册、受管理策略、Hook 与 Audit 配置。SQLite 健康和宿主 Elicitation 能力只有在首次 MCP 会话建立后才能验证,因此 setup 会明确标为 deferred,而不会伪造成功。
可选的运维参数包括 --deep-reconcile-seconds(默认 1800,0 禁用周期深扫)、--verification-review-days(默认 180)和 --sqlite-journal-mode wal|delete(默认 wal;网络文件系统可显式选择 delete,但这不会提供跨机器锁)。
重复执行 setup 是幂等的,只会更新目标项目中 KeepM 管理的配置块。~/.config/keepm/config.toml 只保存 KeepM 自身的本机 Vault 配置,不会在所有项目中全局启用 Agent。KeepM 不要求安装或运行 Obsidian;在 WSL 中直接使用 /mnt/c/... 形式的 Windows 挂载路径即可。
极简维护命令
健康报告复用 memory_doctor 的确定性诊断结果,只导出状态和 finding 元数据,不包含记忆正文、Proposal 内容或任何 repair/update token:
uvx keepm doctor --format json
uvx keepm doctor --format markdown --output keepm-health.md
Safe GC 只处理 Memory/.trash/ 中具有可信软删除时间、且超过指定期限的普通文件。默认命令只生成预览和短时一次性计划;repair 备份、符号链接、无可信删除时间的文件以及正常的 active/archived/superseded 记忆均不会被删除:
# 仅预览,不删除
uvx keepm gc --older-than-days 30
# 使用预览返回的 token 执行完全相同且未变化的计划
uvx keepm gc --confirm --token <gc-token>
确认后的 GC 是不可恢复删除;trash 内容、checksum、候选集合或 token 时效发生变化时会拒绝执行并要求重新预览。
JIT 两阶段读取与可复现卡片契约
上下文压缩丢细节的真正原因往往不是“没存”,而是“存得太粗”与“召回靠语义联想”。KeepM 把两个问题分开解决。
写入侧:确定性契约。 decision、constraint、fix 必须包含固定英文段落 ## Decision and constraints 与 ## Reproducible parameters(无论正文是中文还是英文),fix 还必须在 frontmatter 携带至少一个仓库相对 sources 指针:
sources:
- deploy/docker-compose.yml#service:db
- src/config/database.py#symbol:get_engine
指针路径是机器真源,# 后的锚点只是给人看的提示,KeepM 绝不做 AST 解析,避免重构造成误报。契约只在写入时生效(create / propose / inbox_update / promote,以及改变正文或 kind 的 update);契约之前保存的卡片仍然可解析、可检索,只刷新 verified_at 或 tags 也不会被拦。写入层另外会拦住带密码的连接串与显式密码赋值,但会放行 ***、${PGPASSWORD}、<password> 这类脉敏写法。
读取侧:两阶段 JIT。
阶段 1:骶架探测
memory_context(query) ─► 相关记忆、handoff、Inbox 计数
memory_catalog() ─► 有界槽位句柄(name / kind / scope / 30 字用途 / is_stale)
阶段 2:目标点读
memory_catalog(source_path="deploy/docker-compose.yml")
─► 路径反查到 postgres-wsl2-io-config
memory_read(identifier="postgres-wsl2-io-config")
─► 完整参数、真源指针、版本凭证
目录只返回句柄,不返回事实:排序固定为 pinned → kind 优先级 → verified_at → name_key,默认 limit=20、用途行截断到 30 字符,并带 notice 明确禁止从槽位名推测参数。同名的 global 槽位被 project 槽位遮蔽后不会重复出现,is_stale 直接复用 doctor 的验证判据(只对 active 的 constraint / fix / workflow 生效)。
路径反查把“该读哪张卡”从语义联想变成确定性路由:准备修改 deploy/docker-compose.yml 时,相关 fix 卡片会直接被命中,而不依赖 Agent 猜到名字。目录支持文件与目录前缀,并对 ./、反斜杠和大小写做可移植归一化。
Agent 工作流与低噪对话式审核
任务开始
└─ memory_context(query)
├─ 上下文充足 ─────────────────► 继续主任务
└─ 上下文不足
└─ memory_search ─► 只 memory_read 相关记忆
产生值得保留的信息
├─ 用户明确要求或已确认 ─────────────► memory_create / memory_update
├─ Agent 推断且有长期价值 ──────────► memory_propose ─► Inbox 待审核
└─ 尚未完成的任务状态 ──────────────► memory_handoff_create / update
写操作会立即刷新对应索引,不需要在任务开始或结束时常规调用 memory_sync。Hook 只负责提醒当前 Agent 做有边界的恢复或检查点整理;KeepM 不读取原始对话,也不会调用模型。
KeepM 使用受控对话完成 Inbox 审核,不强制依赖 GUI 或 Obsidian 插件。Agent 只有在用户主动要求、当前对话刚产生新 Proposal,或 Inbox 出现过期/数量阈值信号时,才会在主任务回答末尾提醒;每次最多呈报 3 条。宿主支持 MCP Elicitation 时,实际提升前还会显示一次与 Proposal checksum 和目标方案绑定的原生最终确认。
Agent 对话式审核示例
顺便提醒:检测到 2 条待审核候选记忆:
- Proposal P1[项目偏好] 优先使用 pnpm 而非 npm(建议:批准)
- Proposal P2[架构决策] 放弃 Redis,改用 SQLite(建议:批准)
可以回复“批准 Proposal P1、拒绝 Proposal P2”或“稍后”。
主任务永远优先,Proposal 使用独立于 Step 1 等主任务步骤的编号。“行”“好的”“按你说的办”“按建议处理”等泛化赞同只授权主任务,绝不授权 Inbox 变更;多条候选时用户必须明确引用 Proposal P1 等标签。只有最近明确呈报了一条 Proposal 时,“批准记忆提案”才可授权该唯一候选。用户回复“稍后”或忽略提醒后,本次会话不再重复打扰;沉默不会批准、拒绝、修改或删除任何内容。
正式记忆使用“槽位命名”:project-package-manager 表示稳定主题,pnpm 只是该槽位当前的结论。memory_context / memory_search 在发现 active 名称、别名硬碰撞或同 kind 主题重叠时会返回有界的 conflict_hints;Agent 必须完整读取相关候选并核对项目真源,不能只信第一条。
确认冲突并得到用户明确授权后,Agent 先预览 memory_resolve_conflict(dry_run=true),再用绑定同一方案的短时 token 执行。supersede 保留历史关系,archive 归档失去独立价值的节点,delete 只把错误节点移入可恢复回收站。KeepM 会同时校验两份 checksum/token、拒绝 supersedes 环,并通过可恢复的文件事务日志与单次 SQLite 事务保证崩溃一致;若进程在多文件替换中断,下次启动会继续提交或安全回滚。
MCP 工具一览
| 分组 | 工具 | 用途 |
|---|---|---|
| 上下文 | memory_status、memory_context |
运行状态、有长度边界的任务上下文和仅计数的 Inbox 信号 |
| 检索 | memory_catalog、memory_search、memory_read、memory_links |
有界槽位目录与文件路径反查、active 记忆加权检索、权威读取、WikiLink 与反向链接 |
| 正式记忆 | memory_create、memory_update、memory_delete、memory_resolve_conflict |
创建已确认记忆;保护更新、删除及两条 active 记忆的预览式冲突解决 |
| Inbox | memory_propose、memory_inbox_list、memory_inbox_read、memory_inbox_update、memory_inbox_promote、memory_inbox_reject、memory_inbox_prune |
隔离、查看、修正、批准、拒绝、合并或安全清理候选 |
| Handoff | memory_handoff_create、memory_handoff_read、memory_handoff_update、memory_handoff_complete |
保存、恢复、更新和归档未完成任务状态 |
| 运维 | memory_doctor、memory_repair、memory_sync |
诊断损坏、预览授权的确定性修复、对账或重建索引 |
修改或删除已有对象前必须完整读取当前内容,并提供一次性版本凭证;如果 Markdown 在读写之间发生变化,KeepM 会拒绝过期操作,不会盲目覆盖。
对账、文件系统与长期健康
- 分层对账: 高频快速路径使用
mtime_ns + size;服务启动、默认每 30 分钟一次的周期深扫,以及memory_doctor都会重新计算内容 SHA-256。memory_status返回last_checksum_scan和deep_scan_due。 - 落盘边界: 单文件写入会先
fsync临时文件,os.replace后再fsync父目录;Markdown 仍是唯一真源,Doctor 只报告损坏,不猜测性重写。 - 单活 Writer: 一个 Vault 同一时间只能由一台机器写入。
memory_status会尽力识别 NFS/SMB 等网络文件系统并给出提示;SQLite journal mode 可显式配置为wal或delete,但两者都不能替代跨主机协调。 - 核验提示:
memory_doctor只对 active 的constraint、fix、workflow给出verification_missing/verification_overdueinfo;decision和preference默认免检,系统绝不因此自动归档或改写记忆。 - 指针校验: 只有本机配置记录了
[projects.<id>].root,且该目录仍然解析回相同 project id 时,doctor 才会检查sources指针是否存在;否则返回source_pointer_check_skipped。缺失只会产生 info 级source_pointer_missing,绝不把报告标为 failed——因为同一个 Vault 会被多台机器共用。项目根目录只保存在本机~/.config/keepm/config.toml,绝不写入 Vault。 - 结构化报告:
memory_doctor(report_format=json|markdown)和keepm doctor复用同一份无正文健康报告;CLI 可安全写入本地 JSON/Markdown,不引入 HTML 渲染。 - Host 确认适配:
memory_status.host_confirmation根据 MCP 客户端能力报告elicitation或proposal-protocol。不支持 Elicitation 时沿用已经明确完成的 Proposal P1/P2 授权;宿主声明支持后,只有原生确认明确接受才会继续,拒绝、取消或调用错误都会保持 Proposal pending,不写入正式记忆。 - 无正文审计溯源: Proposal 提升审计记录来源 Proposal、MCP 客户端、来源引用、目标记忆、KeepM 策略版本与确认模式,但不会记录 Proposal 正文、描述或 Prompt。
设计哲学与非目标
- 本地优先且透明: 不依赖云服务、HTTP 守护进程或私有存储格式。
- 先准入,后保留: 用户确认的知识才能成为正式记忆;Agent 推断在批准前只能留在 Inbox。
- 确定性安全护栏: 正文限长、高置信度秘密检测、Unicode 槽位去重、单文件原子写入、可恢复冲突事务、checksum、短时凭证、关系环检测、软删除和 doctor 授权修复。
- 人类可编辑真源: 手工修改的 Markdown 会增量对账;无效文件会被诊断和隔离,不会被猜测性改写。
- 不内置 LLM、Embedding 或向量数据库: 语义提炼由当前 Agent 完成,KeepM 只执行确定性规则。
- 不使用伪置信度、静默衰减或自动提升: 用明确生命周期状态和
verified_at管理记忆,审核阈值绝不构成写入授权。 - 不强制 Obsidian 插件或审核 UI: 受控 Agent 对话是通用审核入口;支持 MCP Elicitation 的宿主可额外提供原生最终确认。
- 不归档原始对话: 临时进度进入有边界的 handoff,长期记忆只保留提炼后的可复用结论。
License
Release files for keepm 3.5.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| keepm-3.5.1.tar.gz | 208.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| keepm-3.5.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 356.7 kB
Release files / keepm-3.5.1.tar.gz
| Download URL | keepm-3.5.1.tar.gz |
|---|---|
| Size | 208.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
9576e7d303c105bd390551c5898bf81f0ccc3500328ee8dc6400183c06a0c3f1
|
|
BLAKE2b-256 checksum How to use checksums |
3ee51fab7c4832b733c6ad1e3925a3a5428d4191766fa5f9da30c20b39aa88d5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.10.10 {"installer":{"name":"uv","version":"0.10.10","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / keepm-3.5.1-py3-none-any.whl
| Download URL | keepm-3.5.1-py3-none-any.whl |
|---|---|
| Size | 147.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
11a1b03e9025425f7c316c3ce3b8bf3735d79ffef1d5d277ca87e9ff13adc7ea
|
|
BLAKE2b-256 checksum How to use checksums |
e9c052da0d412e6af65a0902f0d664ab523bc59ba95bb6ddcfff85dc8fc87463
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.10.10 {"installer":{"name":"uv","version":"0.10.10","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|