Admission-controlled local Markdown memory MCP for AI coding agents
Project description
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;
- 指定要接入的项目目录,默认使用当前工作目录;
- 仅在该项目中注册
keepmstdio MCP Server、安装受管理的 Agent 记忆策略,并默认配置SessionStart/StopHook。
自动化配置:
uvx keepm setup --yes --root /path/to/notes --agent codex --project-dir /path/to/project
可选的运维参数包括 --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 时效发生变化时会拒绝执行并要求重新预览。
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 条。
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_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默认免检,系统绝不因此自动归档或改写记忆。 - 结构化报告:
memory_doctor(report_format=json|markdown)和keepm doctor复用同一份无正文健康报告;CLI 可安全写入本地 JSON/Markdown,不引入 HTML 渲染。 - Host 确认适配:
memory_status.host_confirmation根据 MCP 客户端能力报告elicitation或proposal-protocol。不支持、取消或调用错误都 fail closed;当前 Proposal P1/P2 明确授权协议始终保留,不会把能力缺失当成批准。
设计哲学与非目标
- 本地优先且透明: 不依赖云服务、HTTP 守护进程或私有存储格式。
- 先准入,后保留: 用户确认的知识才能成为正式记忆;Agent 推断在批准前只能留在 Inbox。
- 确定性安全护栏: 正文限长、高置信度秘密检测、Unicode 槽位去重、单文件原子写入、可恢复冲突事务、checksum、短时凭证、关系环检测、软删除和 doctor 授权修复。
- 人类可编辑真源: 手工修改的 Markdown 会增量对账;无效文件会被诊断和隔离,不会被猜测性改写。
- 不内置 LLM、Embedding 或向量数据库: 语义提炼由当前 Agent 完成,KeepM 只执行确定性规则。
- 不使用伪置信度、静默衰减或自动提升: 用明确生命周期状态和
verified_at管理记忆,审核阈值绝不构成写入授权。 - 不要求 Obsidian 插件或审核 UI: Obsidian 只是可选编辑器,受控 Agent 对话才是标准审核入口。
- 不归档原始对话: 临时进度进入有边界的 handoff,长期记忆只保留提炼后的可复用结论。
License
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file keepm-3.2.0.tar.gz.
File metadata
- Download URL: keepm-3.2.0.tar.gz
- Upload date:
- Size: 174.1 kB
- Tags: Source
- Uploaded using 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}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5d53363522a4678455b8a94da413b938fcec89361c5ab8689239370735c8c888
|
|
| MD5 |
91715cde7a9931807e9473de4c28d245
|
|
| BLAKE2b-256 |
8132c8a21237cd91c78d3ec173890864961770cb7a3cb3e540990774939ffae6
|
File details
Details for the file keepm-3.2.0-py3-none-any.whl.
File metadata
- Download URL: keepm-3.2.0-py3-none-any.whl
- Upload date:
- Size: 129.9 kB
- Tags: Python 3
- Uploaded using 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}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4ac0305d5d6ce3438c5c52942bca46b76882ec26a9c8d0d2106d4cb85e57e527
|
|
| MD5 |
fbd8513d685ae79077b2ba3016b48ef9
|
|
| BLAKE2b-256 |
e57fda8c05c8f4b02962cf47154954b0953e1de50e12bf0585c4994ef4d18114
|