mcpField
R
rutter

rutter

本地服务
ruttermemory.com记忆与知识02 天前更新

关于 rutter

rutter 是为 AI Agent 提供共享记忆层的 MCP 服务,基于用户自有文件夹中的 Markdown 笔记。它记录带日期的会话结论及所引用笔记,便于在已配置的客户端间搜索过往决策。

主要功能

  1. 01以只追加方式保存 Markdown 记录
  2. 02记录会话结论及笔记哈希
  3. 03用本地 SQLite 索引搜索笔记
  4. 04回顾近期会话和立场
  5. 05按内容哈希跟踪重命名笔记

适用场景

  1. 01回忆早前会话中的决策
  2. 02跨已配置的 AI 客户端搜索笔记
  3. 03核对记录决策所依据的笔记
  4. 04回顾立场随时间的变化

MCP 相关

该 MCP 服务提供搜索和读取笔记、近期会话及已记录立场的工具。已配置客户端的钩子会将会话结论和立场更新写入共享 Markdown 文件夹。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"shinytoyrobots-rutter": {
"command": "npx",
"args": [
"-y",
"rutter-memory"
],
"env": {
"LIBRARIAN_VAULT_PATH": "<LIBRARIAN_VAULT_PATH>",
"LIBRARIAN_USER_LABEL": "<LIBRARIAN_USER_LABEL>"
}
}
}
}
启动命令npx -y rutter-memory
需要配置的环境变量
LIBRARIAN_VAULT_PATHFolder of markdown notes (an Obsidian vault works)
LIBRARIAN_USER_LABELName the server uses for whose work this is; defaults to 'the user'

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
npmrutter-memory0.9.0

工具

4

收录的工具列表 · 更新于 1 周前

参数类型必填说明
typestring否按 frontmatter 中的 `type` 筛选(例如 note、moc、reference)。
limitinteger否最大结果数(默认值为 8)。
querystring是要搜索的内容(自由文本;必须匹配所有词语)。
domainstring否按 frontmatter 中的 `domain` 筛选。
statusstring否按 frontmatter 中的 `status` 筛选(例如 evergreen、snapshot)。

详细介绍

rutter

面向 AI Agent 的个人记忆层。 一份记忆,多个 Agent,由你掌控。

模型不是记忆。你的笔记才是。 rutter 会回忆过去的决策,以及 AI 会话引用过的笔记。记录以纯 Markdown 格式保存在你自己的笔记文件夹中(与笔记并列的 _librarian/ 文件夹里),而不是存放在模型或供应商的账户中。

它是一个基于该文件夹的 MCP(Model Context Protocol)服务。会话做出某个决定时,客户端会留下一行记录。一个钩子(客户端在每轮交互后运行的脚本)会将这行记录存入你笔记文件夹中带日期的文件,不会为了润色而改写内容,并附上它所引用的每篇笔记的路径和内容哈希(笔记内容的指纹)。

几周后,你可以在同一个 AI 工具或另一个已配置的工具中询问自己的结论,就能找回那行记录及其日期和相关笔记。重命名但未编辑的笔记会通过哈希追踪。rutter 无法定位的引用会标记为未解析,而不会被丢弃。原地修改的笔记目前还不会被标记。

它适合使用 Markdown 笔记且熟悉配置 AI 客户端的人。请从 docs/getting-started.md 开始;Claude Code 用户只需几分钟即可安装插件。其他用户可从 npm 安装,软件包名为 rutter-memory(那里的 rutter 是一个无关库的名称)。

它不包含模型。它由代码和存储组成,因此推理由你的客户端负责。

这个名字源自大航海时代:rutter 是记录实际航行路线的航海日志,与地图相对。地图记录已知的信息,rutter 记录你为此做过什么。

这是个人工具,以参考实现形式发布,并非受支持的产品。 它为一个人的工作流打造,分享出来是因为这种机制或许有用。不承诺开发路线,不承担支持义务,也不保证下一次提交不会改动你所依赖的内容。欢迎复刻、借鉴其中的想法,也可以提交 issue。请不要在它的基础上构建任何关键系统。

在所有 AI 工具中共用一份记忆

rutter 为 Claude Code、Grok、Codex、Copilot CLI、Antigravity 和 Muse Code 保存同一组记录。每个客户端都会将会话摘要写入同一个笔记文件夹。每个客户端也会通过同一个 MCP 服务读取这些摘要。

你周二在 Codex 中做出的决定,只要 Codex 为它写入了一条记录且其钩子已运行,周四向 Claude Code 提问时就能看到。你无需在客户端之间复制任何内容。这之所以可行,是因为记忆是由你掌控的 Markdown 文件夹,而不是某个工具内置的功能。

你使用的工具请参阅所需操作
Claude CodeClaude Code 快速上手只需几分钟;无需克隆
GrokGrok 使用路径安装一次 npm、配置一个钩子,并运行一次 grok mcp add
CodexCodex 使用路径安装一次 npm,并配置一个你信任的钩子
GitHub Copilot CLICopilot CLI 使用路径安装一次 npm、配置一个钩子,并添加一个指令文件
Antigravity CLI(agy)Antigravity 使用路径安装一次 npm、配置一个钩子,并添加一个规则文件
Muse Code(muse)Muse Code 使用路径安装一次 npm,并运行一次安装程序
任何其他 MCP(Model Context Protocol)客户端仅通过 npx 回忆添加一条配置。仅支持搜索和回忆:没有钩子就不会捕获任何内容
从克隆版本使用 Claude Code从源代码开始共 8 个步骤(M1 到 M8),从手动写入一条记录开始。适用于贡献者

Grok 仅在 Linux 上经过验证(已知问题)。仅需 npm 的使用路径(Codex、Copilot CLI、Antigravity、Muse Code)是在同时安装了 Claude Code 的机器上测试的,因此尚未在干净的机器上测试;请参阅已知问题。

注册 MCP 服务后,每个客户端都能读取记忆。写入则需要一个在每轮对话后运行的钩子,而这 6 个客户端都有这样的钩子。任何其他 MCP 客户端都可以读取但无法写入,只需通过 npx 运行服务 (仅通过 npx 回忆)。Antigravity 这一行介绍的是 agy 命令行工具,而不是 Antigravity IDE。

将每个客户端都指向同一个笔记文件夹。每个客户端设置该路径的方式各不相同。Claude Code 插件会在安装时询问该路径。Grok、Codex 和 Copilot CLI 会从启动它们的 Shell 中读取 LIBRARIAN_VAULT_PATH。 Antigravity 和 Muse Code 的安装程序则接受 --vault。每条记录都会注明由哪个客户端写入;仅当钩子能够判断时才会注明时间 (请参阅已知限制)。

这与现有记忆有何不同

你的运行环境几乎肯定已经以某种方式实现了这些功能。Claude Code 会将会话整理成摘要,并从中推断偏好,写入记忆文件夹,然后随时间推移进行整合——合并重复内容,删除看起来过时的内容。

整合是合理的默认做法,但这恰恰与这里的做法相反。

这里的内容永远不会重写已存储的行。记录只会追加,读取时按会话分组;写入时也不会为了风格而改写某一行:只会进行一行规范化处理,并截断至 2,000 个字符。

第二个区别更为重要。摘要本身不是记录,而是一种陈述。摘要加上其中引用的笔记的版本化状态才是记录,因为它提供了可供比较的指纹。

相邻领域的做法各自涵盖了这第二部分的一部分。架构决策记录会记录 做了什么 和 为什么这样做,却不会固定记录决策适用时的版本。有事件溯源日志会为事件加上时间戳,却很少记录文件级来源信息。供应链溯源格式能正确地对内容进行哈希处理,但它们是为审计人员打造的,而非为你的下一次工作会话打造。因此,决策会悄然偏离产生它们的代码,却没有任何提示。

这里的每条引用都会附带笔记在记录该行时的内容哈希。即使笔记改了名称,也会根据精确的哈希匹配找到对应笔记;无法定位的笔记则会显示为未解决,而不是被悄悄丢弃。存储的哈希还让你可以将文件与其当时的状态进行比较。目前还未实现报告原地修改的笔记。

这种设计还带来两个次要特点。存储库属于你——它是你自己的笔记目录中的 Markdown,而不是供应商的账户或工具的私有文件夹,因此具有可移植性、可搜索性、可提交到 git 的特性,并且即使这个项目消失,你仍然可以读取其中内容。这也是你使用的每个客户端都能读写同一批记录的原因。而且,由于客户端会在上下文仍然加载时写入摘要,记录过程不需要额外的大模型调用或网络调用。代价是,质量取决于客户端是否遵守风格约定,详见 服务告诉客户端的内容。

这些功能都不是为了与检索能力竞争。具备能力的 Agent 读取组织良好的笔记目录,本来就能很好地完成检索。这个项目解决的是短暂会话无法实现的部分:跨越时间的记忆。

它目前的功能

  • 将笔记目录索引到本地 SQLite FTS5 全文索引中——这是可丢弃、可重新生成的缓存。你的文件始终是事实来源。
  • 随手记录。 当会话得出结论或产出成果时,客户端会留下一行记录;Claude Code、Grok、Codex、Copilot CLI、Antigravity 或 Muse Code 的 Stop hook 会将该行追加到 <notes>/_librarian/sessions/<date>.md,并通过内容哈希引用涉及的笔记。客户端会被要求为每项可区分的成果各写一行,而不是每个会话只写一行——一次工作会话通常会留下三四行;阅读时,这些记录会被归并为对该会话的完整叙述。同一会话已经记录过的行会被跳过(具体规则见 docs/memory-of-use.md)。记录持久保存、可提交到 git,并由客户端写入。
  • 这行记录有风格约定。 面向一位聪明但时间紧迫、未参与该会话的读者来写:先写结果,使用常见词语而非会话中的简写,不要杜撰代号或版本标签,约 40 个词。此约定作为指引包含在服务的 MCP 指令中。服务不会为了符合风格而重写摘要——超过字数限制的摘要会在记录时报告,然后未经编辑直接存储。服务会将每行规范为单行(删除控制字符、合并空白),并在超过 2,000 个字符时截断;详见风格约定。
  • 工作区来源信息。 每条记录都包含会话的工作目录、据此得出的项目名称,以及存在时的 git 远程 URL,因此跨越三项工作的某一天也能清晰呈现。无需配置;解析过程只读取本地文件——不会运行 git,也不会联系远程服务。
  • 四个只读 MCP 工具:
    • librarian-search — 排序后的全文搜索。每条结果都包含其路径、type/status/created 来源信息,以及匹配片段。多词查询采用 AND 匹配,因此搜索“blue man group”会找到同时包含这三个词的笔记,而非任意包含其中一个词的笔记。你之前互动过的结果还会附带一条简短的既往互动说明;这只会增加信息,绝不会改变排序。
    • librarian-get-note — 按路径获取一篇笔记的完整内容。
    • librarian-recent — “我最近在忙什么?” 按日期从新到旧列出会话,并提供日期、项目和来源信息;可选 project 筛选条件、以天为单位的 window,或 count。
    • librarian-positions — “我对 X 有什么看法?后来变了吗?” 可通过三种方式查询:用 topic 查询精确的话题键(返回一个答案或明确说明未找到),用 query 根据记录的立场进行自由文本匹配,或用 note 查询按路径引用某篇笔记的立场。每个答案都是该话题当前的立场,并附上形成和最后修订的日期;添加 chain: true 可查看完整的取代历史。
  • 随服务传递的指令。 任何已连接的客户端在回答关于近期活动的问题时,都会被告知使用 librarian-recent;在回答“我以前见过这个吗?”这类问题时,先使用 librarian-search,再直接读取文件;并用通俗语言报告回忆到的摘要——包括风格约定存在之前写入的记录,这是让那些密集的旧记录变得清晰的唯一方法。无需为每个项目配置客户端。
  • 记录自身的使用情况。 按 ISO 周统计有状态行为被调用的次数,计数仅存于本地。
  • 立场记录(decision-graph Phase A)。当客户端对某个话题形成、改变、重申或撤回立场时,会留下另一种更少见的记录——立场指令,并追加到 <notes>/_librarian/positions/<YYYY-MM>.md。它与会话记录完全分离,采用只追加的记录流。指令类型(assert、revise、reaffirm、retire)决定事件的作用;立场文本本身不作分类,其中只有两个字符串会被读取——[[wikilink]] 会成为带版本的引用,revises: <event-id> 会记录它所取代的事件——两者都不会从存储的文本中删除。记录不会为符合风格而重写;每条不同的指令只记录一次。
  • 立场回忆(decision-graph Phase B)。librarian-positions 根据这些记录流回答“我对 X 有什么看法?这种看法如何变化?”。某个话题的当前立场是其最新事件中的立场;如果该事件是 retire,返回的是带有撤回事件自身记录文本的已撤回占位条目——不会返回被撤回的立场,也不会为了生成该结果而从历史记录中删除任何内容。每个答案都会说明其来源:立场形成的日期(即最初的 assert),以及存在时最后一次修订的日期——重申会再次确认立场,但不会改变该日期。长时间未有任何事件涉及的立场会标记为休眠;每次读取时都会根据事件自身的时间戳即时计算,且不会存储在任何地方。已撤回的立场绝不会标记为休眠。整个机制是一种投影:每次运行 npm run reindex 时,都会完全重建三个 SQLite 表,且只依据 <notes>/_librarian/positions/*.md 重建。只有重新索引才会触发更新——上次重新索引之后记录的立场,要等下一次运行后才能被回忆到。这种延迟会明确披露,不会悄无声息地造成遗漏;也正因如此,回忆机制完全不会干扰记录过程。
  • 笔记重命名后仍能保留身份。 引用会同时记录笔记路径和记录时的内容哈希。所谓“失效”,就是路径在磁盘上不存在,仅此而已,无论文件类型是什么——只要某个受限知识库文件仍然存在,对它的引用就是有效的(无论该文件是 .gitignore、导出的 .html,还是位于 _librarian/ 目录下),即便它不是已索引的 Markdown 笔记也是如此。重命名一篇被引用的笔记且不更改其内容后,下一次运行 npm run reindex 会自动将旧引用绑定到新路径——不使用启发式方法,不计算相似度,只进行精确的内容哈希匹配——并在 librarian-recent / 搜索结果增强中静默解析。如果重新索引无法确定(笔记也被编辑过,因此没有当前笔记的哈希与之匹配;或者多篇当前笔记具有相同哈希),那么在 librarian-recent 中,该引用会明确显示为未解析状态并列出候选项;在搜索结果增强中,若某个候选笔记恰好是搜索结果,也会显示这一状态。此状态会一直保持,直到通过 npm run identity-confirm 确认该引用。如果没有任何候选项(笔记既被重命名又被编辑),则该引用只会显示在 librarian-recent 中——该列表是发现未解析引用的完整入口;搜索结果增强以候选项为锚点,因此无法提及没有候选项的引用。在搜索结果中,单纯的候选项绝不会被标注为用户曾与之互动;未解析状态及其候选项会作为单独的明确说明呈现。确认后的绑定具有持久性:即使知识库后来发生变化,导致自动精确哈希匹配指向其他位置,确认的绑定仍会优先采用,并会显示不一致情况(“已确认 X;当前哈希匹配到 Y”),而不会被静默覆盖——只有再次运行 npm run identity-confirm 才会更改绑定。无论发生何种情况,存储的会话记录都不会被重写。

已知限制

先在此说明,避免之后才发现:

  • 较早的记录内容密集。 风格约定及其字数预算是在最初两周的记录之后才制定的,而现有记录不会追溯修改。早期条目读起来像构建日志。阅读时的指导是唯一能触达这些记录的方式。
  • 质量取决于你的客户端。 服务端不包含模型,因此忽略风格约定的客户端仍会生成摘要,而服务端会照常忠实地存储这些摘要。
  • 你的工具之间共享,但人与人之间不共享。 一个人的工具共享同一份记忆。这里没有涉及人与人之间共享记录、批准流程,或决策版本的优先级。这些是团队规模下的难题,这里都没有解决。
  • 记录标注的是客户端,而非模型。 当钩子能够确定客户端时,会话条目或立场事件会带有 client 标签(claude、grok、codex、agy、copilot 或 muse),这样你就能看出哪个客户端停止生成摘要。标签指的是宿主,而非模型:agy 运行 Gemini 和 Claude 模型,且没有钩子负载会指出具体是哪一个模型。宁可不标,也不猜测;因此,标签出现之前的记录、手动注册的钩子,以及无法明确判断的轮次都不会显示标签。目前无法按客户端筛选或搜索。
  • 捕获取决于每种工具所用的模型是否遵循指令。 钩子只会提取模型写下的内容。Claude Code、Grok、Codex、Copilot CLI、Antigravity 和 Muse Code 都经过了真实会话测试。如果模型跳过该内容,就不会有任何内容可供捕获。
  • 重建索引时可能会短暂影响另一个会话。 服务端启动并检测到更改时会重建索引,每几千条笔记大约会花一秒删除并重新创建表。此时从另一个打开的会话进行搜索,可能会得到空结果。这种情况很少见,因为索引未发生变化时不会重建,而且下一次调用就会恢复。
  • 引用展示的是捕获了什么,而非读取了什么。 客户端会选择要列出的路径,哈希则在轮次结束后、执行捕获时计算。rutter 无法确认模型是否读取了某个文件、某个文件是否产生了结论、捕获是否完整,或路径未变的笔记自那时起是否发生过更改(尚未实现此类报告)。仅追加是服务端遵守的规则,并非防篡改审计。请参阅what rutter can and cannot establish。
  • 语义搜索尚未实现。 embeddings.ts 只是移植后的接口,没有具体实现;检索仅支持全文搜索。
  • 仍在积极评估中。 有状态行为受使用情况门槛控制——项目会衡量它是否真的被频繁使用,并准备好接受它并未被使用的结论。

要求

  • Node ≥ 22(使用内置的 node:sqlite,无需原生构建步骤;包含 FTS5)。已在 Node 26 上验证。
  • 一个 Markdown 笔记目录。该项目最初面向 Obsidian 构建,能够理解 wikilinks 和 frontmatter,但并不要求使用 Obsidian。
  • 用于自动捕获的 Claude Code、Grok、Codex、Copilot CLI、Antigravity 或 Muse Code。MCP 工具适用于任何 MCP 客户端。 One memory across your AI tools 中的表格说明了六种工具各自如何捕获,并链接到相应的设置说明。Claude Code 会从转录内容中提取指令,Copilot CLI 和 Antigravity 也会如此(从当前轮次中提取)。Grok、Codex 和 Muse Code 使用 Stop 事件中的最终助手消息,因此在 Codex 和 Muse Code 中,指令必须出现在最终回复里。

设置

首先将其指向你的笔记。 默认路径是作者自己的路径;目录无法读取并不算错误——程序会成功重新索引并报告笔记数为 0,看起来一切正常,直到你搜索时发现什么也找不到。

通过 npm 安装:

export LIBRARIAN_VAULT_PATH=/path/to/your/notes   # do this before reindexing
npm install -g rutter-memory
rutter-memory reindex  # expect a non-zero note count; zero means the path is wrong

不带参数运行时,rutter-memory 命令会启动 MCP 服务,客户端就是这样启动它的。它还支持 reindex [--force]、recent 和 install-hook;运行 rutter-memory help 可查看这些命令。安装 rutter-memory 还会提供一个 rutter 命令,它是同一程序的短名称;这与 npm 上的 rutter 包无关。

从克隆的仓库开始,进行代码开发:

export LIBRARIAN_VAULT_PATH=/path/to/your/notes   # do this before reindexing
npm install
npm run build          # compile to dist/ (optional; tsx runs the TS directly)
npm run reindex        # expect a non-zero note count; zero means the path is wrong

通过环境变量配置:

变量默认值含义
LIBRARIAN_VAULT_PATH~/Documents/knowledge-vault要编入索引的笔记目录(只读)。请设置此项。
LIBRARIAN_DB_PATHnpm 安装:~/.local/share/rutter/<id>/librarian.db,每个笔记文件夹各一个。克隆仓库:<repo>/data/librarian.db派生索引的存放位置。npm 安装会优先使用 $XDG_DATA_HOME,而不是 ~/.local/share。一个索引仅服务于构建它的笔记文件夹;如果第二个文件夹指向同一个文件,操作会被拒绝,而 reindex --force 会将该文件转交给它。
LIBRARIAN_USER_LABELthe user服务在客户端收到的指令和工具描述中,如何说明这些内容属于谁。将其设为你的名字后,客户端会被告知它正在查看你的内容,读起来比“用户的”更自然。

使用记忆(会话记录、使用日志)存储在 <notes>/_librarian/ 下——位于你的笔记目录中,绝不会放在此代码仓库中。请参阅 docs/memory-of-use.md。

初次使用? 阅读 docs/overview.md,了解 librarian 是什么以及它如何工作;然后阅读 docs/memory-of-use.md,深入了解捕获 / 回忆 / 丰富 / 门控行为。同样的文档也发布在 shinytoyrobots.github.io/rutter 上,可直接阅读——npm run site-drift 会在该网站内容与这些文件不一致时发出报告。当前的阶段安排见 docs/roadmap.md。 docs/decision-graph.md 介绍了决策图背后的设计——为什么立场是对仅追加事件日志的投影,而不是需要你维护的第二份内容;docs/decision-graph-plan.md 则是将其拆分为多个阶段的构建计划。

从命令行试用

从 npm 安装后,rutter-memory recent 接受与下方 npm run recent 相同的参数。搜索、使用门控和 identity-confirm 只能从克隆的仓库中运行:

npm run search -- bitemporal forgetting memory   # full-text search
npm run recent                                   # recent session summaries
npm run recent -- --days 7                        # just the last week
npm run recent -- --project rutter           # just one project (case-insensitive)
npm run gate                                       # per-ISO-week use count

在工作区来源记录功能出现之前捕获的条目只会显示没有项目——不会显示占位符,而 --project 筛选器会跳过这些条目,不会猜测其所属项目。

如果 npm run recent 在重命名后显示引用为 [UNRESOLVED -- candidates: ...],且重命名同时更改了笔记内容(或目标变成了重复内容),请手动确认正确的目标——这是仅限本地的命令,不是 MCP 工具,因此 Agent 无法自行改写失效引用的含义:

npm run identity-confirm -- Notes/old-name.md Notes/new-name.md

启用环境捕获(两个步骤,一次性)

无需在 CLAUDE.md 中添加任何内容。 整个捕获约定——需要留下摘要、确切语法以及如何撰写——都作为 MCP 指令随服务一起提供,服务会在连接时将其发送给每个客户端。注册钩子,重启,完成。 Antigravity 和 Copilot CLI 是例外。Antigravity 会将这些指令保存为文件,而不是放进提示词中;Copilot 只有在调用 rutter 工具后才会加载指令,因此这两个安装程序也会写入一个指令文件。(详情请见 docs/memory-of-use.md。)

1. 注册 Stop 钩子。 如果通过 npm 安装,请运行:

rutter-memory install-hook                       # adds the hook to ~/.claude/settings.json
rutter-memory install-hook --client codex        # Codex: ~/.codex/hooks.json (then trust it via /hooks)
rutter-memory install-hook --client antigravity  # Antigravity: ~/.gemini/config/hooks.json
rutter-memory install-hook --client copilot      # Copilot CLI: ~/.copilot/hooks/rutter.json

请全局安装(npm install -g),不要通过 npx 安装:钩子通过绝对路径注册,而 npx 缓存可能随时被清除。切换 Node 版本后,请重新安装并再次运行同一行命令;它会将现有钩子移到新路径,而不是再添加一个。

如果是从克隆安装,请运行以下命令:

npm run build && npm run install-hook          # adds the hook to ~/.claude/settings.json
npm run build && npm run install-hook -- --client codex   # Codex: ~/.codex/hooks.json (then trust it via /hooks)
npm run build && npm run install-hook -- --client antigravity   # Antigravity: ~/.gemini/config/hooks.json
npm run build && npm run install-hook -- --client copilot       # Copilot CLI: ~/.copilot/hooks/rutter.json

……或者手动将其添加到 ~/.claude/settings.json(钩子会运行 dist/capture-cli.js,因此请先构建):

{
  "hooks": {
    "Stop": [ { "hooks": [ { "type": "command", "command": "/ABSOLUTE/PATH/hooks/librarian-stop.sh" } ] } ]
  }
}

2. 重启 Claude Code。 钩子会在会话开始时读取;新会话也会加载刚构建的服务。使用 /mcp 验证(四个工具),然后在下一次实际会话后检查捕获内容是否出现在 <notes>/_librarian/sessions/ 中。

服务会告知客户端的内容

如果客户端从未留下摘要,钩子就不会捕获任何内容;服务也不包含用于撰写摘要的 AI——因此服务会提出要求。此处的约定块是从 src/server.ts 中的 SERVER_INSTRUCTIONS 原样引用的,该文件是约定的唯一来源;有一项测试(COR-R-030)会在此处副本与其不一致时失败。

当会话决定或产出了值得日后回忆的内容时,请留下会话摘要——发出一行指令,格式如下:

每完成一件可以单独描述的事情,就发出一行,而不是等到最后把所有内容都写在一行里;琐碎工作完全省略。捕获钩子会在每轮对话后提取最新的一行;无需调用工具来记录。后续一行只描述自上一行以来新增的内容。

每行都要写给一位时间紧迫、头脑清晰但未参与本次会话的读者:先说明决定或产出了什么;优先使用常见词语,而非会话中的简称;展开说明或避免使用本次会话新造的代号、版本标签和缩写(知识库中使用的术语可以保留);当用户做出决定、选择、裁定或纠正时,注明是用户所为,而不是因为用户提出了问题。保留给出的理由。目标长度约 40 个词,最多 60 个词——只写一行,不要写成构建日志;内容会原样存储。

当你对某个主题形成、改变、重申或放弃某种立场时,也要留下一行立场记录:`` -- 单独存储,逐字节原样保留,且应少用。

以“Write each line”开头的段落是风格约定(见 风格约定)——它是避免六个月后面对一整个目录却看不懂其中摘要的唯一保障。服务在这方面不会提供帮助:无论收到的内容是什么风格,它都不会改写。未填写的模板是唯一例外:仍用 <angle brackets> 括起来的摘要会被视为“无指令”,而不会被存储,因此只复制指令行却不填写内容,将不会捕获任何内容。

工作目录会随 Stop 事件一并传入,因此每条记录对应的项目也无需设置。

如果捕获内容不再出现,备用方案是将该约定块粘贴到全局 ~/.claude/CLAUDE.md 中,作为常驻规则。这是双重保险,并非必需步骤——如果确实需要这么做,那就是值得报告的缺陷,因为服务本应独立承担这项工作。

安装为 Claude 插件

该插件打包了服务和捕获钩子,因此无需手动构建、注册或编辑任何内容。安装为插件后,Claude Code 只会询问一件事——要搜索的笔记文件夹——然后自行启动服务和 Stop 钩子。

rutter 已列入 Anthropic Directory,适用于 Claude Code 和 Cowork。Claude Code 内置了该目录:在 /plugin → Discover 下找到 rutter,或运行

/plugin install rutter@anthropic-plugin-directory

该目录提供的是 Anthropic 上次审核的版本,可能落后于此代码库。若要直接跟踪此代码库,请改从其自己的市场安装:

/plugin marketplace add shinytoyrobots/rutter
/plugin install rutter@rutter

选择一种方式即可,不要两种都用:两次安装会注册两个服务和两个捕获钩子。

按提示选择笔记文件夹,然后运行 /reload-plugins。如果改用 shell 安装(claude plugin install rutter@anthropic-plugin-directory,或添加市场后运行 rutter@rutter),请传入 --config vault_path=/path/to/notes,或随后使用相同的插件名称运行 /plugin configure;没有笔记文件夹,服务就无内容可读。

我们已在 Claude Code、Codex 和 Antigravity 中检查环境自动捕获;也通过安装程序在 Grok 1.0.62 和 Muse Code 1.4.10 中检查过(Grok 所在机器从未安装过 Claude Code);还在一次 Copilot CLI 会话中检查过,捕获的内容随后已从 Claude Code 中召回。该目录也为 Cowork 列出了 rutter;尚未检查其中的捕获功能。

  • 运行内容。 一个本地 MCP 服务(node dist/stdio.js)和一个 Stop 钩子(hooks/librarian-stop.sh)。两者都只是普通的 Node 和 shell 脚本,可在此代码库中查看;dist/ 是已提交的 TypeScript 构建产物,因此实际运行的代码与 GitHub 上的代码一致。
  • 存放位置。 搜索索引位于插件自己的数据文件夹(~/.claude/plugins/data/…)中,并会在更新后保留。会话记录存放在笔记文件夹内的 _librarian/ 中。
  • 索引会自动维护。 服务首次启动时会构建索引;笔记、会话记录或位置流发生变化后,服务下次启动时会重建索引。若要获取会话中途所做的更改,请启动新会话。
  • 如果你之前手动注册过钩子(rutter-memory install-hook 或 npm run install-hook),添加插件时请从 ~/.claude/settings.json 中移除该条目,否则会尝试捕获两次。系统会检测到重复内容,不会重复存储,但这会造成不必要的工作。
  • 维护者: 已提交 dist/,因此插件可直接从克隆的代码库运行。每次 src/ 变更时,请运行 npm run build 并提交构建结果。

设置 Grok、Codex、Copilot CLI、Antigravity 和 Muse Code

Claude Code 提供一条命令即可安装插件。其他四种方式还需要几个步骤。无论使用哪一种,都请将其指向与其他客户端相同的笔记文件夹,否则每种方式都会各自保存记忆。

Grok

Grok 无需 Claude Code。通过 npm 安装 rutter,然后运行安装程序:

npm install -g rutter-memory
rutter-memory install-hook --client grok

安装程序会写入 ~/.grok/hooks/rutter.json(或 $GROK_HOME/hooks/rutter.json),并输出一条包含笔记文件夹路径的 grok mcp add 命令。需要你自行运行这条命令;安装程序不会代为运行。Grok 会从启动它的 shell 中读取 LIBRARIAN_VAULT_PATH,因此如果笔记不在 ~/Documents/knowledge-vault,请在该 shell 中设置此变量。如果 Grok 已通过 Claude Code 插件运行 rutter 的钩子,安装程序会提示这一点,并且不会添加第二个条目。

钩子仅读取 Grok 最后的助手消息,因此请将摘要行放在最终回复的末尾。Grok 会将该消息截断至 32,768 个字符,因此在非常长的轮次中,末尾的行可能会丢失。如果最终消息中有两行,则只保留最后一行。Grok 路径介绍了完整流程。

Codex

Codex 无法使用该插件。它不会填入插件的任何变量,也不会安装钩子。 已在 Codex 0.163.0 中验证。使用 npm install -g rutter-memory 安装 rutter,然后:

  1. 在启动 Codex 的 shell 中导出 LIBRARIAN_VAULT_PATH。它的钩子只能看到该环境,无法读取 ~/.claude/settings.json。第 3 步的安装程序也会将文件夹路径写入钩子(取自 --vault、此变量或服务的 config.toml 条目);如果这些都未设置,捕获内容会存到默认文件夹。
  2. 使用 codex mcp add rutter … -- rutter-memory 注册服务,并通过 --env LIBRARIAN_VAULT_PATH=… 传入笔记路径。请参阅 docs/getting-started.md 中的 Codex 路径。
  3. 使用 rutter-memory install-hook --client codex 安装钩子。它还会将 rutter 的说明添加到 ~/.codex/AGENTS.md 中,并用标记块包裹,因为否则 Codex 会对模型隐藏这些说明。然后在 Codex 中使用 /hooks 信任该钩子。安装不会授予信任,未受信任的钩子永远不会运行。
  4. 预期摘要行会出现在 Codex 的最终回复中,因为它的钩子会在该处查找。如果最终回复有两行,只会保留最后一行。
GitHub Copilot CLI

已在 Copilot CLI 1.0.98 中验证。使用 npm install -g rutter-memory 安装 rutter,然后:

  1. 在启动 Copilot 的 shell 中导出 LIBRARIAN_VAULT_PATH。钩子会继承该环境。未设置时,捕获内容会存到默认文件夹。
  2. 运行 rutter-memory install-hook --client copilot。它会在 ~/.copilot(或 $COPILOT_HOME)下写入 hooks/rutter.json 和 instructions/rutter.instructions.md;如果这两个文件不是由它写入的,则会拒绝替换。其他钩子文件和你自己的 copilot-instructions.md 都不会受到影响。
  3. 运行安装程序打印的 copilot mcp add 命令。它会显式传入 LIBRARIAN_VAULT_PATH,因为 Copilot 只会向 MCP 服务传递 PATH。
  4. 保留说明文件。Copilot 只有在调用某个服务的工具时才会加载该服务的说明,因此大多数会话都不会看到捕获约定。测试发现,仅靠服务的约定还不够:只有在文件开头写明适用时机的 Copilot 专属说明后,模型才会写出该行;安装程序会写入这条说明。

Copilot 的界面会隐藏摘要行,因为它是 HTML 注释。钩子会从 ~/.copilot/session-state/<session>/events.jsonl 读取当前轮次的助手消息。Copilot 会在钩子启动片刻后才写入该文件,因此钩子最多会等待三秒,让当前轮次写入。如果当前轮次有两行,只会保留最后一行。

Antigravity CLI

本文介绍 agy 命令行工具,并已使用 agy 1.3.2 验证。不涉及 Antigravity IDE。使用 npm install -g rutter-memory 安装 rutter,然后手动完成设置:

  1. 运行 rutter-memory install-hook --client antigravity --vault <your notes folder>。 它会在 ~/.gemini/config/hooks.json 中注册 Stop hook,并将捕获规则写入 ~/.gemini/config/rules/rutter-capture.md。如果没有指定 --vault,它会沿用现有 rutter hook 使用的文件夹, 然后尝试使用 shell 中的 LIBRARIAN_VAULT_PATH,最后使用默认文件夹,并告知你使用的是哪个文件夹。
  2. 运行安装程序打印的 agy mcp add 命令。它会使用与 hook 相同的笔记文件夹,确保读写都使用同一文件夹。安装程序只确定一次文件夹,因为两端获取文件夹的方式不同。MCP 服务的文件夹存储在配置中。hook 没有自己的配置,会继承启动 agy 的 shell 环境变量。如果依赖环境变量,曾出现过一次决定使用实际知识库,而 agy 却只能读取测试知识库的情况。导出的 LIBRARIAN_VAULT_PATH 仍会覆盖 hook 的默认值。
  3. 保留规则文件。agy 会将 MCP 服务的指令保存为文件,而不是放入提示词中。测试中,模型既没有根据这些指令写出摘要行,也没有根据 AGENTS.md 中的相同文本写出摘要行。全局 trigger: always_on 规则会在每一轮注入。有了它,Gemini Flash、Gemini Pro 和 Claude Sonnet 都会在作出决定后写出一行,在回答简单问题后则不会写。重新运行安装程序即可更新规则。
  4. 预期摘要行会出现在本轮的任意位置。Stop 事件不包含回复文本,因此 hook 会从 agy 的转录中读取当前轮次的助手消息。如果本轮有两行,只会保留最后一行。不会再次读取更早轮次的指令。

要改用其他笔记文件夹,请使用新的 --vault 重新运行安装程序,然后重新运行 agy mcp add。每次捕获都会在 stderr 上打印 in vault <path>,可在 agy 的日志 ~/.gemini/antigravity-cli/log/ 中查看。使用默认文件夹时也会打印相应提示。

Muse Code

已使用 Muse Code 1.4.10(Meta 的终端 Agent muse)验证。使用 npm install -g rutter-memory 安装 rutter,然后运行 rutter-memory install-hook --client muse --vault <your notes folder>。 它会将 Stop hook 和可选的 rutter 服务条目添加到 ~/.config/muse/settings.json,并在 ~/.config/muse/AGENTS.md 中添加标记区块,因为仅凭服务指令,Muse 的模型不会写出摘要行。Muse 会清除环境变量后再运行 hook,因此笔记文件夹会直接写入 hook。安装程序会拒绝处理符号链接或无法解析的文件,并且绝不会更改自有区块之外的文本。之后请启动新的 Muse 会话。详情以及已验证和未验证的内容,请参阅 Muse Code 路径。

接入 Claude Code

刚开始使用这个项目?docs/getting-started.md 提供了适用于每个客户端的设置流程,从安装到首次回忆。

运行 npm run build 后,在仓库根目录中:

claude mcp add rutter --scope user -- node "$PWD/dist/stdio.js"

--scope user 会将服务注册到所有 Claude Code 会话中,无论所在目录为何。 如果不加此选项,服务只对本仓库的项目可用——在你实际工作的目录中无法使用。

服务会在启动时刷新索引,因此新会话会自动获取更新;运行 npm run reindex 可在不重启的情况下刷新。你可以提问,例如 “搜索我的笔记,找找我之前做过的关于 X 的事情”,客户端会调用 librarian-search。

项目布局

src/
  config.ts          notes + db + _librarian paths, ignore list
  vault.ts           markdown walk + frontmatter parse
  db.ts              node:sqlite open + FTS5 schema
  indexer.ts         full reindex (notes -> cache)
  startup-index.ts   build the index at start if missing, rebuild only if notes or records changed
  search.ts          FTS5 query + get-note
  embeddings.ts      stubbed port (not implemented)
  server.ts          MCP tool registration (search, get-note, recent, positions) + server instructions
  stdio.ts           stdio entry point (local Claude Code)
  # memory-of-use:
  fs-safe.ts         write choke point: path confinement + atomic, append-only writes
  sanitize.ts        untrusted summary -> one inert line
  refs.ts            versioned identity (path + content-hash)
  workspace.ts       workspace provenance (cwd -> project + git remote, local reads only)
  session-record.ts  typed record format + append-preserving persistence
  capture.ts         ambient capture orchestration
  directive.ts       parse the client's session-summary directive (no inference)
  positions.ts       position-event stream format + append-preserving persistence (decision-graph Phase A)
  position.ts        position capture orchestration
  position-directive.ts  parse the client's position directive (no inference)
  position-fold.ts   fold the position streams into the rebuildable projection (reindex only, Phase B)
  position-recall.ts librarian-positions' three query modes + what is computed rather than stored
  position-render.ts how a recalled position is worded (attribution, retired stub, inert rendering)
  recent.ts          librarian-recent (grouping / project / window / count / empty-state)
  enrichment.ts      additive prior-engagement annotation on search results
  instrumentation.ts append-only use log + per-ISO-week counts
  identity.ts        note identity: exact-hash rename binding + the rebuildable projection
  app.ts             application seam (domain + instrumentation), used by server + tests
  reindex.ts / search-cli.ts / recent-cli.ts / gate-cli.ts / capture-cli.ts / identity-confirm-cli.ts   CLIs
hooks/
  librarian-stop.sh  Claude Code / Grok / Codex / Copilot CLI / Antigravity / Muse Code Stop hook -> capture-cli
  hooks.json         registers that hook when installed as a Claude plugin
.claude-plugin/      plugin manifest (name, version, how it starts the server, notes-folder option, listing links) and marketplace
dist/                committed build, so the plugin runs straight from a clone
spec/                the executable spec — scenarios, requirements, conformance mapping
test/                node:test suite (temp fixture directories; never touches your real notes)

构建方式

行为会先定义,再编写代码。spec/spec.md 包含 Given-When-Then 场景,以及据此推导出的需求;每项需求都对应评估它的测试,每次修订也都会记录哪些方案被否决及原因。

如果你想了解这里某项决策的来由,这个文件会如实说明。本文档是摘要;规范文件则提供详细内容。

隐私政策

rutter 完全在你的机器上运行。本节就是完整的隐私政策。

收集内容。 作者和任何第三方都不会收集任何信息。服务会读取你指定的笔记文件夹,且绝不会更改你的笔记。它会写入五类本地文件,你都可以打开并阅读。其中四类存放在笔记文件夹内的 _librarian/ 文件夹中;第五类与插件一起存放:

  • 会话记录,位于 _librarian/sessions/:AI 客户端在会话决定或产出内容时写入的单行摘要,按原样存储(规范化为单行);同时记录其引用的笔记路径及内容哈希、工作目录、由工作目录推导出的项目名称、会话 ID、写入记录的客户端(四个固定名称之一,绝非模型名称),以及该目录的 git 远程 URL(如果有,则从 .git/config 读取;不会访问该 URL,且存储前会移除其中的任何令牌、密码或查询字符串)。
  • 立场记录,位于 _librarian/positions/:你针对某个主题形成、改变或撤销立场时,客户端记录的立场,按相同方式存储,并附带日期。
  • 笔记身份账本(_librarian/note-identity.md):当你引用的笔记被重命名时,记录引用现在指向的路径,以旧路径、新路径和内容哈希的形式保存。在重建索引或确认匹配时写入。
  • 使用日志(_librarian/stateful-use.jsonl):每次使用回忆工具时,记录时间戳和工具名称,方便你判断是否值得保留这些工具。
  • 搜索索引(SQLite 文件,存储在插件自己的数据文件夹中:npm 安装位于 ~/.local/share/rutter/,克隆版本位于 data/,或者位于 LIBRARIAN_DB_PATH 指定的位置),由你的笔记和上述记录构建,以加快搜索速度。它是缓存,可随时删除并重建。

使用和存储方式。 仅用于在你自己的电脑上回答你自己的搜索和回忆问题。不会向任何地方发送数据:代码不会发起网络请求,也没有分析或遥测功能。rutter 自身会运行两项内容:本地服务(不会生成其他程序),以及捕获钩子 hooks/librarian-stop.sh,每轮结束后运行本地的 dist/capture-cli.js,以写入上述记录。两者都不会读取凭据或 API 密钥。你使用的 AI 客户端(例如 Claude)会看到工具返回给它的内容,并遵循该客户端自身的隐私条款;rutter 无法控制这些条款。

与第三方共享。 无。

保留期限。 文件会一直保留,直到你将其删除。会话记录、立场记录、身份账本和使用日志按照设计只增不改;要删除它们,请删除笔记文件夹中的 _librarian/ 文件夹。要删除索引,请删除插件的数据文件夹(卸载插件时会执行此操作)、克隆版本的 data/ 文件夹,或 npm 安装版本的 ~/.local/share/rutter/(卸载软件包不会将其删除)。如果设置了 XDG_DATA_HOME,该安装的索引会位于 $XDG_DATA_HOME/rutter/;如果设置了 LIBRARIAN_DB_PATH,索引则是该变量指定的文件,以及它的 -wal 和 -shm 文件。请先退出正在使用该索引的客户端。任何内容都不会存放在其他地方。

联系方式。 如有问题或疑虑:提交 issue,或发送邮件至 [email protected]。

许可证

MIT。请参阅 LICENSE。


索引是缓存。笔记属于你。记录才是重点。

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。