dsh-memory-delta

memorytested: passnpmMIT

Layered cross-session memory for DSH that pushes only what changed - the first round injects every active entry, later rounds push only added / updated / removed ones, and nothing at all is injected when nothing changed, with keys that merely repeat an entry id left out of the text so the baseline i

下载量 / Downloads
726
依赖体积 / node_modules
0.5 MB
测试时间 / Tested
2026-11-07
DSH 版本 / Version
0.2.2-rc.1

Install

dsh plugin --profile web add dsh-memory-delta

Sandbox test results

StageResult
1 install✓
2 list✓
3 mount✓
4 boot—

Four stages run in an isolated sandbox: install (network on) → list → mount → boot (last three with no network).

README

dsh-memory-delta

[English](README.md) | 中文

给 AI 编码助手的、分层自动注入的跨会话记忆。

一个 DSH 插件 + 一个零依赖的独立 CLI。借鉴 OpenSpec 的

规格 / 变更 / 归档 纪律 —— 但走推送而不是拉取。

主仓库:GitHub ·
Gitee 是只读镜像 ——
issue / PR 请提到 GitHub,提到镜像站会丢。
状态:M1–M3 已完成并在真实 DSH 上实机验证(差分注入 / 两个工具 / 蒸馏提醒)。
实机验证矩阵见下方「验证」。
有疑问? → [常见疑问 FAQ](docs/faq.zh.md):"是不是每聊一句就把全部记忆发一遍?"
"超预算会丢条目吗?""归档 / 撤回 / 取代有什么区别?""会不会和 AGENTS.md 重复注入?"
英文版:[FAQ](docs/faq.md)。

为什么需要它

AI 编码助手有两个反复出现的毛病:

1. 新会话不记得任何事 —— 每个会话都要重新交代背景、偏好、结论。

2. 记住了也管不好 —— 全塞进一两个 Markdown,越写越大、越写越贵,而且结论过时了没人删。

已有的规格驱动工具(OpenSpec 等)解决的是"代码不跑偏",但它们是拉取式:靠指令要求 AI 去读,

新会话不会主动想起来。dsh-memory-delta 走推送:会话一开始就把该知道的塞进上下文,但只推最精炼的部分,

而且只推变化的部分,细节按需检索。

设计要点

        ┌─ PUSH:会话开始自动注入(字节预算硬约束)
        │    T0 身份与约定   用户偏好 / 机器环境 / 账号约定
        │    T1 索引与待办   接着办什么
库 ─────┤
        └─ PULL:按需检索(不占常驻预算)
             inbox/      候选条目 —— **模型默认只能写这里**
             facts/      当前真相(只有 status=active 参与注入)
             decisions/  决策与理由(只增不改)
             archive/    被取代条目的归档
             journal.md  流水(永不注入)

目录名要分两个轴看(这一点以前没写清,容易被 facts 这个词误导):

目录 · 在流程哪一步 · 记什么 · 谁能写 · 参与注入

inbox/ · 候选(还没确认) · 模型觉得值得长期留住的结论 · 只有模型(memory_write) · ❌ 从不

facts/ · 常驻 · 踩过的坑 + 怎么绕开:环境限制、工具行为、真实的失败与解法 · 只有人(promote) · ✅ 每轮

decisions/ · 常驻 · 你定下的约定:业务 / 流程 / 口味上的决定 —— 防止重复问你 · 只有人(promote) · ✅ 每轮

archive/ · 归档 · 退场的旧结论:被取代(supersede)或不再适用(archive) · 取代/归档时自动搬 · ❌ 永不(但仍搜得到、能取回)

主流程:模型只能写 inbox/ → 人确认后 promote 进 facts/ 或 decisions/ → 退场的进 archive/。

拿不准放哪边就问:"明天世界变了,这条会不会失效?" 会 → facts/;只有你改主意才失效 → decisions/。

两条写起来的诀窍:facts/ 里写清"什么情况下适用"(坑的价值是"下次别再踩",不是"曾经踩过");

decisions/ 里写清"为什么这么定"(有了理由,下回它就能自己判断,不会再问你第二遍)。

这四个目录名(以及 journal.md / index.md / memory.config.json)的完整说明,mem init
会写进库自己的 README.md —— 打开记忆库目录就能看到,不用回来翻项目文档。

七条纪律:

  • 推送的东西必须极小:注入层里的内容每次会话都要花 token。所以流水、设计文档都不进注入层。

实测一个 31 条常驻的真实记忆库:注入文本 4369 字节,平均 141 字节/条,

所以同规模的库用 5 KB 预算就装得下。文本里刻意不写两样东西:条目 id(它只是

差分用的元数据,落在侧车状态文件里,根本不进上下文;内联进正文曾吃掉 34% 的预算),

以及与 id 一字不差的 key

(createEntry 会拿 key 当文件名,于是真实库里 31 条有 30 条的 key 与 id 完全相同 ——

正文里再写一遍是纯重复,实测白占 15% 预算)。每条还会按 90 字截断首行。

  • 只推变化的部分:每条条目带 12 位内容 hash,插件记住上一轮的状态,下一轮只推新增/已更新/已失效;

完全没变化时一个字都不注入。(上游 dsh-agent-instructions 没有差分:文件一变就整篇重注入,

实测一个会话里改 15 次某个 8.5 KB 的文件 ≈ 白烧 58k tokens。)

  • 状态存侧车文件:<harness home>/storages/dsh-memory-delta/inject-state/<会话id>.json

(目录按 config.stateDir → 内核服务 ctx.dshHomePath → $DSH_HOME → ~/.dsh 的顺序解析;

⚠️ 2026-10-01 修:以前只认 $DSH_HOME,而官方桌面版的 home 就是默认的 ~/.dsh、

宿主进程里没有这个环境变量 → 侧车静默不落盘、每次重启重灌一次全量记忆)。

⚠️ 2026-09-30 改的:早先把 {id: hash} 塞在消息的 source 里,那违反了 DSH 会话格式 v0 白名单

(plugin source 只允许 kind/plugin/form/sections/summary),会让整条会话在格式迁移时被拒、

永久打不开(本机 14 条会话因此报废,只能手工修日志)。现在状态不碰会话格式,

且只在消息真的进了上下文之后才记账 —— 排队后又被清掉的消息不会让状态虚增。

  • 模型只写收件箱:错误结论若静默进入常驻层,会被反复注入。提升需要显式 promote。
  • 一个 key 一个真相:事实/决策带语义键 key,同一个 scope+key 上只能有一条 active。

新结论要进来,必须显式 --supersedes 旧的 —— 这是把"记忆腐化"挡在常驻层外的闸门。

  • 结论有状态:active / superseded / expired。被取代的打双向链接并归档,而不是无限追加。
  • 纯 Markdown + frontmatter:人可读、可 git diff、可 review、能像代码一样提交。

安装(作为 DSH 插件)

⚠️ 这段是实机踩出来的,两条弯路都别再走:

❌ 往 package.json 的 dsh.profile.bundles 里加
   → DSH 启动时按市场注册表(.generations/desired.json)重新生成,未知条目被清掉

❌ 在 cordis.patch.yml 里写一个裸条目
   → 被静默忽略(patch 对不存在的 id 只做 config 覆盖/禁用)

✅ 在 cordis.patch.yml 里用 - insert: 包起来

步骤(DSH_HOME 通常是 %APPDATA%\dsh-desktop\harness):

1. 把本包放进 profile 的 node_modules:

   <DSH_HOME>\profiles\web\node_modules\dsh-memory-delta\
       package.json
       bin\mem.mjs
       src\plugin.mjs  src\hook.mjs  src\planner.mjs

2. 在 <DSH_HOME>\profiles\web\cordis.patch.yml 末尾追加:

   - insert:
       - id: dsh-memory-delta
         name: dsh-memory-delta
         config:
           root: ''             # 留空 = 会话工作目录下的 memory/
           # maxBytes: 4096     # 可选。**不写 = 听库配置 memory.config.json#injectBudget**(再没有才是 3072)
           enabled: true
           dueWithin: 0         # verify_when 提前几天提醒复核(0 = 只在已到期时)
           panel: true          # 侧边栏「记忆」页签的数据/动作路由
           allowWrite: true     # 允许面板按钮写记忆库(收件箱提升 / 整理文件名)
           skill: true          # 注册插件自带的技能(装了就能 /dsh-memory-delta 查用法与边界)

3. 保存即可 —— patch 层有 watchUserPatches,会热加载,不需要重启。

卸载:删掉 patch 里那段 - insert:,再删掉 node_modules\dsh-memory-delta 目录。

插件市场已收录(lpf20200901/dsh-memory-delta),市场里直接装即可 —— 那条路走的是**本包自带的
cordis.patch.yml(它故意不写** maxBytes,预算由记忆库自己的配置决定)。上面的手工步骤
仍然适用于本地开发。
npm 上也有一份(dsh-memory-delta):npm i -g dsh-memory-delta 装的是 mem 这个 CLI
(同一份记忆库、同一套检索实现);DSH 里也可以直接按包名装:
cd ~/.dsh && dsh plugin --profile web add dsh-memory-delta。
⚠️ **已知危险:插件市场装/卸别的插件会重写 profile 的 cordis.patch.yml,手写的 - insert: 块
会连注释一起被抹掉。** 2026-10-08 实测:装一个第三方插件时本插件那一段整块消失,表现为
「文件在、没挂上」 —— node_modules 里文件都在,但每轮不再注入记忆、技能目录里
/dsh-memory-delta 也没了,而且日志里没有任何提示。
体检:看一眼 cordis.patch.yml 里还找不找得到 - id: dsh-memory-delta。
恢复:把上面那段 - insert: 贴回去、保存即热加载生效(客户端页签要刷新一次页面)。

插件提供什么

能力 · 说明

差分注入 · 首次注入全部 active 条目(baseline);之后每轮只推「新增 / 已更新 / 已失效」;无变化时零注入

memory_search · 按相关度排序的检索,覆盖 facts / decisions / inbox / archive / journal / 会话索引。字段有权重(key/id > tags > 结论 > 正文)、整串短语有加成;中文按 bigram 匹配,所以 沙箱禁管道 能命中 沙箱禁止命名管道,不用手动加空格。每条结果带 score 与"命中最多的那一行"的片段

memory_write · 把候选条目写进 inbox —— 模型不允许直接改事实层

蒸馏提醒 · 会话跑过若干轮而记忆已是最新时,提醒模型把本次结论落到 inbox;每会话只提醒一次,且提醒消息不带状态,不污染差分基线

…(truncated)

Rendered from the README published on npm. Formatted only, not edited.

Versions

Published on npm::2,最后更新 2026-10-15

Links

GitHub · Homepage · npm

Same category