Doramagic 项目包 · 项目说明书

nlm-memory 项目

本地优先的非线性记忆操作系统,面向 AI 操作者。统一索引打通 Claude Code、Codex、Cursor、Windsurf、Hermes、OpenCode、Aider、pi 等工具,并提供可编辑的时间线。

Overview & System Architecture

nlm-memory 是一个面向 AI 算力使用者的"本地优先(local-first)非线性记忆操作系统"。从 package.json 的描述与关键字集合可以确认:它被定位为 AI / MCP / Claude-Code / Codex / Hermes / 本地优先 / 召回 / 会话记忆 等交叉领域的基础设施,遵循 Apache-2.0 协议,并以 nlm CLI ...

章节 相关页面

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

章节 组合根与 CLI

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

章节 召回与改写

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

章节 Hook 与指针块

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

目的与定位

nlm-memory 是一个面向 AI 算力使用者的"本地优先(local-first)非线性记忆操作系统"。从 package.json 的描述与关键字集合可以确认:它被定位为 AI / MCP / Claude-Code / Codex / Hermes / 本地优先 / 召回 / 会话记忆 等交叉领域的基础设施,遵循 Apache-2.0 协议,并以 nlm CLI 作为唯一对外入口("bin": { "nlm": "dist/cli/nlm.js" })。整个系统以"会话 → 事实 → 代码范例"为主线,提供可被 Agent 即时调用的记忆通道 package.json:2-3

总体架构

系统由四层组成:CLI 组合根、HTTP/MCP 传输层、领域核心(Hexagonal Ports & Adapters)、以及基于 Vite + React 的 UI 单页应用。所有具体实现都从属于 core/ 内的端口(Port),CLI 文件是唯一同时知晓 SqliteStoragePgStorageOllamaClientHonoMcpServer 的"组合根",替换后端时只需要修改该文件 src/cli/nlm.ts:1-45

flowchart LR
  A[AI Agent / Claude Code / Codex] -->|MCP stdio| B(CLI: src/cli/nlm.ts)
  A -->|HTTP| C[Hono: src/http/app.ts]
  B --> C
  C --> D[Recall Service]
  C --> E[Fact Recall Service]
  C --> F[Scheduler + Classifier]
  D --> G[Rewrite Prompt]
  E --> H[Related Facts]
  D --> I[Pointer Block]
  F --> J[Citation Detect]
  C --> K[(Sqlite / PgStorage)]
  C --> L[Provider Registry]
  M[UI: Vite + React] --> C

资料来源:src/cli/nlm.ts:14-23src/core/recall/rewrite-prompt.ts:1-15src/core/hook/pointer-block.ts:1-30

核心模块组成

组合根与 CLI

nlm CLI 同时承担 startmigraterecallmcpsetupinstalluninstallhook install/uninstallconnect/disconnectdigest 等十余个子命令 src/cli/nlm.ts:30-46。它内嵌 Hono 的 serve 与 MCP StdioServerTransport,因此"用同一个 Node 进程既可以服务本地 Web UI,又可以以 stdio 形式接入 Claude-Code / Codex 客户端",无需拆分多个二进制。

召回与改写

rewrite-prompt.ts 把模糊自然语言查询拆分为 keywordQuery(喂给 FTS5 BM25)与 semanticQuery(喂给向量嵌入)两个版本;改写失败时解析器会抛错,调用方"失败开放"地退回原始查询,避免把错误改写结果污染后续评分 src/core/recall/rewrite-prompt.ts:1-25related-facts.ts 在召回命中之上再选 3–5 条高置信度事实(按确认次数排序),阈值可由 NLM_HOOK_FACT_LIMIT 等环境变量调优;任一步骤异常都会返回空数组,让指针块优雅降级到"仅会话"模式 src/core/recall/related-facts.ts:1-45

Hook 与指针块

pointer-block.ts 渲染 Hook 注入到对话上下文的"指针块"——只包含 ID + 标签,不复制会话正文;这是"教学 Tool 清单"的唯一跨运行时分发面,新装用户不需要手动改 prompt 即可了解 recall_sessions / recall_facts / recall_code / get_fact_history 四个工具 src/core/hook/pointer-block.ts:1-32citation-detect.ts 通过 tool_useprose 两条信号通道判定 Agent 是否真正引用了被召回的 ID,是未来学习式重排模型的训练样本来源 src/core/hook/citation-detect.ts:1-20

存储与提供者抽象

src/core/storage/ 同时提供 SqliteCodeExemplarStorePgCodeExemplarStore 两种适配器:主键统一由 sha256(installScope|repo|codeHash|outcome)[:16] 派生,保证"同段代码在同一作用域内只占一行" src/core/storage/sqlite-code-exemplar-store.ts:1-35;PG 适配器使用 pgvector 索引并把 retired_at 字段纳入 schema(修复记录见 v0.14.1)。provider-models.ts 把 LLM 提供方按"发现方式"区分:Ollama 调 /api/tags、OpenAI 系调 /models、DeepSeek/Anthropic 因无稳定列表端点而采用硬编码 src/core/providers/provider-models.ts:1-45registries.ts 暴露的 SourceKindProviderKind 联合类型就是 UI 表单的合法取值集合 src/ui/lib/registries.ts:1-30

Web UI

UI 使用 Vite + React SPA 形态("build:ui": "vite build --config src/ui/vite.config.ts"),并通过 React 端口的 <Drawer><Pagination><Skeleton> 等基础组件对外提供一致的交互 src/ui/components/README.md:1-30Pulse 页展示运行时分组的会话与主题热度 src/ui/pages/Pulse.tsx:1-30Recall 页把"会话召回 / 事实召回"的命中率、按来源、热门查询、热门主体并列展示,用于区分"采用度问题"与"语料覆盖度问题" src/ui/pages/Recall.tsx:1-30Thread 页提供实体筛选与分页浏览 src/ui/pages/Thread.tsx:1-25StubPage 用于标记尚未从旧 Astro UI 移植完成的页面,集中跟踪于 NocoDB #95 src/ui/pages/Stub.tsx:1-5

近期演进与社区焦点

v0.20.0 起,调度器在摄入阶段自动把超大会话切片(PR #341);v0.19.0 / v0.18.0 为分类器补齐了 JSON 重试 + 分块容错以及分级分类与超大恢复;v0.16.0 / v0.15.0 引入了被动式 recall_code 与基于已提交会话的"代码范例自动捕获"两阶段闭环;v0.14.x 进一步把范例存储落到 Postgres 后端并在 HTTP /mcp 通道补线;v0.13.0 则增加了 doctor / verify / codex-repair 安装自检与每日备份。这意味着当前主线能力已从"会话检索"扩展为"事实 + 代码范例 + 安装自愈"的复合记忆体。资料来源:社区发布说明

See Also

资料来源:src/cli/nlm.ts:14-23src/core/recall/rewrite-prompt.ts:1-15src/core/hook/pointer-block.ts:1-30

Runtime Adapters & Session Ingest

Runtime Adapters 是 nlm-memory 把不同 AI 编程代理(Claude Code、Codex、Hermes、Pi 等)的会话转录接入本地记忆库的适配层;Session Ingest 负责把适配器解析出的原始转录归一化为内部 Session 模型,并执行分类、嵌入、超限切分与代码示例抽取等下游处理。整个模块是事实写入路径的起点,其稳定性直接决定后续 ...

章节 相关页面

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

概览

Runtime Adapters 是 nlm-memory 把不同 AI 编程代理(Claude Code、Codex、Hermes、Pi 等)的会话转录接入本地记忆库的适配层;Session Ingest 负责把适配器解析出的原始转录归一化为内部 Session 模型,并执行分类、嵌入、超限切分与代码示例抽取等下游处理。整个模块是事实写入路径的起点,其稳定性直接决定后续 Recall、Fact Recall 以及代码示例召回的质量。本项目版本 0.20.0(package.json)正是在该管道上增加了调度层面的自动切分能力。

资料来源:src/cli/nlm.ts:1-30 | package.json:1-15

适配器种类(Source Kinds)

SourceKind 联合类型集中声明系统所支持的运行时后端;UI 注册表与 daemon 契约复用同一份定义,避免类型漂移。

SourceKind接入方式说明
claude-codeMCP stdioAnthropic Claude Code CLI
codexCodex 插件市场OpenAI Codex CLI
hermes独立插件Hermes Agent 配套
piJSONL 解析Pi 编程代理
jsonl-generic文件 watcher通用 JSONL 转录
webhookHTTP POST远程代理主动推送

每条 Source 记录携带 runtimeLabelparseConfigenabled 三个核心字段;parseConfig 决定具体解析器从何种结构中抽取对话轮次和时间戳。HTTP 列表接口仅返回 hasToken: boolean,明文 token 仅在 insert / regenerate 时一次性回显,避免长期泄露。

资料来源:src/ui/lib/registries.ts:1-40 | src/ui/lib/registries.ts:50-80

CLI 与安装路径

CLI 是 Runtime Adapter 的唯一组合根(composition root),所有具体后端的接线与排错命令均集中于 src/cli/nlm.ts

  • nlm connect claude-code — 在 ~/.mcp.json 写入 MCP server block;
  • nlm connect codex — 安装 Codex 插件市场包;
  • nlm disconnect claude-code / nlm disconnect codex — 卸载对应接线;
  • nlm doctor — 同时探测 Claude Code 与 Codex 的 MCP 接线状态,并扫描 @nlm-memory-ts 残留的过期 trust 条目;
  • nlm mcp — 以 stdio 方式运行 MCP server,供宿主代理通过 MCP 协议调用 Recall / Fact Recall 工具;
  • nlm hook install — 安装 Claude Code 的 recall 钩子(shadow 模式)。

doctor 报告一并返回 daemon 可达性、~/.nlm/.env 是否存在以及是否设置 NLM_MCP_TOKEN,便于安装失败时定位根因。

资料来源:src/cli/nlm.ts:30-80 | src/cli/nlm.ts:80-120

Session Ingest 管道

Session Ingest 是写入侧的主管道,其关键节点与发布节奏紧密相关:

flowchart LR
  A[Runtime 转录文件] --> B[Adapter 解析]
  B --> C[归一化 Session]
  C --> D{是否超限?}
  D -- 否 --> E[Classifier 分类]
  D -- 是 --> F[Auto-chunk 切分]
  F --> E
  E --> G[Embedder + Storage]
  G --> H[(SQLite / Postgres)]
  • 解析:Adapter 依据 parseConfig 把 JSONL 转录切分为 user / assistant / tool_use 块;
  • 切分v0.20.0 起 scheduler 在 ingest 入口自动对超大会话做 chunk 处理,避免后续 LLM 分类与嵌入触发 token 上限;
  • 分类v0.18.0 引入的分层分类器处理超长会话,并具备 JSON 弹性(v0.19.0:重试 + per-chunk 容错);
  • 代码示例抽取v0.15.0 起,落地会话自动触发 Phase 1 代码示例捕获,v0.16.0 增加被动召回(Phase 2);
  • 持久化:分类与嵌入结果通过 SqliteStoragePgStorage 持久化,并衍生 code_exemplar 行。

会话落地后还参与召回闭环:RecallService 在召回时合并 PointerBlock 中的"已知事实"(Spec G.2)与代码示例,被 citation-detect 标记为"已被代理引用",构成训练数据回流。

资料来源:src/core/recall/recall-service.ts:1-40 | src/core/storage/sqlite-code-exemplar-store.ts:1-40 | src/core/storage/pg-code-exemplar-store.ts:1-30 | src/core/hook/pointer-block.ts:1-50 | src/core/hook/citation-detect.ts:1-40

运行态可见性(Pulse)

UI 的 Pulse 页按 Runtime 维度聚合 ingest 后的会话指标:本周新增、上周新增、累计会话数、最近会话时间,以及该 runtime 下最常出现的实体主题(Topics,cap 20)。运维者可凭此一眼识别某运行时是否在持续接入、是否退化。

资料来源:src/ui/pages/Pulse.tsx:1-50

失败模式与常见问题

  • MCP 接线缺失nlm doctor 会同时报告 claude-code.mcpConfiguredcodex.mcpConfigured;任一项为 false 即意味着 ingest 不会自动发生,需先执行 nlm connect ...
  • 过期 trust 条目:Codex 注册表中若残留 @nlm-memory-ts 字符串,doctor 会标记为 staleNlmMemoryTs,防止旧 plugin 接管新版本。
  • 超限会话v0.18.0 之前,分类器在长会话上可能静默失败;v0.20.0 后由 scheduler 在 ingest 阶段提前切分,无需手工干预。
  • 来源 Token 泄露:HTTP 列表接口只返回 hasToken: boolean;调用 insert / regenerate 才会一次性返回明文 token,避免长期泄露。
  • Storage 后端差异SqliteStoragePgStoragecode_exemplar 表结构上完全一致,但 PG 端需要在迁移中显式声明 retired_at 列(v0.14.1 修复)。

资料来源:src/cli/nlm.ts:50-90 | src/ui/lib/registries.ts:30-60

See Also

  • Recall Service 与 Citation 检测:src/core/recall/recall-service.ts
  • PointerBlock 与召回注入:src/core/hook/pointer-block.ts
  • Pulse 页 UI:src/ui/pages/Pulse.tsx
  • v0.20.0 Release Notes(auto-chunk oversized sessions on ingest):https://github.com/pbmagnet4/nlm-memory/releases/tag/v0.20.0
  • v0.18.0 Release Notes(hierarchical classification + oversized-session recovery):https://github.com/pbmagnet4/nlm-memory/releases/tag/v0.18.0

资料来源:src/cli/nlm.ts:1-30 | package.json:1-15

Recall, MCP Tools & REST API

nlm-memory 通过 RecallService 把本地存储、FTS5 关键词检索、向量语义、改写器、相关事实/示例选择器统一为一个无副作用的 use case,对外同时为 MCP 工具、HTTP REST API 与 hook 注入提供召回能力。RecallService 显式声明只依赖端口(SessionStore、LLMClient、FactStore、Code...

章节 相关页面

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

架构总览

nlm-memory 通过 RecallService 把本地存储、FTS5 关键词检索、向量语义、改写器、相关事实/示例选择器统一为一个无副作用的 use case,对外同时为 MCP 工具、HTTP REST API 与 hook 注入提供召回能力。RecallService 显式声明只依赖端口(SessionStoreLLMClientFactStoreCodeExemplarStoreCodeEmbedder),不引入框架或数据库,因此测试可以用 fake 适配器替换实现 资料来源:src/core/recall/recall-service.ts:1-15

整体数据流如下:

flowchart LR
  U[User prompt] --> H[classifyPrompt]
  H -->|evaluate| A[POST /api/recall]
  H -->|generative| X[skip]
  A --> R[RecallService.search]
  R --> RW[rewrite-prompt]
  R --> KW[Keyword match]
  R --> SM[Semantic embed]
  R --> RF[pickRelatedFacts]
  R --> RX[pickRelatedExemplars]
  R --> CIT[detectCitations]
  R --> PB[formatPointerBlock]
  PB --> T[LLM Context]
  T --> MCP[MCP tools]

RecallService 与召回路径

RecallService.search 接收 RecallQuery,依次执行:模式选择(keyword / semantic / hybrid)、limit 截断、可选实体/类型过滤、查询改写、关键词打分、向量召回、reranker 合并与元数据 tiebreak 资料来源:src/core/recall/recall-service.ts:48-89

查询改写rewrite-prompt.ts 把模糊自然语言查询("那个 pgvector 的事情")改写成 keyword + semantic 两种形式;解析失败或形状异常抛 LLMUnreachableError,由 search() 失败开放到原始 query,避免污染下游打分 资料来源:src/core/recall/rewrite-prompt.ts:1-50

相关事实/示例:当 withRelatedFacts 启用时,pickRelatedFacts 收集 top-N 命中涉及的实体,从 FactStore 抓取非废弃事实并要求至少 2 个 session 共同佐证,排序后取 3–5 条注入 pointer block;环境变量 NLM_HOOK_FACT_LIMITNLM_HOOK_FACT_MIN_CORROBORATIONNLM_HOOK_FACT_MIN_CONFIDENCE 可覆盖默认 5/2/0.7 资料来源:src/core/recall/related-facts.ts:1-30。代码示例召回(v0.16.0 Phase 2)走 pickRelatedExemplars,需 exemplarStore + codeEmbedder + installScope 三件套同时就位 资料来源:src/core/recall/recall-service.ts:30-50

引用检测detectCitations 识别助手回合引用了哪些被召回的 session ID,作为未来学习 reranker 的训练数据;tool_use 通道是模型调用 get_session/recall_facts/get_fact_history/recall_sessions 等 MCP 工具时携带 ID 的强信号,prose 通道在响应文本中匹配 ID 子串 资料来源:src/core/hook/citation-detect.ts:1-30

MCP 工具集与 REST API

nlm connect 系列命令把 nlm-memory 注册为 Claude Code、Codex、Pi 等运行时的 MCP server。pointer-block.ts 在每次召回注入的 prompt 末尾强制列出 NLM MCP 工具清单——这是新装机用户唯一不需要编辑配置就能学到的工具目录 资料来源:src/core/hook/pointer-block.ts:1-30

核心 MCP 工具:

  • get_session — 取回完整 session 正文,模型需引用某次会话
  • recall_sessions — 跨会话关键词/语义检索,通用回忆问题
  • recall_facts — 结构化事实查询,例如"我对 X 偏好 Y 吗"
  • get_fact_history — 事实演变轨迹,同一事实需溯源
  • recall_code — 代码示例向量检索,编码任务前查参考实现

recall_code 命令与 /mcp transport 在 v0.14.0 / v0.13.1 先后接通,HTTP 路径与 stdio 路径在 mcpDeps 上保持完全一致的依赖注入 资料来源:src/cli/nlm.ts:1-100

CLI 启动 nlm start 后,createApphttp://localhost:3940 同时挂载 POST /mcp(token 守门)与 POST /api/recall 路径;POST /api/recall 接收 mode 查询参数(keyword / semantic / hybrid),由 RecallService 处理后回 JSON 资料来源:src/cli/nlm.ts:1-100。Hook 侧 classifyPrompt 是保守的生成式排除器,仅识别 write/draft/create/... 等高确定性开头跳回 recall;否则一律评估查询 资料来源:src/core/hook/gate.ts:1-30。Pi 运行时由 nlm connect pi 把扩展挂到 ~/.pi/agent/settings.json,每次 prompt 先打 localhost:3940/api/recall?mode=keyword 资料来源:nlm/README.md:1-30

UI 端 Recall.tsx/api/recall-stats 拉来的 hit-rate、按来源分布与 top queries 渲染为"采用率"面板,与"覆盖率"并列以区分是没人用还是查不到 资料来源:src/ui/pages/Recall.tsx:1-30

故障模式与限制

  • 改写器不可达:模型挂了或返回非 JSON → 抛 LLMUnreachableErrorsearch() 失败开放到原始 query,不影响 recall 主路径 资料来源:src/core/recall/rewrite-prompt.ts:1-50
  • 事实/示例选择器异常pickRelatedFacts / pickRelatedExemplars 任何错误一律返回空数组,pointer block 退化为仅 session 列表 资料来源:src/core/recall/related-facts.ts:1-30
  • Citation 误报MIN_ID_LEN = 6 防止短 ID 与 prose 误匹配;tool_use 通道几乎无假阳性 资料来源:src/core/hook/citation-detect.ts:1-30
  • Hook 误判 generative:高确定性反例会错误跳过 recall,是 gate.ts 设计上要消除的最差失败模式 资料来源:src/core/hook/gate.ts:1-30

See Also

  • Code Exemplars & Recall Lane
  • Session Ingest & Hooks
  • Local Daemon & Installation

来源:https://github.com/pbmagnet4/nlm-memory / 项目说明书

Storage Backends, Schema & Migrations

nlm-memory 是一个本地优先(local-first)的非线性记忆操作系统(v0.20.0),其存储层采用端口-适配器(Ports & Adapters)模式,将具体数据库实现与上层业务逻辑解耦。整个栈的唯一组合根(composition root)是 src/cli/nlm.ts,它负责把 SqliteSessionStore、OllamaClient、Hono、...

章节 相关页面

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

章节 会话存储(SessionStore)

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

章节 事实存储(FactStore)

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

章节 信号存储(SignalStore)

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

存储后端、Schema 与迁移

概述

nlm-memory 是一个本地优先(local-first)的非线性记忆操作系统(v0.20.0),其存储层采用端口-适配器(Ports & Adapters)模式,将具体数据库实现与上层业务逻辑解耦。整个栈的唯一组合根(composition root)是 src/cli/nlm.ts,它负责把 SqliteSessionStoreOllamaClientHonoMcpServer 等具体实现装配起来;其他模块只依赖端口(ports)接口。资料来源:src/cli/nlm.ts:1-19

存储层提供两个可互换后端:

后端引擎适用场景关键依赖
SQLite(默认规范库)better-sqlite3 + sqlite-vec本地单机、嵌入式安装better-sqlite3@^12.10.0, sqlite-vec@^0.1.6
PostgreSQLpg + pgvector团队共享、需要 pgvector 扩展pg@^8.21.0, pgvector@^0.3.0

资料来源:package.json:1-90

发布产物 files 数组中包含 distmigrationspluginnlmassets 与许可文件,表明迁移脚本与 CLI 同包发布。资料来源:package.json:30-40

存储后端架构

nlm-memory 的双后端设计源于其本地优先定位,同时保留向集中式部署升级的路径。src/cli/nlm.tsdoctor 子命令会根据运行时类型分发修复逻辑:

if (storage instanceof PgStorage) { /* PG 路径 */ } else { /* SQLite 路径 */ }

资料来源:src/cli/nlm.ts:1-90

CLI 还显式导入并调用以下存储子系统,分别承担不同职责:

  • SqliteStorage / PgStorage — 协议实现(位于 src/core/storage/,未在本文检索范围内)
  • applyPendingRestorestageRestore(来自 src/core/storage/db-restore.ts)— 数据库恢复管线
  • listBackupDatesresolveBackuprunRollingBackup(来自 src/core/storage/backup-rotation.ts)— 滚动备份与轮转

资料来源:src/cli/nlm.ts:30-45

下图展示了请求从 CLI 经过应用层到具体后端实现的典型路径:

flowchart LR
  CLI[nlm CLI] --> App[Hono HTTP / MCP]
  App -->|端口| Storage[Storage Port]
  Storage --> SQLite[(SQLite + sqlite-vec)]
  Storage --> PG[(PostgreSQL + pgvector)]
  SQLite --> Backup[db-restore + backup-rotation]
  PG --> Backup
  Backup --> Migrations[migrations/ 目录]

Schema 与领域存储

存储后端承载多类领域对象,每一类都对应独立存储端口与具体实现。已知的领域存储包括:

会话存储(SessionStore)

SqliteSessionStore(推断自 src/cli/nlm.ts:32SqliteSessionStore 注释)与对应 PG 实现承载,记录 AI 运行时的完整会话。

事实存储(FactStore)

用于结构化事实(subject/predicate/value),供 agent 在任务中途拉取。v0.14.1 的 fix(pg): add facts.retired_at to the PG schema 显示事实表具有退役时间字段,PG 与 SQLite 模式需同步演进。资料来源:社区发布说明 v0.14.1

信号存储(SignalStore)

支撑主题(topic)与运行时(runtime)信号聚合,支撑 Pulse 页面上的「This week / Last week / Total sessions / Last session」指标。资料来源:src/ui/pages/Pulse.tsx:1-40

代码样本存储(CodeExemplarStore)

存储从已提交会话中自动捕获的代码样本。SQLite 与 PG 两侧均使用确定性主键:

id = sha256(installScope|repo|codeHash|outcome).slice(0, 16)

保证同一 (scope, repo, 代码内容, outcome) 组合只产生一行。资料来源:src/core/storage/sqlite-code-exemplar-store.ts:1-50

PG 端使用相同 ID 生成策略,但通过位置化参数($1, $2, ...)绑定字段,行类型 ExemplarRow 与 SQLite 端的列名命名风格(snake_case)保持一致,以便上层共用类型映射。资料来源:src/core/storage/pg-code-exemplar-store.ts:1-60

数据源注册表

src/ui/lib/registries.ts 暴露的 SourceKind 包含六类摄取来源:claude-codecodexhermespijsonl-genericwebhook。v0.14.0 的「runtime-test the webhook ingestSession PG branch」表明 webhook 通道已在 PG 后端得到运行时测试覆盖。资料来源:src/ui/lib/registries.ts:1-50、社区发布说明 v0.14.0

迁移、备份与恢复

CLI 通过 nlm migrate 子命令对规范 SQLite 库运行待执行的迁移脚本;migrations/ 目录与编译产物同包发布,便于在新机器上一次性应用。资料来源:package.json:30-40

日常运维通过 db-restorebackup-rotation 模块完成:

  • applyPendingRestore / stageRestore — 在 CLI 启动时检测挂起的恢复操作并原子地应用
  • listBackupDates — 列出可选的备份日期
  • resolveBackup — 按标识符解析具体备份
  • runRollingBackup — 执行滚动备份

资料来源:src/cli/nlm.ts:30-45

社区版本中以下变更涉及存储层演进路径:

版本变更影响
v0.20.0feat(scheduler): auto-chunk oversized sessions on ingest摄取阶段对超大会话自动分块,缓解单行膨胀
v0.14.1fix(pg): add facts.retired_at to the PG schemaPG 模式补齐事实退役时间字段
v0.14.0feat(exemplars): Postgres backend代码样本存储新增 PG 后端
v0.13.0feat(pg): clear app.ts of all rawDb/cast escape hatches应用层清空直接 DB 访问,统一走注册表与 action

常见故障模式

  1. 迁移缺失 — 直接运行 nlm start 前未执行 nlm migrate 会导致 facts.retired_at 等列不存在;先运行迁移子命令可解决。资料来源:package.json:30-40
  2. PG/SQLite 模式漂移 — 历史上 PG 与 SQLite 字段演进不同步(如 v0.14.1 的 retired_at 修复),升级前需确认两库均已应用最新迁移。
  3. 存储类型误用app.ts 历史上曾出现 rawDb/cast 逃生通道(v0.13.0 已清理),新增代码应继续走端口契约,避免再次出现方言泄漏。
  4. 超大会话 — 升级到 v0.20.0 之前可能因单行内容过大触发摄取失败;调度器的自动分块是推荐的规避手段。

参见

  • 召回管线(Query Rewriting 与相关事实选择)
  • MCP 与 HTTP 传输
  • 备份与灾难恢复流程

资料来源:package.json:1-90

Hooks, Hook Modes & Runtime Integration

nlm-memory 是一个本地优先(local-first)的非线性记忆操作系统,专为 AI 算子设计 package.json:1-10。其 Hook(钩子)系统 是连接外部 AI 运行时(Claude Code、Codex、Hermes、Cursor、Windsurf、OpenCode、Pi 等)与本地记忆服务(HTTP/MCP 守护进程)的桥梁。Hook 在外部 a...

章节 相关页面

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

章节 Transcript Reader

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

章节 Citation Detector

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

章节 版本与变更追踪

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

概览

nlm-memory 是一个本地优先(local-first)的非线性记忆操作系统,专为 AI 算子设计 package.json:1-10。其 Hook(钩子)系统 是连接外部 AI 运行时(Claude Code、Codex、Hermes、Cursor、Windsurf、OpenCode、Pi 等)与本地记忆服务(HTTP/MCP 守护进程)的桥梁。Hook 在外部 agent 触发特定事件(如 Stop、UserPromptSubmit、PreToolUse)时自动调用 nlm 守护进程,把会话上下文转化为可被 recall 的指针、事实和代码样本 src/cli/nlm.ts:18-44

Hook 子系统遵循"组合根(composition root)"模式——src/cli/nlm.ts 是唯一知道所有具体实现(SqliteSessionStoreOllamaClientHonoMcpServer)的文件,core/ 中其他模块只依赖端口(ports)src/cli/nlm.ts:46-58。这意味着新增运行时只需修改 CLI 入口,而不动核心逻辑。

Hook 模式

Hook 系统支持两种工作模式,由 nlm hook install 命令启用时确定:

模式行为用途
Shadow(影子)只记录、不注入评估 recall 准确率、收集训练数据
Live(实时)把指针块注入上下文生产使用,让 agent 主动调用 NLM 工具

Shadow 模式让用户在不改写 prompt 的情况下观察 recall 表现;Live 模式则将 formatPointerBlock 渲染的指针块直接拼到用户消息中。指针块是纯指针的:只包含 id + label + 摘要,不暴露会话正文,这是"新鲜安装用户从不编辑 prompt 或 settings 文件"约束下的核心分发面 src/core/hook/pointer-block.ts:7-21

flowchart LR
    A[AI Runtime<br/>Stop Hook] -->|transcript_path| B[nlm hook handler]
    B --> C[Recall Service]
    C --> D[Pointer Block]
    D -->|Shadow| E[Log Only]
    D -->|Live| F[Inject into Context]
    F --> G[Agent 主动调用<br/>get_session / recall_facts]
    G --> H[Citation Detect]
    H --> I[Cite Memo<br/>训练数据]

指针块底部会列出全部四个 NLM MCP 工具名(get_sessionrecall_factsget_fact_historyrecall_sessions),并可选附加事实(Spec G.2)和代码样本(Phase 2 引入)src/core/hook/pointer-block.ts:25-46

运行时集成

CLI 提供了统一的安装/卸载/连接/断开接口,覆盖多类 agent 运行时 src/cli/nlm.ts:36-44

  • nlm connect claude-code — 写入 ~/.mcp.json
  • nlm connect codex — 安装 Codex marketplace 插件
  • nlm connect hermes / hermes-agent — Hermes 集成(agent 插件目录)
  • nlm connect cursor / windsurf / opencode / pi — 编辑器侧集成
  • nlm disconnect <runtime> — 对称移除(含 --dry-run 预演)

Doctor 命令会探测每个运行时的连接状态:当检测到 ~/.codex/config.toml 中残留 @nlm-memory-ts(Codex 自身的注册项)时报告为 staleNlmMemoryTs: true,避免误判 src/cli/nlm.ts:95-114

UI 层(Vite + React SPA)通过 src/ui/pages/Pulse.tsx 展示每个 runtime 的活跃度、话题和会话数,支持分页和抽屉详情。Skeleton 组件只用于形状已知且首屏延迟明显的场景,缓存刷新时不会再次展示骨架屏 src/ui/components/README.md:11-22src/ui/pages/Pulse.tsx:8-30

关键组件

Transcript Reader

src/core/hook/transcript.ts 从 Claude Code 的 JSONL transcript 中解析所有 assistant turn。Stop-hook 的引用检测需要整个会话的 tool_use 序列,而非仅最后一轮——模型通常先调工具、读结果、再写总结。读取失败时必须 fail-quiet,不能因 transcript I/O 错误中断 hook 链路 src/core/hook/transcript.ts:7-22

Citation Detector

detectCitations 实现了两个有序通道:tool_use(强信号,模型实际调用了引用 ID 的工具)和 prose(弱信号,ID 出现在响应正文中)。最小 ID 长度过滤避免短 token 误命中。该模块的输出是未来学习型重排器(learned reranker)的训练数据基底 src/core/hook/citation-detect.ts:7-32

版本与变更追踪

最新稳定版 v0.20.0 引入了调度器对超大会话的自动分块(auto-chunk oversized sessions on ingest,PR #341)package.json:2-2。v0.13.1 修复了代码样本通道接入 HTTP /mcp 传输的接线问题;v0.14.0 进一步把代码样本后端迁到 Postgres 并保证 recall_code MCP 工具可用。运维侧硬化(nlm doctor --fixnlm verifynlm codex-repair)以及每日滚动备份在 v0.13.0 一起落地,详见社区变更日志。

常见失败模式

  1. Hook 未触发nlm doctor 会报告 claudeCode.mcpConfiguredcodex.mcpConfigured 状态,可据此判断 wiring 是否生效 src/cli/nlm.ts:98-114
  2. 指针块为空formatPointerBlock 在 hits/facts/exemplars 全为空时返回 "";这意味着 recall 未命中,需要检查嵌入模型与回填状态。
  3. 断开不彻底 — Codex 插件与 marketplace 卸载可能部分失败,CLI 采用"best-effort 移除 + 单独报错"的策略,调用方可重复运行直到完全清理 src/cli/nlm.ts:62-78

See Also

  • README.md — 项目总览与快速上手
  • CHANGELOG — 完整版本变更记录
  • src/core/recall/ — Recall 服务、查询改写(rewrite-prompt)实现
  • src/install/ — 多运行时安装、规则文件、Ollama 健康检查
  • src/ui/components/README.md — UI 组件库规范(Drawer、Pagination、Skeleton 等)

来源:https://github.com/pbmagnet4/nlm-memory / 项目说明书

Agent Self-Improvement Signals & Code Exemplars

nlm-memory 是一个面向 AI 代理的"本地优先非线记忆操作系统",其核心目标之一是让代理在多次会话之间形成可积累的"自我改进"能力,而不只是把上下文塞满一次性的提示窗口。围绕这一目标,系统引入了信号(Signals)与代码示例(Code Exemplars)两条数据线:前者记录代理在推理过程中产生的可观察事件,后者把"被实际采用并存活下来"的代码片段沉淀为可复用资...

章节 相关页面

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

概述与定位

nlm-memory 是一个面向 AI 代理的"本地优先非线记忆操作系统",其核心目标之一是让代理在多次会话之间形成可积累的"自我改进"能力,而不只是把上下文塞满一次性的提示窗口。围绕这一目标,系统引入了信号(Signals)代码示例(Code Exemplars)两条数据线:前者记录代理在推理过程中产生的可观察事件,后者把"被实际采用并存活下来"的代码片段沉淀为可复用资产,二者共同构成代理随时间自我打磨的反馈基底 资料来源:[src/cli/nlm.ts:1-30]资料来源:[package.json:1-15]。

代码示例子系统从 v0.14.0 起获得 Postgres 后端与 recall_code MCP 工具保证 [v0.14.0],v0.15.0 引入"自动捕获已提交会话中的代码示例"(Phase 1)[v0.15.0],v0.16.0 进一步提供"被动代码示例召回"(Phase 2)[v0.16.0],v0.13.1 修复了 HTTP /mcp 传输未挂接该通道的问题 [v0.13.1]。

数据模型与存储

代码示例的类型契约 CodeExemplar 在 SQLite 与 Postgres 两套实现间保持一致,字段包括 installScopesignalIdsessionIdrepomodellangtaskContextcodecodeHashoutcomegitShasurvivedtscreatedAtretiredAtlabelSource 等 资料来源:[src/core/storage/sqlite-code-exemplar-store.ts:1-40]资料来源:[src/core/storage/pg-code-exemplar-store.ts:1-40]。主键使用确定性哈希:

sha256(installScope|repo|codeHash|outcome).slice(0, 16)

其语义保证"同一安装范围、同一仓库、同一段代码、同一结果"仅产生一条记录,便于跨会话去重与版本对比 资料来源:[src/core/storage/sqlite-code-exemplar-store.ts:30-50]。

两个后端共享 exemplarId() 计算逻辑,差异主要在 SQL 绑定方式:SQLite 使用 better-sqlite3 的预编译 insertStmt(),Postgres 使用参数化 INSERT INTO code_exemplars (...) 数组绑定,二者写入失败均以 { id, skipped } 形式返回,调用方可据此区分"新写入"与"命中已存在" 资料来源:[src/core/storage/sqlite-code-exemplar-store.ts:50-80]资料来源:[src/core/storage/pg-code-exemplar-store.ts:40-70]。

上下文注入与指针块

被动召回的关键载体是"指针块"(Pointer Block)。它是纯文本块,由 formatPointerBlock() 渲染,不携带会话正文,只包含 ID、标签、startedAt 与可选 summary,目的是让代理在最小上下文成本下决定"是否值得拉取" 资料来源:[src/core/hook/pointer-block.ts:1-30]。指针块同时承载会话、事实与示例三段内容:

formatPointerBlock(hits, facts = [], exemplars = [])

exemplars 非空时,块内会追加代码示例条目,结构由 PointerExemplar 接口约束:{ outcome, lang, repo, taskContext } 资料来源:[src/core/hook/pointer-block.ts:25-45]。这样设计的好处是指针块成为跨运行时(Claude Code、Codex、Hermes 等)唯一稳定分发面,新装用户无需修改任何 prompt 或 settings 文件即可感知到示例通道 资料来源:[src/core/hook/pointer-block.ts:1-15]。

为了避免代理"看到自己之前的注入内容又被回灌",stripInjectedContext() 在会话落库前清除块头与脚标:块头包括 ## Possibly-relevant prior sessions (nlm-memory)## Known facts about top entities,脚标为 NLM tools: 开头行;清除时还会把因此产生的 3+ 连续空行折叠为单行 资料来源:[src/core/hook/strip-injected-context.ts:1-30]资料来源:[src/core/hook/strip-injected-context.ts:30-50]。这一机制确保示例注入对下游 LLM 是"无痕"的,避免污染后续分类与摘要任务。

引用检测与信号回流

被注入只是第一步,系统还需要判断代理是否真的引用了给到的示例,这由 detectCitations() 完成。识别按信号强度分两层:

通道判定方式误报率
tool_use代理调用 get_session / recall_facts / get_fact_history / recall_sessions 等 MCP 工具且参数含被注入 ID极低
proseID 字符串直接出现在响应文本中模型极少回显,触发罕见

MIN_ID_LEN = 6 阈值用于过滤短通配串带来的误命中 资料来源:[src/core/hook/citation-detect.ts:1-30]。返回值 DetectedCitation[] 同时携带 ID 与通道类型,可作为未来学习式重排模型的训练数据 资料来源:[src/core/hook/citation-detect.ts:30-50]。

与示例并行的另一条信号线是"已知事实"。pickRelatedFacts() 在被召回的 Top-5 命中涉及的实体集合上,挑选置信度 ≥ 0.7 且至少被 2 个不同会话佐证过的事实,注入到指针块的 ## Known facts 区段;该函数内部对超集与置信度阈值的失败采用"快速失败为空数组"策略,绝不阻塞主召回路径 资料来源:[src/core/recall/related-facts.ts:1-30]。

失败模式与边界

常见问题与对应边界条件:

  • 示例未生效:检查会话是否被标记为 committed,只有 committed 会话才会进入 Phase 1 自动捕获管线 [v0.15.0];
  • recall_code 不可达:v0.13.1 修复了 HTTP /mcp 通道未挂接示例通道的问题,升级后即可 [v0.13.1];
  • Postgres 端 facts.retired_at 列缺失:v0.14.1 显式补齐该列,部署时需确认迁移已应用 [v0.14.1];
  • 指针块回灌:若 stripInjectedContext() 漏掉新块头,需同步更新 BLOCK_HEADERS 数组 资料来源:[src/core/hook/strip-injected-context.ts:5-15]。

See Also

  • nlm-memory 主项目首页:<https://github.com/pbmagnet4/nlm-memory>
  • Release 索引:<https://github.com/pbmagnet4/nlm-memory/releases>
  • 召回架构与查询改写:参见 src/core/recall/rewrite-prompt.ts
  • 安装与连接流程:参见 src/cli/nlm.tsconnect / disconnect 子命令

来源:https://github.com/pbmagnet4/nlm-memory / 项目说明书

CLI, Configuration, Setup & Security

nlm-memory 的 CLI (nlm) 是整个栈的"组合根",在 src/cli/nlm.ts 中集中装配后端实现、HTTP 服务、MCP 传输和外部编辑器连接。本页聚焦于该 CLI 的命令结构、配置机制、首次安装流程以及与安全相关的设计。

章节 相关页面

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

CLI 入口与子命令

nlm 命令是 Node 22+ 的 ESM 可执行文件,通过 package.json"bin": { "nlm": "dist/cli/nlm.js" } 暴露 资料来源:[package.json]。文件顶部的注释明确指出:nlm.ts 是唯一知道所有具体实现的文件,其他模块都通过端口 (port) 依赖注入,后端替换仅需编辑此文件 资料来源:[src/cli/nlm.ts:25-26]。

CLI 主要子命令包括:

子命令作用
start启动 HTTP 服务(默认端口 $NLM_PORT, 默认 3940)
migrate对 SQLite 规范库执行待处理迁移
recall一次性从 shell 发起 recall 查询(调试用)
mcp以 MCP stdio 服务运行,用于 ~/.mcp.json 接入
setup交互式首次安装向导(推荐入口)
install / uninstall注册/移除 macOS LaunchAgent(开机自启)
hook install / hook uninstall给 Claude Code 注入/移除 recall hook
connect <runtime> / disconnect <runtime>接入/移除 Claude Code、Codex、Hermes、Cursor、Pi、Windsurf、Opencode 等编辑器的 MCP 配置块
doctor校验数据库完整性,可选 --fix 安全修复自环边 (I1)、孤立 superseded 会话 (I2)
backfill-facts对历史会话跑分类器并填充 FactStore (Phase B.5)

资料来源:src/cli/nlm.ts:13-23,src/cli/nlm.ts:71-94

doctor 子命令报告四个维度的健康状况:daemon 连通性与版本、~/.nlm/.env 状态、Claude Code ~/.mcp.json 是否包含 MCP 块、Codex config.toml 与 marketplace 插件情况——同时还检测 nlm-memory-ts 这种陈旧条目以避免误判 资料来源:[src/cli/nlm.ts:38-56]。

配置与分类器选择

CLI 通过环境变量驱动后端选择。buildClassifier()nlm.ts 中实现,默认走 Ollama(NLM_CLASSIFIER 未设置时),生产模型为 qwen3.5:4b;若切换至 DeepSeek,则使用 deepseek-v4-flash 资料来源:[src/cli/nlm.ts:138-148]。Ollama 端点来自 OLLAMA_URL 环境变量,默认 http://localhost:11434,以保持"本地优先、无密钥"的姿态 资料来源:[src/cli/nlm.ts:134-137]。

buildAdapters() 表明:数据源表 sources 是注册真相,每个启用行通过 adapterFromSource() 映射到对应 adapter;NLM_ADAPTERS 仍作为基于名字的子集过滤器用于开发期强制筛选 资料来源:[src/cli/nlm.ts:151-160]。backfill-facts 提供 --limit--from <session-id>、状态文件 resume、--dry-run--reprocess--no-embed 等丰富开关,适合长任务分批恢复 资料来源:[src/cli/nlm.ts:189-201]。Recall 侧的查询改写在 src/core/recall/rewrite-prompt.ts 中以严格 JSON 输出 keywordQuery / semanticQuery,失败时 fail-open 回到原始查询,避免对下游打分造成静默污染 资料来源:[src/core/recall/rewrite-prompt.ts:1-21]。

首次安装与安全硬化

runSetup 通过 @clack/prompts 实现交互式向导(作为依赖声明在 package.json 中 资料来源:[package.json])。nlm install 注册 macOS LaunchAgent 实现登录自启;connect 家族命令会读取 ~/.codex/config.toml 检测 [mcp_servers.nlm-memory] 块,但不会误把 Codex 自身的 [projects."…/nlm-memory-ts"] 信任条目当作 nlm 残留 资料来源:[src/cli/nlm.ts:39-49]。disconnect codex 阶段以"尽力而为"语义执行 plugin 与 marketplace 卸载,即使部分清理已先发生,也不会中断流程 资料来源:[src/cli/nlm.ts:99-114]。v0.13.0 引入的 install hardening 包含 doctor / verify / codex-repair 与每日备份,直接服务于"可恢复、可审计"的运维姿态 资料来源:v0.13.0 release。

安全:Token、目录权限与响应脱敏

Token 安全方面,ensureMcpToken 在安装阶段生成 NLM_MCP_TOKEN,~/.nlm/.env 路径由 join(homedir(), ".nlm", ".env") 拼出,hardenNlmDirPermissions 负责收紧 ~/.nlm 目录权限。doctor 输出明确报告 hasMcpToken: Boolean(process.env["NLM_MCP_TOKEN"]),便于环境审计 资料来源:[src/cli/nlm.ts:46-58]。UI 侧在 src/ui/lib/registries.ts 中明确:HTTP 响应中的 SourceRow / ProviderRow 永远不返回 api_keysource token,仅在插入或重新生成时一次性"揭示 (reveal)" 原始值 资料来源:[src/ui/lib/registries.ts:1-9]。

Pointer 注入层面,formatPointerBlock 仅向 agent 暴露 id 与 label,不泄露会话正文,符合"指针不外带内容"原则 资料来源:[src/core/hook/pointer-block.ts:1-15]。代码示例入库采用确定性主键 sha256(installScope|repo|codeHash|outcome)[:16],保证同一 (scope, repo, 精确代码, 后果) 去重 资料来源:[src/core/storage/sqlite-code-exemplar-store.ts:18-30]。retired_at 字段在 v0.14.1 补齐到 PG schema,实现软删除与可追溯的"召回体面退役"。

常见失败模式

  1. Codex 残留配置:disconnect codex 未一并清理 marketplace 时,doctor 报告 mcpConfigured=false 但运行时仍能命中旧插件;以 --withHooks 同步剥离 ~/.codex/hooks.json
  2. 分类器超时:qwen3.5:4b 在超时预算(180s)下需 think:false,由 ClassifierBox 通过 classifierNeedsThinkDisabled 统一处理;若误用带思考的 prompt 模板,recall 评分会整体下移。
  3. 查询改写崩解析:REWRITE_SYSTEM_PROMPT 输出非 JSON 时 RewriteResult 解析抛错,已通过"返回原文"路径安全降级 资料来源:[src/core/recall/rewrite-prompt.ts:30-50]。
  4. 本地 Ollama 缺失:embeddingModelPresent / ollamaModelPresent 引导用户拉取模型,embedding 缺位时 backfill-facts --no-embed 可绕过以保进度。

See Also

  • Code Exemplars & Recall
  • Postgres & SQLite Storage
  • MCP Integration & Hooks

资料来源:src/cli/nlm.ts:13-23,src/cli/nlm.ts:71-94

UI Pages, Daily Digest & Telemetry

nlm-memory v0.20.0 是一个本地优先的 AI 算子非线性记忆操作系统,其前端目前正从 Astro 迁移到 Vite + React SPA(参见 src/ui/pages/Stub.tsx)。本页覆盖三大主题:用户界面的核心页面(Pulse / Recall / Thread)、nlm digest 每日活动摘要命令,以及 Recall 调用遥测的实现位置与...

章节 相关页面

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

章节 Pulse 页 — 运行时与主题活跃度

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

章节 Recall 页 — 采用率与覆盖率遥测

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

章节 Thread 页 — 实体挑选器

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

UI 页面、每日摘要与遥测

nlm-memory v0.20.0 是一个本地优先的 AI 算子非线性记忆操作系统,其前端目前正从 Astro 迁移到 Vite + React SPA(参见 src/ui/pages/Stub.tsx)。本页覆盖三大主题:用户界面的核心页面(Pulse / Recall / Thread)、nlm digest 每日活动摘要命令,以及 Recall 调用遥测的实现位置与口径。

UI 页面概览

Pulse 页 — 运行时与主题活跃度

src/ui/pages/Pulse.tsx 展示每个运行时的 this_weeklast_weeksessions_totallast_session_at 等 KPI,并按主题一致性(coherence)分为三档:active(3+ 会话且 30 天内被触及)、sparse(仅 1–2 会话但最近被触及)、stale(30 天以上未触及)。COHERENCE_HINT 字典为用户提供从一档迁移到另一档时的判断依据。该页通过 Pagination 组件在 footer 槽中分页会话列表,并以 runtime-topics 渲染前 20 个主题芯片,超出时折叠显示。

Recall 页 — 采用率与覆盖率遥测

src/ui/pages/Recall.tsx 区分两类受众:Session recall(编排器回答历史问题时拉取,运维者面)与 Fact recall(代理在任务中途拉取结构化事实,代理面)。两条曲线互补——命中率回答"recall 是否返回了东西","by source" 回答"是否有任何东西调用它",合起来区分采用率问题与语料覆盖问题。EMPTY_SESSION / EMPTY_FACT 默认值用于首屏无数据时稳定渲染。

Thread 页 — 实体挑选器

src/ui/pages/Thread.tsxEntityPicker 通过 entityRuntimeMap 把每个实体映射到出现过的运行时集合,按 most-active / least-active / a-z / z-a 排序,ENTITY_PAGE_SIZE_OPTIONS 默认 [24, 48, 96]。该模式在 Stub.tsx 注释中明确指出尚未从 Astro UI 完全移植。

Stub 页 — 迁移占位

src/ui/pages/Stub.tsx 返回 .stub-shell,明确指向 NocoDB #95(Vite + React SPA 移植任务)作为追踪来源。

通用组件规范

src/ui/components/README.md 规定:

  • Drawer:所有右侧滑入面板统一通过 <Drawer>,由其接管 backdrop 点击、Escape、焦点容器、.drawer-head / .drawer-body 结构。blockEsc={mergeSource !== null} 用于合并操作嵌套转义。
  • Paginationsrc/ui/components/Pagination.tsx 是唯一分页器,total === 0 时返回 nullDEFAULT_SIZES = [10, 25, 50],页码从 0 开始。
  • Skeletonsrc/ui/components/Skeleton.tsx 仅在形状已知且数据获取足够慢以致页面从 "Loading…" 跳变到填充内容显得突兀时使用;缓存的重新获取复用旧数据,永不显示骨架。
  • Formatfmt.pluralfmt.percentfmt.shortDatefmt.daysBetweenrelativeAge 取代内联的 toLocaleString()n === 1 ? "" : "s" 模式。

每日活动摘要(Daily Digest)

nlm digestsrc/cli/nlm.ts 的文件头注释声明,用于打印每日活动摘要,或通过 --telegram 标志发送到 Telegram。该命令运行在 CLI 组合根,所有具体后端(SqliteSessionStore、OllamaClient、Hono、McpServer)仅在此文件中出现。其他模块通过端口依赖,替换后端只需编辑这一个文件——这种"composition root"模式让 digest 子命令与 HTTP 服务器、MCP stdio 服务器、LaunchAgent 安装器共用同一套构建管线。

Recall 遥测与 Hook 注入

src/core/hook/pointer-block.ts 渲染 live 模式下由 recall hook 注入的指针块——纯展示,仅包含 idlabel,不携带会话内容。底部固定列出全部 NLM MCP 工具名,因为指针块是跨运行时教学工具清单的唯一分发面;新装用户从不编辑提示词或设置文件,所有工具信息必须随此块一同发布。PointerFact 字段 <subject> <predicate>: <value> [N sessions] 为代理提供与指针并行的结构化上下文。

src/core/hook/strip-injected-context.ts 的反向操作:FOOTER_PREFIX = "NLM tools:",与 BLOCK_HEADERS 中的两段标题配对,从代理输出中剥离已注入上下文,避免重复渲染。collapseBlankRuns 把 3+ 连续空行折成一行。

src/core/recall/rewrite-prompt.ts 中的查询改写是 Recall 遥测的上游闸口——改写错则所有下游打分静默污染,故输出严格 JSON;解析失败抛出 LLMUnreachableError 让调用方回退到原始查询而非嵌入垃圾。

flowchart LR
  A[Claude/Codex prompt] --> B[Recall Hook]
  B --> C{rewrite-prompt}
  C -->|JSON ok| D[Keyword + Semantic query]
  C -->|parse fail| E[Fallback: raw query]
  D --> F[pointer-block.ts]
  F --> G[Pointer block + NLM tools footer]
  G --> A
  H[nlm digest] --> I[Telegram / stdout]
  J[Recall.tsx] --> K[session + fact hit rate]

失败模式与版本说明

  • Astro → SPA 移植:未移植路由通过 src/ui/pages/Stub.tsx 占位,避免空白页与 404 混淆。
  • 空集合渲染Paginationtotal === 0 时返回 null,Recall 页用 EMPTY_SESSION / EMPTY_FACT 常量稳定首屏,避免组件树随 undefined 抖动。
  • JSON 韧性package.json 当前版本 0.20.0 在 v0.19.0 引入"JSON-resilience — retry + per-chunk tolerance",与 rewrite-prompt 的"失败开放回退"策略互补:前者重试直到成功,后者立即回退防止污染。
  • Postgres 与 SQLite 后端并存:v0.14.0 引入 Postgres 代码示例后端(src/core/storage/pg-code-exemplar-store.ts),并与 src/core/storage/sqlite-code-exemplar-store.ts 共享 ExemplarRow 字段语义;Telemetry 指标在两个后端上口径一致。

参见

  • package.json — 项目元数据与脚本入口
  • src/cli/nlm.ts — CLI 组合根与 digest 子命令
  • 每日 digest 通过 --telegram 标志外发,与 nlm doctor 安装健康检查共用同一状态机

来源:https://github.com/pbmagnet4/nlm-memory / 项目说明书

失败模式与踩坑日记

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

medium 可能修改宿主 AI 配置

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

medium 能力判断依赖假设

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

medium 维护活跃度未知

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

medium 存在评分风险

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

Pitfall Log / 踩坑日志

项目:pbmagnet4/nlm-memory

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

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

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

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

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

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

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

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

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

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

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

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

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

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