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

生成时间：2026-07-26 01:04:42 UTC

## 目录

- [Overview and Architecture](#page-1)
- [MCP Tools and Data Model](#page-2)
- [Hooks, Retrieval and Synchronization](#page-3)
- [Configuration, Deployment and Evaluation](#page-4)

<a id='page-1'></a>

## Overview and Architecture

### 相关页面

相关主题：[MCP Tools and Data Model](#page-2), [Hooks, Retrieval and Synchronization](#page-3)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [server.py](https://github.com/jarmstrong158/context-keeper/blob/main/server.py)
- [README.md](https://github.com/jarmstrong158/context-keeper/blob/main/README.md)
- [pyproject.toml](https://github.com/jarmstrong158/context-keeper/blob/main/pyproject.toml)
- [CLAUDE.md](https://github.com/jarmstrong158/context-keeper/blob/main/CLAUDE.md)
- [hooks/scope_guard.py](https://github.com/jarmstrong158/context-keeper/blob/main/hooks/scope_guard.py)
- [context_keeper/store.py](https://github.com/jarmstrong158/context-keeper/blob/main/context_keeper/store.py)
- [mirror.py](https://github.com/jarmstrong158/context-keeper/blob/main/mirror.py)
</details>

# Overview and Architecture

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

## 设计目标与定位

context-keeper 的核心目标是为 agent 提供一份可在多次会话间复用的"项目记忆"，使决策不再随对话窗口的滚动而丢失。它在 v0.10.0 中明确选择了与同类工具 [Curion](https://github.com/geanatz/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.py` | PostToolUse 钩子，按 scope 即时注入约束 |
| 投影层 | `mirror.py`、`markdown_export` | 决策库到 `DECISIONS.md` 的 render-on-write |

`server.py` 是入口点，对外暴露 `record_decision`、`update_entry`、`deprecate_entry`、`get_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_entry`、`deprecate_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` 提供：它监听 `Edit`、`Write`、`NotebookEdit` 三类 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 的完整数据通路：

```mermaid
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 注入
```

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

---

<a id='page-2'></a>

## MCP Tools and Data Model

### 相关页面

相关主题：[Overview and Architecture](#page-1), [Hooks, Retrieval and Synchronization](#page-3), [Configuration, Deployment and Evaluation](#page-4)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [server.py](https://github.com/jarmstrong158/context-keeper/blob/main/server.py)
- [decisions.py](https://github.com/jarmstrong158/context-keeper/blob/main/decisions.py)
- [summary.py](https://github.com/jarmstrong158/context-keeper/blob/main/summary.py)
- [embeddings.py](https://github.com/jarmstrong158/context-keeper/blob/main/embeddings.py)
- [mirror.py](https://github.com/jarmstrong158/context-keeper/blob/main/mirror.py)
- [markdown_export.py](https://github.com/jarmstrong158/context-keeper/blob/main/markdown_export.py)
- [constraints.py](https://github.com/jarmstrong158/context-keeper/blob/main/constraints.py)
</details>

# MCP Tools and Data Model

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

## 设计目标与工具总览

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

主要工具族包括：

- **记录族**：`record_decision`、`record_constraint`（以及其它 `record_*`），承担新条目写入。
- **维护族**：`update_entry`、`deprecate_entry`，用于就地修改或软废弃。
- **读取族**：`get_project_summary`（会话起始注入）、`query_decisions`、`search_entries` 等检索入口。
- **派生族**：与 `mirror.py`、`markdown_export.py` 协同的导出与同步工具。

## 数据模型：条目（Entry）即一等公民

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

关键字段包括：

| 字段 | 作用 |
|---|---|
| `id` | 条目唯一标识，用于更新与去重 |
| `type` | 决策 / 约束 / 笔记 等 |
| `content` | 主文本，作为词法检索的源 |
| `retrieval_hints` | 2-4 条替代措辞（v0.7.0 引入），同时索引到词法与语义通道 |
| `scope` | 约束类条目的生效范围（v0.6.0 用于 `scope_guard` 钩子） |
| `status` | `active` / `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 引入的 **abstention** 与 **supersession-as-ranking** 进一步细化召回：当查询与所有条目相关性都低于阈值时，工具应主动放弃回答而非返回噪声匹配；当一条新决策替代旧决策时，旧条目按"被超越"维度降权而非简单弃用。资料来源：[decisions.py:140-220]()

## 派生视图：Mirror 与 Markdown 投影

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

```mermaid
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 把记忆工具从"被动数据库"升级为"主动守护"的关键设计。

---

<a id='page-3'></a>

## Hooks, Retrieval and Synchronization

### 相关页面

相关主题：[MCP Tools and Data Model](#page-2), [Configuration, Deployment and Evaluation](#page-4)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [semantic_index.py](https://github.com/jarmstrong158/context-keeper/blob/main/semantic_index.py)
- [mirror.py](https://github.com/jarmstrong158/context-keeper/blob/main/mirror.py)
- [hooks/session_start.py](https://github.com/jarmstrong158/context-keeper/blob/main/hooks/session_start.py)
- [hooks/scope_guard.py](https://github.com/jarmstrong158/context-keeper/blob/main/hooks/scope_guard.py)
- [hooks/constraint_reinject.py](https://github.com/jarmstrong158/context-keeper/blob/main/hooks/constraint_reinject.py)
- [hooks/pre_compact.py](https://github.com/jarmstrong158/context-keeper/blob/main/hooks/pre_compact.py)
</details>

# Hooks, Retrieval and Synchronization

## 系统总览

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]()`

## 数据流总览

```mermaid
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 检索]

---

<a id='page-4'></a>

## Configuration, Deployment and Evaluation

### 相关页面

相关主题：[Overview and Architecture](#page-1), [MCP Tools and Data Model](#page-2), [Hooks, Retrieval and Synchronization](#page-3)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [pyproject.toml](https://github.com/jarmstrong158/context-keeper/blob/main/pyproject.toml)
- [mcpb/manifest.json](https://github.com/jarmstrong158/context-keeper/blob/main/mcpb/manifest.json)
- [server.json](https://github.com/jarmstrong158/context-keeper/blob/main/server.json)
- [glama.json](https://github.com/jarmstrong158/context-keeper/blob/main/glama.json)
- [scripts/build-mcpb.sh](https://github.com/jarmstrong158/context-keeper/blob/main/scripts/build-mcpb.sh)
- [scripts/make_placeholder_icon.py](https://github.com/jarmstrong158/context-keeper/blob/main/scripts/make_placeholder_icon.py)
</details>

# 配置、部署与评估

## 概述

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

## 打包与元数据配置

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

- `pyproject.toml` 定义 Python 包元数据、入口点与可选依赖，用于发布到 PyPI 的 `context-keeper-mcp` 包。资料来源：[pyproject.toml:1-40]()
- `server.json` 是 MCP 注册中心的服务声明，描述 stdio 传输、入口命令以及能力列表。资料来源：[server.json:1-40]()
- `mcpb/manifest.json` 是 MCPB（MCP Bundle）的清单，声明 bundle 名称、版本、打包文件清单与图标。资料来源：[mcpb/manifest.json:1-40]()
- `glama.json` 提供给 Glama 注册中心使用的元数据镜像，使第三方目录能够同步。资料来源：[glama.json:1-40]()

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

## 构建脚本与发布流程

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

- `scripts/build-mcpb.sh` 调用必要工具把 `mcpb/` 目录打包成可安装的 MCPB 归档，是发布到 MCP 注册中心前的最后一步。资料来源：[scripts/build-mcpb.sh:1-40]()
- `scripts/make_placeholder_icon.py` 生成打包时所需的占位图标，避免在没有设计资源的情况下阻塞发布流程。资料来源：[scripts/make_placeholder_icon.py:1-40]()

发布流程可概括为：先用 `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_entry`、`deprecate_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 的最小可行发布体系。

---

<!-- evidence_pipeline_checked: true -->
<!-- evidence_injected: true -->

---

## Doramagic 踩坑日志

项目：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

<!-- canonical_name: jarmstrong158/context-keeper; human_manual_source: deepwiki_human_wiki -->
