DeepSeek Harness Hub
← 返回列表

chenzheshushi-commits/dsh-evolve

DeepSeek Harnessspec-screened在 GitHub 查看 ↗
⚠ 装前注意

面向 DeepSeek Harness 的自演化记忆与技能生命周期。

基本兼容但装前注意:npm 同名包「dsh-evolve」归属 dushaobindoudou/dsh-plugin,装到的可能不是本插件 · 最近上游提交 2026/9/17 · 已提供中文文档

DeepSeek Harness 的自进化记忆 + 技能生命周期——持久化跨会话记忆,具备零 token 确定性召回、分级审批、基于重复的强化学习,以及针对技能和记忆的防膨胀收敛。

综合分
35.3
GitHub 分
35.3
用户评分
★ Stars
8
周下载量
安装插件(需先安装 dsh CLI 引擎:npm install -g @deepseek-ai/dsh)
dsh plugin --profile web add chenzheshushi-commits/dsh-evolve
npm 同名包「dsh-evolve」归属 dushaobindoudou/dsh-plugin,装到的可能不是本插件,改用 GitHub 源安装
数据截至 2026/9/19(元数据每日更新 · 实装验证按队列轮转,单条结论的验证时间见上方)
安装兼容性检查⚠ 装前注意

以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。

npm 包dsh-evolve @ 0.0.1
Node 引擎要求 >=22.5.0 · 基线 Node 22.19 满足
dsh CLI 依赖未声明 dsh 版本约束
入口文件main/exports/bin 已声明

npm 同名包「dsh-evolve」归属 dushaobindoudou/dsh-plugin,装到的可能不是本插件

验证方式:npm registry 存在性 + package.json 静态校验 · 最后验证 2026/9/19 19:16:26

依赖的 DSH / Cordis 模块
@deepseek-ai/cordis@deepseek-ai/dsh-client-connection@deepseek-ai/dsh-client-runtime@deepseek-ai/dsh-client-ui-settings@deepseek-ai/dsh-client-ui-slots@deepseek-ai/dsh-host-webserver@deepseek-ai/dsh-llm@deepseek-ai/dsh-settings@deepseek-ai/dsh-storage@deepseek-ai/dsh-storage-domain@deepseek-ai/dsh-system-prompt@deepseek-ai/dsh-tools
用户评分
还没有人投票,来当第一个
订阅周报,不错过优质插件更新
每周一封 · 高评分插件 + 新用户活动

README

dsh-evolve

面向 DeepSeek Harness 的自演化记忆与技能生命周期。

你的 agent 在会话之间会遗忘一切。这个插件为它提供持久记忆,把重复的流程转化为可复用的技能,并且——至关重要地——让这些知识不会堆积成噪音堆。真正的演化是变异加上选择加上修剪;大多数记忆插件只做了第一步。

这个插件出厂时是空白的。它对你或你的工作没有任何预置的看法:只有机制和规则。它学到的一切都只存在于你的本地安装中,绝不会离开。

要求

| 要求 | 原因 |
|---|---|
| Node.js >= 22.5.0 | 使用内置的 node:sqlite 模块进行 FTS5 全文搜索。Node 20 无法工作。 |
| DeepSeek Harness 0.1.0-rc.7+ | 宿主平台。提供工具、存储、LLM,以及(可选的)Web 服务器。 |
| PATH 中有 git (可选) | 启用可回滚的自动记忆检查点。没有它,检查点会被跳过。 |
| PATH 中有 tar | 对于需要回滚快照的技能重写是必需的。备份失败会中止 refine/fold,而不是冒险进行不可恢复的覆盖。 |
| Linux / macOS / Windows | 在 Linux 上开发;CI 在 Linux 和 Windows 上运行完整测试套件。Windows 需要 PATH 中有 git/tar 才能使用可选的检查点和回滚功能——当它们不存在时,插件会跳过而不是失败。(v0.6.0 及更早版本在 Windows 上写入技能提案时会抛出 EPERM;已在 v0.6.1 中修复。) |

降级在设计上是优雅的:如果 SQLite/FTS5 不可用,插件会回退到纯 bigram 召回,任何缺失的可选依赖只会禁用其自身功能。它绝不会阻止 harness 启动。

安装

直接从本仓库安装——无需 npm 包:

dsh plugin --profile web add github:chenzheshushi-commits/dsh-evolve

固定到特定发布版本,而不是跟踪 main:

dsh plugin --profile web add "https://github.com/chenzheshushi-commits/dsh-evolve/releases/download/v0.6.5/dsh-evolve-0.6.5.tgz"

然后重启 harness——工具在启动时被发现,不会热重载。

或者克隆下来进行开发:

git clone https://github.com/chenzheshushi-commits/dsh-evolve.git
cd dsh-evolve
pnpm install
pnpm run build      # builds the web-settings client bundle
pnpm run test       # smoke + registration probe + web-route e2e

它的功能

跨会话记忆
结构化记录(fact / preference / decision / lesson / todo / note),带有作用域
(user = 所有地方,project = 此处)和 1–3 的重要性。存储以 JSON 作为事实来源,外加一个你可以阅读和手动编辑的 Markdown 镜像。

召回是零 token 且确定性的:bigram-Jaccard 相似度与 SQLite FTS5 BM25 通过 Reciprocal Rank Fusion 融合。没有嵌入 API,没有每轮模型调用。CJK 文本被正确分词(搜索 苹果 不会匹配 水果)。
相关记忆会根据当前消息在每一步自动注入,而持久的用户偏好/事实会在每一轮开始时作为常驻快照注入。

分级审批,而非“全部确认”
模型编写的记忆会经过一道确定性关卡,由它决定自动确认还是留待审核,判断依据仅限于模型无法粉饰的属性:

- 可逆性(重要性级别)
- 与你已确认的内容是否冲突
- 与现有记忆是否重叠
- 该写入是否可以追溯到你实际说过的话

显而易见、可逆、以用户为依据的写入会自动落地。有风险或不确定的写入则排队等待审核。这道关卡刻意忽略模型提供的 kind 字段——让自我报告的标签决定其自身的豁免,那根本算不上关卡。自动确认的条目仍然可见且可撤销,一个配置标志即可让你回到“全部审核”的行为。

强化:你重复的内容会变得更强
重新观察到相同的理解不会使其重复——而是会强化它。观察次数会上升,重要性会在可配置的阈值处攀升,并且保留质量更高的表述,而不是盲目覆盖。置信度会显示出来(low / medium / high),以便智能体能够将已确立的知识置于一次性言论之上。

会自我改进而非不断累积的技能
共享同一标签的高价值经验会凝结成一个 SKILL.md。新的证据会就地改进现有技能——带版本控制,并保留你的手动编辑——而不是生成一个近乎重复的副本。

策展会运行一个真实的生命周期:active → stale → archived。归档会将技能移出活动目录,并且可逆。内容重写需要先成功备份;归档和恢复是可逆的目录移动。该插件绝不会自动物理删除资产。

反臃肿收敛
大多数记忆系统都会跳过的另一半。

技能: 通过内容相似度检测近乎重复的技能,并标记因改进而臃肿的文件。合并会生成一个总括技能并归档原始技能(可逆)。折叠会将层层堆叠的改进章节重新压缩为简洁的叙述。从未真正被加载过的候选者排在最前——既重复又未被使用,是合并的最强理由。

记忆: 一个硬性字符预算,绝不会静默丢弃任何内容(超出预算时会返回裁剪候选供你决定),一道防止改写后的近乎重复项和单薄低信号写入的关卡,以及将得到充分强化的项目记忆提升到全局范围。

检测始终开启,且零 token 成本。每个变更操作都需要主动选择加入。

后台审查
在一轮结束时(有节流),一次隔离的 LLM 处理会重放该轮的对话快照,并询问哪些内容值得记住。建议会经过同一道审批关卡——审查者只提出建议,绝不直接写入。

它作为独立调用运行,因此你的主对话和提示缓存永远不会被触及,并且
因为它是一个没有附加任何工具的纯文本补全,所以它在结构上无法产生副作用。它可以指向一个与你的主模型不同(更便宜或更强)的模型。

弱模型会安全地降级:格式错误的审查会被跳过,因此最坏的结果是“这一轮什么都没学到”——绝不会是“学到了错误的东西”。

了解你,并为你塑造工具
已确认的用户范围偏好和事实会累积成一个自动增长的个人档案,你可以查看它,并按你表现出每一条的一致程度排序。

技能还可以携带一个用户风格叠加层:一个在技能被使用时应用的小型指令层,源自你的个人档案。底层的 SKILL.md 永远不会被重写,因此该叠加层是完全可逆的——清除它,技能就恢复原样。

维护扫描
单个工具将所有只读检查聚合到一份报告中——可归档的技能、合并候选、臃肿的文件、记忆预算、晋升候选,以及是否已累积足够的成果数据值得评分。可以安全地通过外部 cron 按计划运行;该插件从不安装内部计时器。

工具

记忆: memory_remember memory_recall memory_index memory_confirm
memory_confirm_batch memory_auto_review memory_profile memory_budget memory_promote
memory_forget

技能: crystallize_skill refine_skill skill_curator archive_skill restore_skill
skill_rollback converge_skill fold_skill skill_style

运维: evolve_maintain memory_stats skill_stats

配置

一切都可以通过插件的设置页面(Web 配置)或你的 DSH 配置进行配置。值得注意的开关:

| 键 | 默认值 | 效果 |
|---|---|---|
| autoConfirmEnabled | true | false = 每次模型写入都等待审查 |
| reviewEnabled | true | 每轮后台审查 |
| reviewEveryTurns | 5 | 审查节流 |
| reviewModel | (主模型) | 将审查路由到不同的模型 |
| refineLLM | false | 在结晶/精炼技能时使用 LLM 处理 |
| reinforceEvery | 3 | 每个重要性阶梯的观察次数 |
| memoryMaxChars | 20000 | 记忆字符预算(0 禁用) |
| convergeSuggest | true | 呈现合并/折叠建议 |
| curatorStaleDays / curatorArchiveDays | 30 / 60 | 技能生命周期阈值 |
| ftsEnabled | true | false = 纯二元组召回,不使用 SQLite |

LLM 仅用于可选的辅助处理——技能精炼、后台审查和技能合并。它们全都是单次执行、可跳过的,并在失败时回退到确定性行为。没有任何东西在你的主循环中运行。

设计规则

- 绝不破坏框架。 每条失败路径都安静地降级;该插件无法阻止启动。
- 绝不删除用户资产。 归档、备份、回滚——但绝不销毁。
- 无内部计时器。 会话内工作挂靠在事件上;离线工作是调用某个工具的外部 cron。
- 交付时保持空白。 不预加载个人数据。它学到的东西留在你的机器上,绝不会被打包。
- 机制优先于模型智能。 安全性来自确定性规则,因此更换模型只会改变质量,绝不会改变安全性。

v0.6.5 的新内容——配置守卫现在询问存储,而不是路由

v0.6.5 是一个补丁版本,没有生产代码变更。它修复了一个声称的检查范围超过实际检查范围的测试。

对 v0.6.4 的审查复现了该版本做出的每一项声明(32 个变异,预期变红处 27/27 变红;8 个引用数字加 3 个下限全部重新计算),随后表明 v0.6.4 最引以为傲的守卫并没有捕获它本应捕获的缺陷:

lib/index.js:279   config: cfg  ->  config: { ...cfg }
(存储拿到的是快照;设置页面会静默停止工作)

config-liveness.test.mjs   4/4 通过      = 2 计数的
副作用才被捕获。一个让正确工作失败的守卫会教人们忽略红色。它现在把
实际的 set-config 动作 POST 到实际的路由,并读取实际的存储;实测:
等价的重构通过,赋值到副本上则失败。
- fsync 扫描中的四个盲点,全部经过实测。 双引号的 openSync(p, "r")
是不可见的(引号风格不是语义);计算出的模式被当作合规而不是无法判定;
刷新必须出现在 400 个字符以内,而本仓库已经有比这更宽的单行模块;
并且发现逻辑只读取 lib/ 的顶层,所以未来任何 lib/ops/ 都不会被覆盖。
现在:引号被规范化,计算出的模式会被报告,基于作用域的向前查找,递归扫描。
- 唯一的运行时证明可以被静默关闭。 让只读探测返回 false,就把唯一的
非源文本证据变成了永久跳过,而跳过不是失败。跳过现在必须由环境来证明其合理性。
- fsyncTree 不再返回一个恒为真的 ok——一个名为 ok 的字段会招来
永远不会触发的 if (!ok) abort——而且现在盖在标记上的 durability 注释
会到达 reconcile 裁决,而不是完全没有读者。
- budgetStatus 的有效计数契约,之前只是一条注释,现在被断言了;
search.js 的下限注释写的是 0.5,而实现说的是 0.6。

检索精度没有变化,仍作为 issue #2 跟踪。

v0.6.3 的新内容——完成 v0.6.2 所声称的,并撤销一个回归

v0.6.3 是一个补丁版本。它针对一份对 v0.6.2 的审查采取行动,该审查发现上一个
版本发布了一个不真实的声明,并引入了一个回归。

- 最后一个路径级 fsync 没了,而且门禁现在能看见它。 v0.6.2 说
lib/fsync.js 是“唯一为了被刷新而打开路径的地方,并且有测试拒绝任何其他
模块这样做”。lib/skills.js 在技能写入路径上仍然有一个。门禁的正则用了
[^)]?,它无法跨越嵌套调用,所以 openSync(dirname(file), 'r') 被读作
合规——把那个参数提升到一个局部变量,其他什么都不改,同一个门禁就变红了。
参数拆分现在做了括号平衡,并且有一个测试向它喂入四种写法,包括
两层嵌套。那一行也是树中唯一一个吞掉所有错误的 fsync,包括真实的 ENOSPC。
- 只读文件不再导致发布失败。 v0.6.2 只要有任何文件拒绝 flush 就拒绝发布,因此技能树中一个 0444 文件就会直接破坏 crystallize / refine / rollback。这把两种不同的事件混为一谈:平台不支持这种 fsync,以及文件是只读的。两者都不意味着字节丢失——数据在尝试 flush 之前就已写入并关闭,而标记的关键属性是它被最后写入,而不是每个 fsync 都成功。fsyncFile 现在会报告发生了哪种拒绝,降级的发布会记录在标记上(durability: 'partial' 加上文件列表)并写入日志,而不是中止。
- 运行时证明现在在 Windows 上运行。 那个证明 'r+' 无需读取源文本的断言在 win32 上被跳过,注释是“Windows 忽略写入位的 chmod”。这是错误的——在 Windows 11 / node 22.22.3 上实测,chmod 0o444 映射为 FILE_ATTRIBUTE_READONLY,且 openSync('r+') 会以 EPERM 失败。它现在会探测文件系统是否强制执行该位,只有在确实不执行时(root、FAT/exFAT)才跳过。
- 检索测量用错了量。 下限是与 base 比较的(search.js:236);v0.6.1/v0.6.2 中引用的数字(1.41、1.47、3.07)是返回分数,经过了三个乘数之后。重新按 base 推导:真实命中是 0.8393,近似并列的假阳性是 0.8065(所以那一对是可区分的,与旧说法相反),而不相关记录是 1.7541——超过真实命中的两倍。最后这一点正是任何下限都无法解决这个问题的原因,而现在这正是棘轮所断言的内容。此前棘轮会在“真实命中被杀掉”时变红,而下限变更会触发这一点,同时让漏洞大开。
- 配置接线被断言,而不仅仅是其机制。 持有活动对象的存储被测试了;宿主在每条写入路径所修改的同一个对象上把它交给存储,这一点此前只是通过阅读 index.js 的三行来确认。现在已被断言。
- injectionCount 重新只有一个定义。 预算平局决胜读取的是持久化字段,而存储的其余部分使用的是有效计数。

检索精度本身没有变化,仍作为 issue #2 跟踪。

v0.6.2 的新内容——守卫按行为评判,而不是按措辞

v0.6.2 是一个补丁版本:没有新功能,没有检索行为变化。它针对的是对 v0.6.1 的外部审查,该审查攻击了那个版本中添加的守卫,并绕过了其中两个。

- 所有 fsync 逻辑现在都集中在一个模块中。 存在四份副本,其中两份在软失败列表中缺少 ENOTSUP,因此同一个无法同步的文件系统会让事务层抛出异常,而提案层却无动于衷。lib/fsync.js
现在,路径被打开以便刷新的地方只剩这一处,并且有测试拒绝任何其他模块这样做——这是通过扫描 lib/ 发现的,而不是手写列表,因为手写列表会让一个带有完全相同缺陷的全新模块完全未被检查。(v0.6.2 发布了这一声明,而 lib/skills.js 中仍保留着一次这样的 fsync,而门禁的正则表达式无法看到它;已在 v0.6.3 中修复。)
- 守卫不再信任变量名。 它过去通过正则匹配标识符来决定“这是文件还是目录?”,因此将参数重命名为 dir,同时把 'r+' 回退为 'r',就会恢复原来的 Windows 缺陷,而所有测试仍然通过。现在规则在调用点检查,并单独在运行时证明:在只读文件上,'r+' 根本无法打开,因此一个已经悄悄回退到 'r' 的辅助函数会在真正的辅助函数报告拒绝的地方报告成功。
- 失败的刷新不再能被发布为成功。 fsyncTree 返回哪些文件拒绝了,所有三个发布协议在写入提交标记之前都会检查它。该标记的全部含义就是“这些字节已在磁盘上”;在刷新被拒绝之后写入它,是一个恢复过程随后会信任的谎言。在 Windows 上,这第一次变得可观察,而不是静默。
- 治理限制在运行时可以调整。 store.js 在构造时复制了配置对象,因此在设置页面将 maxPendingQueue 从 50 降到 10 会返回 200,/state 显示 10,而洪水防御会继续允许 50,直到进程重启。存储现在持有宿主自己的对象。在修复之前,连续两次评审都报告了这一点。
- 一条误导性注释和两个讨好的断言得到纠正。 lib/search.js 声称不相关的记录“得分恰好为 0——一个宽泛的安全差距”。它们的得分是 1.41。两个看似守护该差距的 smoke.mjs 精确性断言之所以通过,只是因为它们的夹具恰好省略了共享的 2-gram;现在它们说明了这一点,并指向记录真实状态的失败 test.todo。
- 门禁的 Python 依赖已在仓库中声明。 它们只存在于 CI 工作流中,因此在全新克隆上运行 test:contracts 会因 ModuleNotFoundError 而失败——而 rfc3339-validator 是承重而非可选的原因,是困在 yml 文件中的知识。现在是 scripts/schema/requirements.txt,CI 从中安装,因此版本固定不会彼此漂移。
- files 不再声明一个不存在的目录(assets)。

针对重写后的守卫运行了六个变异,包括评审用来击败它们的两个;每一个都会让守卫变红。

v0.6.1 的新内容——Windows 平台修复和跨操作系统 CI

v0.6.1 是一个补丁版本:没有新配置,在 Linux 或 macOS 上没有行为变化。
它修复了一个平台缺陷,并关闭了让它得以发布的验证缺口。

- 技能提案在 Windows 上不再抛出异常。 ProposalStore.create() 对
通过 O_RDONLY 句柄读取其文件,并在没有保护的情况下对目录执行 fsync。
Windows 的 FlushFileBuffers 需要写访问权限,因此它抛出了 EPERM —— 而且由于
create() 是提案流水线的唯一入口,skill_rollback 以及
在默认 manual/balanced 模式下的每一次 crystallize/refine/fold/converge
都会抛出异常,而不是返回 {proposed:false, reason}。现在文件以 r+ 打开;目录
fsync 失败会通过事务层已经使用的同一代码列表软失败
(EINVAL/EACCES/EPERM/EISDIR/ENOTSUP)。
- fsyncTree 现在真正再次刷新文件。 它通过目录辅助函数同步常规文件,
而该辅助函数的软失败列表吞掉了由此产生的 EPERM。因此在 Windows 上,
文件从未被刷新——而且是静默的,这比抛出异常更糟,
因为协议 C/D 恢复会把已写入的标记视为树已持久化的证明。
- CI 已存在。 一个 ubuntu-latest + windows-latest 矩阵运行类型检查、构建、
完整测试套件和契约门禁。v0.6.0 在一台 Linux 机器上以 303 个测试全绿,
却仍然发布了上述 bug;没有第二个操作系统,什么都无法发现它。
- 构建出的客户端受到门禁检查,而非手工检查。 lib/client.js 是已提交的
产物,而 files 只发布 lib/,因此 CI 会重新构建并对其做差异比较。过去,
陈旧的产物只有靠记得在打标签前运行一条命令才能被发现。
- 一个已知的检索漏洞现在可见,而非隐含。 smoke.mjs 中的一条精确率红线
之所以通过,只是因为它的测试夹具恰好不包含它所防范的共享 2-gram;
用普通方式表述时,一个不相关的查询会误匹配。它被记录为
scripts/schema/f3-precision-hole.test.mjs 中一个失败的 test.todo,
并附有测量结果,说明为什么仅靠更改阈值无法修复它。本版本中检索行为
保持不变——修复将在 v0.7.0 中随召回率/MRR 证据一起落地。

v0.6.0 的新内容——整洁记忆与受治理的技能演化

v0.6.0 补上了自我演化缺失的安全另一半:自动化可以行动,但每一次
非平凡写入都有确定性边界和恢复路径。

- 整洁处置层级。 manual | suggest | tidy 现在共享同一条资格规则。
Tidy 会自动软删除至多 tidyMaxPerRun 条普通的、低重要性的记忆,
这些记忆从未被召回或注入,并且已过冷却期。固定、重要性为 3、偏好、
决策、待定和被拒绝的记录永远不会成为自动处置对象。软删除的记录
仍然可见且可恢复。没有任何层级会物理删除记忆。墓碑 GC 不属于 v0.6.0。
- 带恢复的持久操作。 每一次技能变更都作为事务运行,带有清单、
预写日志和单一提交点,因此中断会留下一个下次启动可以完成的状态,
而不是一个写了一半的技能。发布使用变更实际需要的协议——一个新目录就是一次
重命名,主体重写会在其重写的文件中提交操作 ID,回滚会经过一个已退役的中间态,而归档则是纯粹的移动。跨文件系统移动会失败关闭,而不是退化为先复制后删除。
- 从卡住的操作中退出。 冲突或部分完成的合并会被冻结,而不是被猜测处理;它会保留其授权,使其他任何东西都无法触碰同一目标,并会出现在设置页面中,供做出前滚或回滚决定。在提交点之后不会发生任何回滚:一个其第二个来源无法归档的收敛会报告部分状态并保留实时合并,因为“清理”会破坏已经成功的工作。
- 按 ID 寻址的归档。 同一技能的多个归档可以共存,每个都有一个带时间戳的 archiveId,恢复时会指定它想要的那一代。skill_rollback 现在只会创建一个提案,并在提案时按内容哈希固定所选备份,因此之后的备份无法改变恢复的内容。
- 技能提案。 在手动和平衡模式下,crystallize/refine/fold/converge 会创建一个提案,而不是更改实时目录。设置页面是唯一的应用/拒绝界面;模型工具不能批准自己的工作。如果你希望在所有安全检查之后立即写入,请选择一个明确的自主 skillProposalMode。
- 陈旧与所有权保护。 提案应用会为散文和语义状态绑定独立的 SHA-256 哈希。任何人工编辑或竞争性变更都会使提案变为陈旧,且零覆盖。技能会绑定到一个随机的每次安装所有者 ID;旧版技能需要在 Web 面板中显式认领。
- 单一变更咽喉。 模型工具、Web 操作、回滚和自动归档都会通过结构化的所有权、策略、大小、机密、备份和回执门禁。自动技能主体上限为 10,000 个字符;人工路径默认上限为 40,000。已经过大的技能只能被重写得更小。
- 机密持久化防护。 强 GitHub/AWS/OpenAI/Anthropic/Slack/Bearer/PEM 模式会在进入记忆、技能、镜像或 Git 持久化之前被阻止。源上下文和审计字段会被脱敏;事件只存储哈希和掩码片段,绝不存储原始令牌。关于“password”或“token”的普通散文仍然是有效知识。批准一个被隔离的发现会绑定到所审查的确切出现位置——包括重复副本——以及扫描器和规范化版本,因此一次发现更多内容的重新扫描不能被较旧的批准放行。
- 客观后台审查。 审查需要大量前台工作。已完成/中断的轮次符合条件;错误/被阻止/中止的轮次不符合条件。状态按会话隔离,成功的技能工具使用会为自主 refine/fold/converge 发放短期、单次使用的回执。
- 可选的轮次开启批准。 启用后,直接的高价值
memory_remember 可以在当前轮次内询问是/否。这有意不覆盖后台审查:后台审查在 turn/end 之后运行,而 DSH 在该阶段禁止审批请求。后台建议继续使用设置审查队列。该弹窗默认关闭,且默认每轮次最多一次。取消或关闭会让该记忆保持待处理状态——未得到答复的提示不构成同意——而拒绝则会将记忆报告为已拒绝,而非已保存。
- Web 重放保护。 特权 Web 操作使用短时效、同源、单次使用的能力令牌。这是 CSRF/重放保护,也是审计锚点;它并不被呈现为人类点击的证明。重试同一操作 id 会重放其回执,而不是被拒绝,因此丢失响应的客户端永远不会被迫将同一变更发布两次。

操作边界:

- 两个进程可以指向同一个 evolve 工作区而不会损坏它:第一个进程获取实例锁,第二个进程对自动工作降级为只读——tidy 会列出候选项而不是删除它们,pruning 会拒绝执行。崩溃进程留下的锁会在该进程消失后立即被回收,而不是在超时之后。每个工作区运行一个 DSH 实例仍然是推荐的设置。
- 在最终过期检查和原子重命名之间存在一个不可避免的、非常小的 POSIX 窗口。当 apply 正在进行时,不要手动编辑同一个 skill。
- 该插件仍然以空白状态发布;包中没有任何 memory、proposal、incident 或 owner id。运行时 JSONL/proposal/operation 文件被排除在工作区 Git 之外。

新配置

| 键 | 默认值 | 效果 |
|---|---:|---|
| disposalMode | manual | manual、suggest 或可恢复的 tidy |
| tidyMaxPerRun | 5 | 每次空闲运行的最大自动软删除数 |
| idleMinutes | 5 | suggest/tidy 的空闲延迟 |
| skillProposalMode | inherit | 遵循记忆审批模式,或显式选择 skill 模式 |
| skillAutoMaxChars / skillMaxChars | 10000 / 40000 | 自动/人工 skill 正文限制 |
| approvalPromptEnabled | false | 在轮次内询问直接的高价值记忆写入 |
| approvalPromptMaxPerTurn | 1 | 每个会话轮次的弹窗预算 |

v0.5.2 中的新内容

修复:注入的通知不再导致 DSH 拒绝加载会话历史。

该插件注入的每条消息(记忆召回、始终开启的偏好快照、检查点和提醒通知)都被标记为 source.form: 'notice'。DSH 已发布的 v0 会话格式要求 notice 来源还必须携带字符串 summary;该插件从未设置它。直到 0.1.0-rc.x 的 harness 都没有校验该字段,所以日志看起来正常——但 DSH 0.1.5-rc.2 添加了 v0→v1 迁移,会在加载时校验每个事件并拒绝整个日志:

failed to observe session "session-…": @deepseek-ai/dsh-session-format-v0-to-v1
refuses this format v0 Session: user/message 10 source summary must be a string
每个曾被此插件注入过的对话都会出现 历史加载失败 / “history failed to load” 的结果——而在 Tier 1 始终开启的情况下,实际上所有对话都会如此。

- 现在全部 8 个注入点都会设置一个简短的 source.summary。没有行为、配置或 API 变更;该摘要只是 DSH 在通知折叠时显示的元数据。
- 升级只能修复新会话。 已经写入磁盘的日志仍然缺少该字段,而 harness 仍然会拒绝它们。要修复这些日志,请参见下文。

修复由 v0.5.1 及更早版本写入的会话日志

scripts/repair-session-logs.mjs 会就地重写出有问题的的事件。先停止 harness,然后:
bash
查看将会发生哪些更改,但不写入
node scripts/repair-session-logs.mjs --all ~/.dsh/sessions --dry

就地修复(每个被修改的日志都会备份到 .bak.)
node scripts/repair-session-logs.mjs --all ~/.dsh/sessions

需要 Node ≥ 22——它需要 node:zlib 中的 zstd 支持,而 Node 20 缺少该支持。请使用与你的 harness 相同的运行时(例如 ~/.local/node22/bin/node)。

可以安全地重复运行:修复是幂等的,事件数量和 seq 编号会被完全保留(会话日志的 seq 是密集的,因此不会删除任何内容——只会重写),并且拼接式 zstd 帧容器布局会保持完整。该脚本会自我验证其产物,如果发现任何异常就会拒绝写入。

除了缺失的 summary 之外,它还会在同一次处理中修复另外两种无关的拒绝情况,以防你的日志中存在这些问题:由其他插件写入的未知历史事件类型(会被重写为已知的 no-op 类型,原始负载会作为文本保留——请注意,DSH 0.1.5-rc.2 即使将这些事件标记为 ignorable 也不再接受它们),以及仍处于版本 2 的 subagent/descriptor 事件。

v0.5.1 中的新内容

修复:始终开启的偏好快照现在会到达每个新对话。

Tier 1 始终开启快照——即在每一轮开始时注入的持久用户偏好/事实块——此前使用一个进程全局的 last-key 进行去重。由于持久偏好很少变化,快照文本保持不变,因此在第一个对话注入它之后,之后每个对话的第一轮都会被静默抑制,完全不会收到该块。逐步相关召回注入器在其重复抑制器上也存在同一类跨会话泄漏。

- 去重现在按会话进行,通过 WeakMap 以会话为键。每个新对话都会在第 1 轮获得始终开启块;在单个对话内,未变化的快照仍会被跳过(去重原本旨在提供的提示缓存保护得以保留)。WeakMap 会随会话一起被回收——无需手动清理,也不会泄漏。
- 回归测试使用两个独立会话驱动真实的 apply(ctx),并断言跨会话注入和会话内抑制都成立。检索基线保持不变(5/5 召回率,MRR 1.0,R6 漂移 0)。
无配置或 API 变更;无迁移。

v0.5.0 的新内容

自主性变成了用户可选的旋钮,中文检索从根源上得到修复。

早期版本硬编码了记忆可以自行决定的程度。v0.5.0 将其变为一项产品设置,在摄取侧和处置侧都是如此——刻意保持不对称,因为摄取错误是一种增加(可见),而处置错误是一种减少(不可见)。

摄取自主性——approvalMode(三个层级)
- manual——每次模型写入都等待你确认。balanced(默认)——锚定到用户原话或已确认记忆的近重复项的可逆写入自动确认;其他一切均为待处理。autonomous——任何可逆、无冲突的写入自动确认。
- autonomous 仍会强制将冲突和高重要性(imp 3)记忆置为待处理——层级划分位于冲突/重要性扫描之后,因此这是结构性保证,而非脆弱的 if。
- 有界,因此不会淹没存储:每个后台审查轮次最多 reviewMaxAutoPerTurn 次自动确认(其余降为待处理),并且对唯一可无损拒绝的区域设置硬性 maxPendingQueue 上限。已确认记忆受字符预算约束,待处理记忆受数量约束——两个池都不会无限增长。
- 后台审查不能再自行决定走 anchored 自动确认捷径(anchoredToUser 由调用方/存储派生,绝不由模型自我报告)。

处置自主性——disposalMode(两个层级)
- manual(默认)——不自动提出任何建议。suggest——空闲时,重新计算并呈现低价值候选供你审查。任何层级都零自动删除——热度保持为只读排序信号,物理删除绝不自动进行;你仍通过两阶段修剪面板对候选进行操作。
- 候选规则是客观且非热度的:从未被注入且从未被召回(两个通道均为零)+ 超过明确的冷却期(disposalMinIdleDays),排除已固定 / 受保护类型 / 待处理 / 近期。技能绝不进入任何自动层级(折叠/归档保持手动)。tidy 层级(有界自动软删除)推迟到 v0.6.x,与墓碑 GC 一同进行。

检索(中文召回已修复)
- R1/R2——分词器缺陷已修复。一个贪婪的 {2,} 正则过去会将整个中文查询吞成一个 token,因此任何多词改写都会得零分。现在,连续匹配要么完整匹配,要么回退到降权的 2-gram 片段(经停用词过滤、有上限),并使用随查询长度自适应的阈值。召回率上升,精确率保持(对抗性误匹配集仍为零)。
- R3 — 标签并入 FTS 索引,在零新增依赖的情况下弥合了部分同义词鸿沟。R5 — 检索降级现在可见(融合 vs 仅 bigram vs fts 降级),而不是静默地降低质量。R6 — 扩展 CJK 范围(Ext-A / Compatibility),已验证在真实存储上对裁决器的相似度阈值造成零漂移(可通过 pnpm run test:baseline 复现)。

可观测性 / 审计
- 后台审查运行会记录到 JSONL 审计中。待处理记录携带其来源的源上下文片段。修剪预览以表格形式呈现。

所有新配置默认都是保守的(balanced / manual)——在你通过设置页面上的两个新块选择启用之前,现有行为保持不变。

v0.4.2 中的新内容

“自演化”缺失的另一半:面向人类的修剪页面。

v0.4.0/v0.4.1 为你提供了演化循环(分层审批、强化、防膨胀收敛、后台审查)。v0.4.2 在人类一侧闭合了这个循环——此前没有用于处理修剪候选的 UI,只有后端工具。现在你可以从设置页面进行修剪:

- 软删除(可逆)。 被遗忘的记忆会获得一个 forgottenAt 墓碑标记,并从召回 / 注入 / 结晶中消失,但在你恢复它们之前仍保留在存储中。MEMORY.md 镜像会获得一个单独的“## Forgotten (recoverable)”部分,因此它们绝不会与活跃记忆静默混合。
- pinned — 三层保护。 固定一条记忆后,它会在所有代码路径中被锁定:绝不会进入修剪候选,绝不会被近似重复强化覆盖,未经显式 confirm=true 绝不会被删除。该保护存在于数据层中(每次删除都会经过的两个位置之一),因此无论删除来自面板、工具调用还是未来的代码路径,它都能生效。
- 受保护类型审查区域。 preference 和 decision 记忆不可直接删除——面板会将它们显示在只读的“受保护记录(需要特殊审查)”部分中,而不是给出一个不起作用的按钮。
- 热度是只读的排序信号。 每条记忆都会获得一个幂律冷度分数 H = 1 / (1 + λ·Δt)^α。时间基准是 accessedAt || createdAt——绝不是 updatedAt(合并 / 精炼会更新 updatedAt,但这不是“访问”;将这种更新视为衰减会静默地降低正在被积极使用的记忆的优先级)。热度只用于对修剪候选排序;它绝不会自动归档任何内容。
- 两阶段面板:预览 → 执行。 阶段 1(POST /prune/preview)构建内存中的计划并返回一个 planDigest。阶段 2(POST /prune/execute)消费它。计划注册表使用原子认领(在 applyPlan 的 await 之前同步翻转 consumed 标志),因此双击 / 重试 / 重发都无法重新执行——没有它,skill-converge 会在负载下创建重复的总括技能。
- 按目标的 ETag 陈旧性检查。 每个目标都携带其在预览时的 etag。如果在执行前有其他东西修改了它,该目标会被跳过(未找到 / 已陈旧)并附上原因;计划的其余部分仍然适用。不会导致整个计划失败。
- JSONL 审计,故障开放 + 摊销环形裁剪。 每次运行都会追加到 .evolve-audit.jsonl(上限 500 行)。审计写入是故障开放*的——磁盘错误只会发出警告,绝不会阻止修剪。

设置页面中的 A2 布局:顶部是审批队列(现有),然后是新的受控修剪区块(候选 + 预览/执行 + 受保护区域 + 已遗忘列表),再下面是概览。固定行会将其复选框渲染为禁用状态。

按设计排除:本地向量模型、语义搜索、知识图谱(对优化来说太重,不是重写)。所有四种纯逻辑机制均被采用——热度、JSONL 审计、带注册表的两阶段预览→执行、空闲刷新——之所以选择它们,是因为它们增加了零新依赖,并遵循“自动检测,显式处置”原则。社区是 GitHub 上的 chenzheshushi-commits/dsh-evolve;欢迎提交问题报告。

许可证

MIT

上游仓库有新提交时邮件通知你(每天最多一封,无更新不打扰),随时一键退订。

💬 加入 DPharness 群聊

插件用法、部署报错、新插件第一时间同步——群里问,比一个人翻文档快。

点击加入 QQ 群
DPharness 群聊二维码,手机 QQ 扫码进群
扫码进群