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 ...
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
目的与定位
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 文件是唯一同时知晓 SqliteStorage、PgStorage、OllamaClient、Hono、McpServer 的"组合根",替换后端时只需要修改该文件 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-23、src/core/recall/rewrite-prompt.ts:1-15、src/core/hook/pointer-block.ts:1-30
核心模块组成
组合根与 CLI
nlm CLI 同时承担 start、migrate、recall、mcp、setup、install、uninstall、hook install/uninstall、connect/disconnect、digest 等十余个子命令 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-25。related-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-32。citation-detect.ts 通过 tool_use 与 prose 两条信号通道判定 Agent 是否真正引用了被召回的 ID,是未来学习式重排模型的训练样本来源 src/core/hook/citation-detect.ts:1-20。
存储与提供者抽象
src/core/storage/ 同时提供 SqliteCodeExemplarStore 与 PgCodeExemplarStore 两种适配器:主键统一由 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-45。registries.ts 暴露的 SourceKind 与 ProviderKind 联合类型就是 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-30。Pulse 页展示运行时分组的会话与主题热度 src/ui/pages/Pulse.tsx:1-30;Recall 页把"会话召回 / 事实召回"的命中率、按来源、热门查询、热门主体并列展示,用于区分"采用度问题"与"语料覆盖度问题" src/ui/pages/Recall.tsx:1-30;Thread 页提供实体筛选与分页浏览 src/ui/pages/Thread.tsx:1-25。StubPage 用于标记尚未从旧 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
- Recall Service & Query Pipeline — 召回与改写内部细节
- Storage Adapters (SQLite / Postgres) — 两种后端的差异与迁移
- CLI & Install Lifecycle —
setup/install/doctor/verify流程 - Pointer Block & Hook Protocol — Hook 注入与 Citation 检测
资料来源:src/cli/nlm.ts:14-23、src/core/recall/rewrite-prompt.ts:1-15、src/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-code | MCP stdio | Anthropic Claude Code CLI |
codex | Codex 插件市场 | OpenAI Codex CLI |
hermes | 独立插件 | Hermes Agent 配套 |
pi | JSONL 解析 | Pi 编程代理 |
jsonl-generic | 文件 watcher | 通用 JSONL 转录 |
webhook | HTTP POST | 远程代理主动推送 |
每条 Source 记录携带 runtimeLabel、parseConfig、enabled 三个核心字段;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); - 持久化:分类与嵌入结果通过
SqliteStorage或PgStorage持久化,并衍生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.mcpConfigured与codex.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 后端差异:
SqliteStorage与PgStorage在code_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
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 显式声明只依赖端口(SessionStore、LLMClient、FactStore、CodeExemplarStore、CodeEmbedder),不引入框架或数据库,因此测试可以用 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_LIMIT、NLM_HOOK_FACT_MIN_CORROBORATION、NLM_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 后,createApp 在 http://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 → 抛
LLMUnreachableError,search()失败开放到原始 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、...
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
存储后端、Schema 与迁移
概述
nlm-memory 是一个本地优先(local-first)的非线性记忆操作系统(v0.20.0),其存储层采用端口-适配器(Ports & Adapters)模式,将具体数据库实现与上层业务逻辑解耦。整个栈的唯一组合根(composition root)是 src/cli/nlm.ts,它负责把 SqliteSessionStore、OllamaClient、Hono、McpServer 等具体实现装配起来;其他模块只依赖端口(ports)接口。资料来源:src/cli/nlm.ts:1-19
存储层提供两个可互换后端:
| 后端 | 引擎 | 适用场景 | 关键依赖 |
|---|---|---|---|
| SQLite(默认规范库) | better-sqlite3 + sqlite-vec | 本地单机、嵌入式安装 | better-sqlite3@^12.10.0, sqlite-vec@^0.1.6 |
| PostgreSQL | pg + pgvector | 团队共享、需要 pgvector 扩展 | pg@^8.21.0, pgvector@^0.3.0 |
资料来源:package.json:1-90
发布产物 files 数组中包含 dist、migrations、plugin、nlm、assets 与许可文件,表明迁移脚本与 CLI 同包发布。资料来源:package.json:30-40
存储后端架构
nlm-memory 的双后端设计源于其本地优先定位,同时保留向集中式部署升级的路径。src/cli/nlm.ts 中 doctor 子命令会根据运行时类型分发修复逻辑:
if (storage instanceof PgStorage) { /* PG 路径 */ } else { /* SQLite 路径 */ }
资料来源:src/cli/nlm.ts:1-90
CLI 还显式导入并调用以下存储子系统,分别承担不同职责:
SqliteStorage/PgStorage— 协议实现(位于src/core/storage/,未在本文检索范围内)applyPendingRestore与stageRestore(来自src/core/storage/db-restore.ts)— 数据库恢复管线listBackupDates、resolveBackup、runRollingBackup(来自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:32 的 SqliteSessionStore 注释)与对应 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-code、codex、hermes、pi、jsonl-generic、webhook。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-restore 与 backup-rotation 模块完成:
applyPendingRestore/stageRestore— 在 CLI 启动时检测挂起的恢复操作并原子地应用listBackupDates— 列出可选的备份日期resolveBackup— 按标识符解析具体备份runRollingBackup— 执行滚动备份
资料来源:src/cli/nlm.ts:30-45
社区版本中以下变更涉及存储层演进路径:
| 版本 | 变更 | 影响 |
|---|---|---|
| v0.20.0 | feat(scheduler): auto-chunk oversized sessions on ingest | 摄取阶段对超大会话自动分块,缓解单行膨胀 |
| v0.14.1 | fix(pg): add facts.retired_at to the PG schema | PG 模式补齐事实退役时间字段 |
| v0.14.0 | feat(exemplars): Postgres backend | 代码样本存储新增 PG 后端 |
| v0.13.0 | feat(pg): clear app.ts of all rawDb/cast escape hatches | 应用层清空直接 DB 访问,统一走注册表与 action |
常见故障模式
- 迁移缺失 — 直接运行
nlm start前未执行nlm migrate会导致facts.retired_at等列不存在;先运行迁移子命令可解决。资料来源:package.json:30-40 - PG/SQLite 模式漂移 — 历史上 PG 与 SQLite 字段演进不同步(如 v0.14.1 的
retired_at修复),升级前需确认两库均已应用最新迁移。 - 存储类型误用 —
app.ts历史上曾出现rawDb/cast逃生通道(v0.13.0 已清理),新增代码应继续走端口契约,避免再次出现方言泄漏。 - 超大会话 — 升级到 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...
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
概览
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 是唯一知道所有具体实现(SqliteSessionStore、OllamaClient、Hono、McpServer)的文件,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_session、recall_facts、get_fact_history、recall_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.jsonnlm 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-22,src/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 --fix、nlm verify、nlm codex-repair)以及每日滚动备份在 v0.13.0 一起落地,详见社区变更日志。
常见失败模式
- Hook 未触发 —
nlm doctor会报告claudeCode.mcpConfigured、codex.mcpConfigured状态,可据此判断 wiring 是否生效 src/cli/nlm.ts:98-114。 - 指针块为空 —
formatPointerBlock在 hits/facts/exemplars 全为空时返回"";这意味着 recall 未命中,需要检查嵌入模型与回填状态。 - 断开不彻底 — 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 两套实现间保持一致,字段包括 installScope、signalId、sessionId、repo、model、lang、taskContext、code、codeHash、outcome、gitSha、survived、ts、createdAt、retiredAt、labelSource 等 资料来源:[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 | 极低 |
prose | ID 字符串直接出现在响应文本中 | 模型极少回显,触发罕见 |
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.ts中connect/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_key 与 source 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,实现软删除与可追溯的"召回体面退役"。
常见失败模式
- Codex 残留配置:
disconnect codex未一并清理 marketplace 时,doctor报告mcpConfigured=false但运行时仍能命中旧插件;以--withHooks同步剥离~/.codex/hooks.json。 - 分类器超时:qwen3.5:4b 在超时预算(180s)下需
think:false,由ClassifierBox通过classifierNeedsThinkDisabled统一处理;若误用带思考的 prompt 模板,recall 评分会整体下移。 - 查询改写崩解析:
REWRITE_SYSTEM_PROMPT输出非 JSON 时RewriteResult解析抛错,已通过"返回原文"路径安全降级 资料来源:[src/core/recall/rewrite-prompt.ts:30-50]。 - 本地 Ollama 缺失:
embeddingModelPresent/ollamaModelPresent引导用户拉取模型,embedding缺位时backfill-facts --no-embed可绕过以保进度。
See Also
- Code Exemplars & Recall
- Postgres & SQLite Storage
- MCP Integration & Hooks
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 调用遥测的实现位置与...
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
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_week、last_week、sessions_total、last_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.tsx 的 EntityPicker 通过 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}用于合并操作嵌套转义。 - Pagination:src/ui/components/Pagination.tsx 是唯一分页器,
total === 0时返回null。DEFAULT_SIZES = [10, 25, 50],页码从 0 开始。 - Skeleton:src/ui/components/Skeleton.tsx 仅在形状已知且数据获取足够慢以致页面从 "Loading…" 跳变到填充内容显得突兀时使用;缓存的重新获取复用旧数据,永不显示骨架。
- Format:
fmt.plural、fmt.percent、fmt.shortDate、fmt.daysBetween、relativeAge取代内联的toLocaleString()与n === 1 ? "" : "s"模式。
每日活动摘要(Daily Digest)
nlm digest 由 src/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 注入的指针块——纯展示,仅包含 id 与 label,不携带会话内容。底部固定列出全部 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 混淆。
- 空集合渲染:
Pagination在total === 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 在发现、验证和编译中沉淀的项目专属风险,不把社区讨论只当作装饰信息。
安装可能改变本机 AI 工具行为,用户需要知道写入位置和回滚方法。
假设不成立时,用户拿不到承诺的能力。
新项目、停更项目和活跃项目会被混在一起,推荐信任度下降。
风险会影响是否适合普通用户安装。
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 发现、验证与编译记录