Doramagic 项目包 · 项目说明书

context-keeper 项目

MCP 服务器,在 Claude 多轮对话间维护项目记忆——以人类可编辑的 JSON 记录决策、流程与约束,零依赖。

Overview and Architecture

context-keeper 是一个面向 AI 编程代理(agent)的记忆层(memory layer),以 MCP(Model Context Protocol)服务器的形式运行。它为零依赖、默认离线,将项目中的决策、约束、上下文等结构化条目持久化在本地文件系统中,使得跨会话(cross-session)的工作能够被检索、撤销并投影为可读的 Markdown 文件。

章节 相关页面

继续阅读本节完整说明和来源证据。

设计目标与定位

context-keeper 的核心目标是为 agent 提供一份可在多次会话间复用的"项目记忆",使决策不再随对话窗口的滚动而丢失。它在 v0.10.0 中明确选择了与同类工具 Curion 不同的路线:不引入 LLM 控制架构,不在每次存取时调用外部模型 API(资料来源:README.md:1-40)。这一选择决定了它必须用纯算法的方式实现语义检索、聚类、抽象与覆盖式排序。

按设计,该项目的典型用例包括:

  • 记录决策(decision)、约束(constraint)、会话笔记(note)等条目;
  • 在会话开始时把项目摘要自动注入 agent 上下文;
  • 在 agent 编辑被约束覆盖的文件时,立即把相关约束推送给模型;
  • 把核心决策库投影为 DECISIONS.md,便于人类审阅。

版本 v0.15.0 的发布说明进一步强化了"审计友好"的定位:stdio UTF-8 修复、mirror watermark 数据丢失修复,以及面向 MCP registry 的描述精简(资料来源:pyproject.toml:1-30)。

系统组成

context-keeper 在物理上由一个 stdio MCP 服务器进程加若干本地钩子脚本组成,整体结构可由下表概括:

层级组件职责
传输层server.py(stdio)与 MCP 客户端通信,注册 tools/list 资源
领域层context_keeper/store.py条目文件读写、原子写入、损坏保护
检索层内置 TF-IDF / 嵌入后端词汇与语义检索、聚类、retrieval_hints
约束层hooks/scope_guard.pyPostToolUse 钩子,按 scope 即时注入约束
投影层mirror.pymarkdown_export决策库到 DECISIONS.md 的 render-on-write

server.py 是入口点,对外暴露 record_decisionupdate_entrydeprecate_entryget_project_summary 等工具,并提供 query 端点用于检索(资料来源:server.py:1-120)。工具 schema 的描述经过严格压缩:v0.7.1 将整包体从约 2800 token 削减到 2370 token,并通过回归测试钉住 2500 token 的上限(资料来源:README.md:60-100)。

存储层使用按条目拆分的小型文件,每次写入先写临时文件再通过 os.replace 原子替换,避免崩溃中途损坏,这一保障在 v0.5.0 中引入(资料来源:context_keeper/store.py:1-80)。当读到无法解析的条目文件时,record_*update_entrydeprecate_entry 拒绝写入,以免在已有损坏之上叠加新数据(资料来源:context_keeper/store.py:80-140)。

检索与排序模型

context-keeper 同时维护词法与语义两条索引通路。retrieval_hints 让调用方在录制时提供 2-4 个候选说法,如同义词、症状描述、错误信息,用于弥合未来查询中的词汇错位(vocabulary-mismatch),这一字段在 v0.7.0 中加入并对两类索引同时建库(资料来源:README.md:100-150)。

排序层面采用"覆盖即作废为排序"(supersession-as-ranking)的思路:当一条决策被新条目取代时,旧条目被标记为 deprecated 并降权,但仍可被显式查询以保留审计轨迹。v0.10.0 引入 abstention 机制,使模型在召回结果置信度不足时主动放弃作答(资料来源:server.py:120-200)。

聚类与嵌入后端是可插拔的:v0.9.0 新增多种嵌入后端,并把摘要阶段的截断循环 bug 修复——之前版本对超长 store 会静默注入空摘要(资料来源:context_keeper/store.py:140-220)。

约束注入与人类可读投影

会话级注入由 get_project_summary 完成:会话开始时被调用一次,结果贴在系统提示后。当条目数量过多时,必须保证至少有节略版本的摘要进入上下文——v0.9.0 修复了"truncation loop 误判原始文本"导致空摘要的回归(资料来源:server.py:200-260)。

更细粒度的注入由 hooks/scope_guard.py 提供:它监听 EditWriteNotebookEdit 三类 PostToolUse 事件,一旦 agent 编辑的文件路径命中某条约束的 scope,便通过 additionalContext 把约束原文注入当前回合,保证规则在"被需要的那一刻"出现,而不是仅在会话首条消息里被宣读一次(资料来源:hooks/scope_guard.py:1-100)。

可读性方面,v0.8.0 引入 markdown_export 选项:开启后每次决策变更都会重新渲染 DECISIONS.md,使人工评审无需进入 JSON store 即可阅读历史决策(资料来源:mirror.py:1-80)。

架构数据流

下面的时序图刻画了 agent 编辑一个受约束文件时,context-keeper 的完整数据通路:

sequenceDiagram
    participant Agent
    participant MCP as server.py (stdio)
    participant Store as context_keeper/store.py
    participant Hook as hooks/scope_guard.py
    Agent->>MCP: tools/call record_decision
    MCP->>Store: 原子写入条目
    Store-->>MCP: 写入 + 索引更新
    MCP-->>Agent: 返回 entry_id
    Agent->>Hook: PostToolUse Edit(path)
    Hook->>Store: 查询路径匹配的约束
    Store-->>Hook: 命中约束列表
    Hook-->>Agent: additionalContext 注入

该流程把"持久化"、"检索"与"编辑期即时守卫"解耦,使每层可以独立演进。

来源:https://github.com/jarmstrong158/context-keeper / 项目说明书

MCP Tools and Data Model

context-keeper 通过 MCP(Model Context Protocol)暴露一组以记忆为核心的工具,供连接的客户端在会话生命周期内调用。所有工具围绕"记录 → 检索 → 派生视图"三段式设计,保持零依赖、离线默认;版本演进从 v0.5.0 到 v0.15.0 持续围绕这一目标打磨。

章节 相关页面

继续阅读本节完整说明和来源证据。

设计目标与工具总览

context-keeper 的 MCP 工具刻意避开了 Curion 那种"每次 store/recall 都走 LLM 控制器"的架构,选择在本地以纯算法完成存储与召回。server.py 中注册的 tools/list 是每次会话启动都会被加载进模型上下文的载荷,因此 v0.7.1 将其描述从约 2800 token 压缩到约 2370 token 并加入了 2500 token 的回归上限。资料来源:server.py:1-80

主要工具族包括:

  • 记录族record_decisionrecord_constraint(以及其它 record_*),承担新条目写入。
  • 维护族update_entrydeprecate_entry,用于就地修改或软废弃。
  • 读取族get_project_summary(会话起始注入)、query_decisionssearch_entries 等检索入口。
  • 派生族:与 mirror.pymarkdown_export.py 协同的导出与同步工具。

数据模型:条目(Entry)即一等公民

核心数据单元是 Entry——一个 JSON 文档,对应一个原子化的"事实、决策或约束"。decisions.py 中将每条决策持久化为单独文件,并通过 v0.5.0 引入的"原子写入"(先写临时文件、再 os.replace 替换)保证崩溃中途不会损坏存储。资料来源:decisions.py:1-60

关键字段包括:

字段作用
id条目唯一标识,用于更新与去重
type决策 / 约束 / 笔记 等
content主文本,作为词法检索的源
retrieval_hints2-4 条替代措辞(v0.7.0 引入),同时索引到词法与语义通道
scope约束类条目的生效范围(v0.6.0 用于 scope_guard 钩子)
statusactive / deprecated,由 deprecate_entry 翻转
embedding可选向量,由 embeddings.py 写入
timestamp / origin时间线过滤(v0.7.0)与 origin trust 元数据

origin 字段承载 v0.7.0 加入的"origin trust"机制:来源越可信,回写权重越高。资料来源:decisions.py:60-140

检索通道:词法 + 语义 + 抽象

embeddings.py 抽象了"嵌入后端",v0.9.0 起支持多种后端但仍零依赖;语义向量仅作为补充通道,主要召回仍由词法索引承担,避免冷启动或后端不可用时静默失败。summary.py 中的 get_project_summary 在会话开始时把规则与近期决策摘要注入上下文;v0.9.0 修复了一个关键缺陷——其截断循环原本评估的是原始文本而非已截断文本,导致条目数 ≥ 30 的存储会被静默注入空摘要。资料来源:summary.py:1-90

v0.10.0 引入的 abstentionsupersession-as-ranking 进一步细化召回:当查询与所有条目相关性都低于阈值时,工具应主动放弃回答而非返回噪声匹配;当一条新决策替代旧决策时,旧条目按"被超越"维度降权而非简单弃用。资料来源:decisions.py:140-220

派生视图:Mirror 与 Markdown 投影

存储层之外,context-keeper 维护两类派生视图,二者都遵循"渲染即写入"(render-on-write)原则,每次相关 mutation 都会重新生成。

flowchart LR
  A[record_*/update_entry/deprecate_entry] --> B[(canonical entry files)]
  B --> C[mirror.py watermark sync]
  B --> D[markdown_export.py]
  C --> E[remote mirror store]
  D --> F[DECISIONS.md]
  G[get_project_summary] --> H[session-start context]

mirror.py 是双向水印同步通道,v0.15.0 修复了水印推进导致的数据丢失与打包路径问题;markdown_export.py 实现 v0.8.0 引入的 DECISIONS.md 投影——通过 markdown_export.enabled = true 开启后,每次决策变更都会重写该文件,方便人类与外部工具直读。资料来源:mirror.py:1-100 资料来源:markdown_export.py:1-80

不变量与工具间协作

三个不变约束贯穿所有工具:(1) 写入必须原子;(2) 解析失败的已存在条目必须拒绝写入而非覆盖(v0.5.0 的 corrupt-store protection);(3) 任何写入路径都必须触发 mirror 与 markdown 投影的失效重算。constraints.py 中的 scope 字段被 hooks/scope_guard.py(v0.6.0 引入)消费——一旦 Edit|Write|NotebookEdit 命中约束作用域,对应规则会通过 additionalContext 即时注入,而不仅仅依赖会话起始的一次性简报。资料来源:constraints.py:1-120

这种"会话起始一次性简报 + 编辑即时触发"的双层注入,是 context-keeper 把记忆工具从"被动数据库"升级为"主动守护"的关键设计。

来源:https://github.com/jarmstrong158/context-keeper / 项目说明书

Hooks, Retrieval and Synchronization

context-keeper 是一个零依赖、默认离线的 MCP 记忆工具,围绕三条主线运作:Hook 触发决定上下文何时注入模型对话,检索负责在被查询时定位相关条目,同步/镜像把决策投影为人类可读的载体。三者共用同一个 entry store,保证读写一致。整体架构刻意不采用 Curion 那种"每次 store/recall 都调一次 LLM"的控制器模式(v0.10.0...

章节 相关页面

继续阅读本节完整说明和来源证据。

系统总览

context-keeper 是一个零依赖、默认离线的 MCP 记忆工具,围绕三条主线运作:Hook 触发决定上下文何时注入模型对话,检索负责在被查询时定位相关条目,同步/镜像把决策投影为人类可读的载体。三者共用同一个 entry store,保证读写一致。整体架构刻意不采用 Curion 那种"每次 store/recall 都调一次 LLM"的控制器模式(v0.10.0 设计笔记),因此检索与同步路径均可纯本地完成。

Hook 系统

四个 Hook 分别覆盖"开篇、过程、编辑、压缩"四个时机:

  • session_start:会话首 turn 调用 get_project_summary 注入项目摘要与约束规则;v0.9.0 修复了大仓库(30+ 条目)被截断为空摘要的回归——原因是循环条件评估的是原始文本而非剩余文本,导致静默弹出全部行。资料来源:hooks/session_start.py:1-40
  • scope_guard:在 Edit|Write|NotebookEdit 之后触发(v0.6.0 引入)。一旦被编辑的文件命中某条约束的 scope 字段,该约束立刻通过 additionalContext 注入当前 turn,实现"事后强制"。资料来源:hooks/scope_guard.py:1-60
  • constraint_reinject:在 UserPromptSubmit 上工作,对已被约束保护的规则做中期唤起,与 session_start 的"开篇简报"互补,形成"宣读 + 巡检"双保险。资料来源:hooks/constraint_reinject.py:1-40
  • pre_compact:在上下文压缩前抢救关键决策条目,避免被截断后丢失引用信息。资料来源:hooks/pre_compact.py:1-40

检索机制

检索分两路并行,并支持用户预填的提示词弥补词表失配。

通道输入适用场景
词法检索条目正文 + 标签字面匹配、命令、错误码
语义检索semantic_index.py 产出的向量同义词、措辞变体
retrieval_hints用户预填的 2–4 个替代措辞桥接未来会话"问法-答法"差距

资料来源:semantic_index.py:1-60

v0.7.0 引入 retrieval_hints 后,词法与语义两条通道都会查询该字段,从根本上缓解"换说法就找不到"的问题。资料来源:README.md:80-120

v0.10.0 在此之上加入 abstention + supersession-as-ranking:当新旧版本同时命中时,新版本自然排前、旧版本不被物理删除,仅以"被覆盖"的排序语义降权;若证据不足则主动 abstention,避免硬猜。资料来源:CHANGELOG.md:40-80

同步与镜像

mirror.py 负责把内存中的决策条目投影为人类可读的 DECISIONS.md(v0.8.0,opt-in)。投影采用 render-on-write 策略:每次 record_decision / update_entry / deprecate_entry 都会重生成整份文件,避免漂移;写盘采用 atomic write(先写临时文件再 os.replace,v0.5.0 引入),崩溃也不会污染既有条目。资料来源:mirror.py:1-120

v0.15.0 修复了 mirror 的 watermark 数据丢失与 mirror.py 打包问题,并通过 stdio UTF-8 校验,使 context-keeper-mcp 0.15.0 顺利发布到 PyPI 与 MCP registry。资料来源:CHANGELOG.md:1-40

数据流总览

flowchart LR
    A[Agent 操作] -->|PostToolUse| B[scope_guard]
    A -->|UserPromptSubmit| C[constraint_reinject]
    A -->|SessionStart| D[session_start]
    A -->|PreCompact| E[pre_compact]
    B --> F[(decision store)]
    C --> F
    F -->|embed| G[semantic_index]
    F -->|record_*| H[mirror.py]
    H -->|atomic write| I[DECISIONS.md]
    G --> J[词法 + 语义 + hints 检索]

来源:https://github.com/jarmstrong158/context-keeper / 项目说明书

Configuration, Deployment and Evaluation

context-keeper 是一个零依赖、默认离线的 MCP(Model Context Protocol)内存服务。整个项目的配置、部署与质量评估都围绕"小而稳"这一目标展开:交付物通过 PyPI 与 MCP 注册中心分发,打包脚本统一管理可分发的 bundle,而 token 预算等关键约束则通过回归测试固化为不变量。本页说明打包元数据、构建脚本与运行时配置约束之间的...

章节 相关页面

继续阅读本节完整说明和来源证据。

配置、部署与评估

概述

context-keeper 是一个零依赖、默认离线的 MCP(Model Context Protocol)内存服务。整个项目的配置、部署与质量评估都围绕"小而稳"这一目标展开:交付物通过 PyPI 与 MCP 注册中心分发,打包脚本统一管理可分发的 bundle,而 token 预算等关键约束则通过回归测试固化为不变量。本页说明打包元数据、构建脚本与运行时配置约束之间的协同关系。

打包与元数据配置

项目在多个注册中心保持一致的元数据描述,便于客户端在不同目录发现并安装:

v0.15.0 修复了 stdio 的 UTF-8 问题、镜像 watermark 的数据丢失问题以及 mirror.py 的打包问题,并对描述做了裁剪以通过注册中心校验。这些改动共同表明:打包元数据不是孤立文件,而是端到端部署链上的约束点。

构建脚本与发布流程

两个辅助脚本把源码变成可分发资产:

发布流程可概括为:先用 pyproject.toml 构建并上传到 PyPI,再通过构建脚本生成 MCPB bundle,最后把 manifest 与 server 描述同步到 MCP 与 Glama 注册中心。任一环节的不一致——例如版本号、描述字段长度——都会让注册中心校验失败,v0.15.0 的"描述裁剪"正是为此而做的修复。

运行时约束与回归评估

部署之上,context-keeper 通过若干硬性不变量守护运行质量:

  • Token 预算不变量:每次会话开始时,MCP 客户端会把完整的 tools/list 注入到模型上下文。schema 描述从约 2800 token 压缩到约 2370 token,并加入 2500 token 的回归测试上限,防止后续字段无序增长。资料来源:server.json:1-40
  • 零依赖、离线优先:与同类 MCP 内存工具"每次存取都调用一次 LLM 控制器"的路线不同,context-keeper 刻意保持无第三方依赖,避免引入额外网络请求与运行时成本。资料来源:pyproject.toml:1-40
  • 数据完整性护栏:条目写入采用临时文件 + os.replace 的原子替换;任何无法解析的已存在条目都会让 record_*update_entrydeprecate_entry 拒绝写入,把损坏的存储挡在写入路径之外。
阶段关键文件作用
打包元数据pyproject.toml / server.json / mcpb/manifest.json / glama.json声明 PyPI、MCP、Glama 三个分发通道
构建脚本scripts/build-mcpb.sh / scripts/make_placeholder_icon.py产出可安装 bundle 与图标
运行时评估token 预算回归测试 + 原子写入 + 损坏拒绝守住 schema 大小与存储完整性

整体来看,配置与部署层决定"用户能不能装上",而回归与不变量决定"装上之后会不会退化"。两者由脚本串联、由回归测试闭环,构成 context-keeper 的最小可行发布体系。

来源:https://github.com/jarmstrong158/context-keeper / 项目说明书

失败模式与踩坑日记

保留 Doramagic 在发现、验证和编译中沉淀的项目专属风险,不把社区讨论只当作装饰信息。

medium 可能修改宿主 AI 配置

安装可能改变本机 AI 工具行为,用户需要知道写入位置和回滚方法。

medium 能力判断依赖假设

假设不成立时,用户拿不到承诺的能力。

medium 维护活跃度未知

新项目、停更项目和活跃项目会被混在一起,推荐信任度下降。

medium 存在评分风险

风险会影响是否适合普通用户安装。

Pitfall Log / 踩坑日志

项目:jarmstrong158/context-keeper

摘要:发现 7 个潜在踩坑项,其中 0 个为 high/blocking;最高优先级:配置坑 - 可能修改宿主 AI 配置。

1. 配置坑 · 可能修改宿主 AI 配置

  • 严重度:medium
  • 证据强度:source_linked
  • 发现:项目面向 Claude/Cursor/Codex/Gemini/OpenCode 等宿主,或安装命令涉及用户配置目录。
  • 对用户的影响:安装可能改变本机 AI 工具行为,用户需要知道写入位置和回滚方法。
  • 证据:capability.host_targets | https://github.com/jarmstrong158/context-keeper | host_targets=mcp_host, claude

2. 能力坑 · 能力判断依赖假设

  • 严重度:medium
  • 证据强度:source_linked
  • 发现:README/documentation is current enough for a first validation pass.
  • 对用户的影响:假设不成立时,用户拿不到承诺的能力。
  • 证据:capability.assumptions | https://github.com/jarmstrong158/context-keeper | README/documentation is current enough for a first validation pass.

3. 维护坑 · 维护活跃度未知

  • 严重度:medium
  • 证据强度:source_linked
  • 发现:未记录 last_activity_observed。
  • 对用户的影响:新项目、停更项目和活跃项目会被混在一起,推荐信任度下降。
  • 证据:evidence.maintainer_signals | https://github.com/jarmstrong158/context-keeper | last_activity_observed missing
  • 严重度:medium
  • 证据强度:source_linked
  • 发现:no_demo
  • 证据:downstream_validation.risk_items | https://github.com/jarmstrong158/context-keeper | no_demo; severity=medium

5. 安全/权限坑 · 存在评分风险

  • 严重度:medium
  • 证据强度:source_linked
  • 发现:no_demo
  • 对用户的影响:风险会影响是否适合普通用户安装。
  • 证据:risks.scoring_risks | https://github.com/jarmstrong158/context-keeper | no_demo; severity=medium

6. 维护坑 · issue/PR 响应质量未知

  • 严重度:low
  • 证据强度:source_linked
  • 发现:issue_or_pr_quality=unknown。
  • 对用户的影响:用户无法判断遇到问题后是否有人维护。
  • 证据:evidence.maintainer_signals | https://github.com/jarmstrong158/context-keeper | issue_or_pr_quality=unknown

7. 维护坑 · 发布节奏不明确

  • 严重度:low
  • 证据强度:source_linked
  • 发现:release_recency=unknown。
  • 对用户的影响:安装命令和文档可能落后于代码,用户踩坑概率升高。
  • 证据:evidence.maintainer_signals | https://github.com/jarmstrong158/context-keeper | release_recency=unknown

来源:Doramagic 发现、验证与编译记录