🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

自演化记忆 chenzheshushi-commits/dsh-evolve

DeepSeek Harnessv0.0.1
chenzheshushi-commits5 天前有提交已提供中文文档扫描:含敏感能力

为 DeepSeek Harness 提供自我演化的记忆与技能生命周期。

37.2/100
综合分
11
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/10/30 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

自动兼容检查有告警:npm 同名包「dsh-evolve」归属 dushaobindoudou/dsh-plugin,装到的可能不是本插件。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add chenzheshushi-commits/dsh-evolve
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:已验证
是什么
dsh 原生插件 · security
装得上吗
本站已真实安装成功
非静态推断
L4 · 真实安装等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 5 天前
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查⚠ 装前注意

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

展开查看检查明细 ↓

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

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

验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/11/1 10:24:26

安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

可执行外部命令读写/删除本地文件发起外部网络请求
扫描于 2026/11/3(1 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

依赖的 DSH / Cordis 模块
@deepseek-ai/cordis@deepseek-ai/dsh-client-connection@deepseek-ai/dsh-client-ui-renderer@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
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

功能亮点

  • 跨会话持久记忆
  • 零token确定性召回
  • 技能与记忆抗膨胀收敛

自进化记忆 + 技能生命周期,为 DeepSeek Harness 打造——跨会话持久记忆,零 token 确定性召回,分级审批,从重复中强化学习,技能与记忆双双抗膨胀收敛。

README

由 DeepSeek 最新模型翻译生成
dsh-evolve 为 DeepSeek Harness 提供自我演化的记忆与技能生命周期。 你的智能体在会话之间会忘掉一切。这个插件给它持久记忆,把重复出现的流程变成可复用技能,而且——关键在于——让这些知识不会堆成噪音。真正的演化是变异加选择加修剪;多数记忆插件只做了第一件事。 插件出厂时是空白的。它对你和你的工作没有任何预设立场:只有机制和规则。它学到的一切都只存在你的本地安装里,绝不外传。 环境要求 | 要求 | 原因 | | 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 上跑完整测试套件。
展开完整文档(README 剩余 1 节)
dsh-evolve

为 DeepSeek Harness 提供自我演化的记忆与技能生命周期。

你的智能体在会话之间会忘掉一切。这个插件给它持久记忆,把重复出现的流程变成可复用技能,而且——关键在于——让这些知识不会堆成噪音。真正的演化是变异加选择加修剪;多数记忆插件只做了第一件事。

插件出厂时是空白的。它对你和你的工作没有任何预设立场:只有机制和规则。它学到的一切都只存在你的本地安装里,绝不外传。

环境要求

| 要求 | 原因 |
| 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.8.2/dsh-evolve-0.8.2.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 融合。不调 embedding API,不每轮调模型。CJK 文本分词正确(搜 苹果 不会匹配 水果)。
相关记忆会在每一步根据当前消息自动注入,耐久的用户偏好与事实则作为常驻快照,在每一轮开始时注入。

分级审批,而非「全部确认」

模型写入的记忆要经过一道确定性闸门,由它决定自动确认还是留待审核,判断依据只有模型无法自我美化的属性:

- 可逆性(重要程度)
- 与你已确认的内容是否冲突
- 与现有记忆是否重叠
- 这次写入能否追溯到你的原话

明显、可逆、有用户依据的写入会自动落库。有风险或不确定的写入则排队等待审核。闸门刻意忽略模型自报的 kind 字段——让一个自报标签决定自己是否豁免,等于没有闸门。自动确认的条目依然可见、可撤销,改一个配置开关就能回到「全部审核」的行为。

强化:你重复的会变强

再次观察到同一理解不会复制它,而是强化它。观察次数上升,重要度在可配置阈值处提升,并且保留质量更好的措辞,而不是盲目覆盖。置信度会显式呈现(low / medium / high),智能体据此可以把已确立的知识看得比一次性说法更重。

会改进而非堆积的技能

共享同一标签的高价值经验会结晶成 SKILL.md。新证据就地精炼已有技能——带版本,保留你的手工修改——而不是再生成一个近似重复项。

整理遵循真实生命周期:active → stale → archived。归档会把技能移出活跃目录,且可逆。内容重写必须先成功备份;归档与恢复是可逆的目录移动。插件从不自动物理删除资产。

反膨胀收敛

这是多数记忆系统跳过的那一半。

技能: 按内容相似度检测近似重复的技能,并标记因反复精炼而臃肿的文件。合并会生成一个伞形技能并归档原技能(可逆)。折叠会把层层堆叠的精炼段落压回干净的正文。从未真正被加载过的候选排在最前——既重复又没用,是最强的合并理由。

记忆: 硬性字符预算,绝不静默丢弃任何内容(超预算时返回裁剪候选,由你决定),一道闸门拦截换词后的近似重复与信息量稀薄的低信号写入,并把强化充分的项目记忆提升到全局范围。

检测始终开启,零 token 开销。每个变更操作都需你主动开启。

后台回顾

在一轮结束时(有节流),一次隔离的 LLM 处理会重放该轮的对话快照,问哪些内容值得记住。建议走同一道审批闸门——回顾者只提议,从不直接写入。

它作为独立调用运行,因此你的主对话与提示词缓存完全不受影响,并且纯文本补全,不挂任何工具,所以结构上不可能产生副作用。还能把它指向另一个模型(更便宜或更强),跟主模型分开。

弱模型降级也安全:格式不对的复盘直接跳过,最坏结果是「这一轮没学到东西」,绝不会「学错了东西」。

懂你,也按你的样子塑造工具

确认过的用户级偏好和事实会不断累积,长成一份自动扩展的配置档,你可以随时查看,按你表现出的稳定程度排序。

技能还能带一层 user-style overlay:用技能时附加一小段指令,内容来自你的配置档。底层 SKILL.md 永不改写,所以这层 overlay 完全可逆——清掉它,技能就回到原样。

维护巡检

一个工具把所有只读检查汇总成一份报告:可归档的技能、可合并的候选、臃肿文件、记忆预算、可提升的候选,以及积累的结果数据是否够多、值不值得打分。可以放心挂到外部 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 | true | 结晶/精炼技能时走一遍 LLM(false = 零 token 的确定性拼装) |
| reinforceEvery | 3 | 每提升一档重要性所需的观察次数 |
| memoryMaxChars | 20000 | 记忆字符预算(0 关闭) |
| convergeSuggest | true | 显示合并/折叠建议 |
| curatorStaleDays / curatorArchiveDays | 30 / 60 | 技能生命周期阈值 |
| ftsEnabled | true | false = 纯 bigram 召回,不用 SQLite |

LLM 只用于可选的辅助环节——技能精炼、后台复盘、技能合并。这些都是一次性调用,可以跳过,失败时回落到确定性行为。主循环里什么都不跑。

设计规则

- 绝不弄坏 harness。 每条失败路径都静默降级;插件不可能阻止启动。
- 绝不删用户资产。 归档、备份、回滚——但绝不销毁。
- 不依赖内部定时器。 会话内的工作由事件驱动;离线工作交给外部 cron 调用工具。
- 出厂即空白。 不预置任何个人数据。它学到的东西留在你的机器上,绝不打包进发行版。
- 机制优先于模型聪明。 安全性来自确定性规则,换模型只改变质量,永远不改变安全性。

v0.8.2 新变化 — 拒绝日志终于有地方落了

默认安装下,守卫的拒绝日志现在真的存在了。 v0.8.1 引入了拒绝控制面请求的日志(记录决定拒绝的 origin、host 和 sec-fetch-site),但只有设置了 $DSH_HOME 环境变量时,日志才写入该变量指向的目录。harness 解析自身 home 的规则是:设置了 $DSH_HOME 就用它,否则用 ~/.dsh;而它不会把这个变量导出给插件进程——所以在默认安装下,日志写到了空处。偏偏那正是有人需要读它的场景。

插件现在按 harness 完全相同的方式解析 harness home(共用一个解析器,插件工作区和日志都用它),并把结果传给控制面;日志目录不存在时会自动创建。日志落在 <harness home>/evolve-guard-debug.log。

v0.8.1 新变化 — 记忆归属工作区,桌面应用能保存了

项目级记忆。 一个宿主进程在所有会话间共享同一个记忆存储,于是项目级记录在任何地方都能被召回:在仓库 A 里工作的会话,只要查询文本恰好重叠,就会被注入仓库 B 的记忆。现在,从某个会话写入的记忆会打上该会话工作区根目录的标记,项目级记录只在自己的工作区内可见。user 级记录仍然全局可见;本版本之前写入的记录没有工作区标记,继续在所有地方可见(fail-open)——所以这只能阻止新的跨项目污染,不会追溯隐藏已有的记忆库。手动召回时传 allProjects: true,可主动做跨项目查询。

键是规范化后的完整工作区路径,不是目录的最后一段:两个 app 目录就是两个项目,在子目录里启动的会话不算另一个项目。可见性规则只有一个函数,召回池、近重复强化循环、待处理队列上限和写入质量评估都用它——只过滤召回会让写入侧仍然跨项目:A 工作区的写入如果恰好是 B 工作区记录的近重复,就会强化(甚至可能改写)另一个项目的记忆内容。

设置页在桌面应用里能用了。 桌面外壳用 dsh-app://app scheme 提供渲染进程页面,而回环守卫拿请求的 Origin host 去比对 Host 头——app scheme 的页面永远对不上,于是每次保存都返回 403。现在,这个 scheme 和 host 已与 loopback 源一起受信任。范围刻意收窄:Origin: null(file:// 页面会发送的值)以及其他所有应用 scheme 仍然拒绝,因为这道防护的真正分量在 loopback socket、loopback Host 和非跨站检查上。现在每次拒绝都会把决定它的三个请求头——origin、host、sec-fetch-site,绝不记录 token——写入 $DSH_HOME/evolve-guard-debug.log,这样「页面报 403」这类反馈就能从机器上直接回答,不用靠猜。

设置页不再因为模型服务商不可达而卡死。 /state 通过 llm.listModels() 枚举模型,而这一步会对账号/API 服务商发起真实 HTTP 请求。一台到不了该 API 的主机不一定报错——它可能干脆永远不回应,而 try/catch 抓不住「永远不回应」:路由停在完全没有响应上,页面什么也没渲染。现在每个服务商的列举都有上限(1.5 s),整个枚举也有上限(3 s);不应答的服务商仍然会被列出,只是模型留空(用该服务商的默认值),而不是把整个页面拖垮。

v0.8.0 新变化——运行在 harness 0.1.7 上

这个版本之所以存在,是因为 DeepSeek Harness 0.1.7 一次性改掉了本插件依赖的三个契约。它没有新增能力:每处改动都是在兑现插件在 0.1.5 上已经做出的承诺。

它又能加载了。 0.1.7 解析链接插件的 @deepseek-ai/dsh- 导入时,改为对照正在运行的 harness,而不是插件自己的 node_modules;同时它的 dsh-llm 把 CallId 改名为 ToolCallId。打包进来的 dsh-tools 副本仍在请求旧名字,导致整个插件导入失败,harness 每次启动都报 evolve (dsh-evolve): failed to import。现在所有与宿主共享的依赖都锁定到加载它的 harness 版本,浏览器那一半也不再引用已退役的 dsh-client-runtime 包(它的 Context 移到了 @deepseek-ai/cordis;slots 来自 dsh-client-ui-renderer)。

注入的通知重新成为合法的会话数据。 0.1.7 把会话日志迁到格式 v4,并直接拒绝 v3 的 { kind: 'plugin', plugin: '…' } 来源包装。写出这种形状会让 harness 一读回日志就拒绝——和 v0.5.2 里缺少 summary 造成的故障一样。现在每条注入消息都带上生产者自有的 kind plugin:dsh-evolve(正是 harness 自己的 v3→v4 迁移器为本插件推导出的值),并且统一通过一个辅助函数构造,形状不会在八个调用点之间漂移。

设置在重启后保留。 0.1.7 从本插件自己的 Config schema 推导可编辑表单,并通过配置档自己的补丁持久化编辑,然后提交到插件的实时引用里,不重新挂载任何东西。正因如此,设置页能改的每个键都声明为 .volatile(),而 store 读取的普通对象在每次提交时都从这些引用镜像——所以改动立即生效,重启后依然保留,两个视图不会各走各的。在没有设置界面的主机上(headless),写入只留在内存里,并在日志中说明这一点,而不是直接失败。

语言覆盖又能从页面上设置了。 它以前放在 harness 生成的设置表单里,而 0.1.7 还没有能渲染这些表单的客户端。现在它是本插件自己设置页上的一个控件。

新增配置

| 键 | 默认值 | 作用 |
| refineLLM | true | 结晶/精炼时跑一遍 LLM;设为 false 则零 token 组装 |
| tier1Enabled | true | 回合开始时始终开启的偏好快照 |
| maxPendingQueue | 50 | 待审队列的硬上限 |
| disposalMinIdleDays | 30 | 记忆闲置多少天后成为冷候选 |
| idleMinutes | 5 | suggest/tidy 重算前的空闲延迟 |
| approvalPromptEnabled | false | 回合内直接写入高价值记忆时是否先询问 |
| language | follow-host | 本页和注入提示词的语言:follow-host、en 或 zh |

这里每个键本来就可配置;变的是值存在哪里、怎么送到运行中的插件。没人要求在运行时调整的治理开关(curator 阈值、热度衰减、记忆预算、检索开关)仍是普通 YAML 配置,不进设置表单。

边界

两个进程共用一个 evolve 工作区时,现在争的是实例锁,而不是同一个存储。没拿到锁的实例拒绝自动工作,而不是去抢:自动 tidy 降级为一份待审列表(lockVerdict.acquired 为 false),受控清理直接拒绝(「另一个实例拥有此工作区;此处禁用清理」)。任何层级都不会删除技能——归档和回滚始终由人来做。

v0.7.0 新内容——会失败的闸门,以及英文支持

两个用户可见的修复,底下还有一个结构性修复。

检索精度(issue #2)。 一条查询只要和某条记忆共用一个两字词,就能把它召回:「编程语言」返回了一条关于用中文回复的笔记。原因是算术——片段得分为 0.6,分数下限的下界也是 0.6,所以单个偶然的 2-gram 就能独自够到下限。提高下限修不好,因为误报得分 1.7541,而真正命中的只有 0.8393:它排在了你真正想要的东西前面。

四处改动,缺一不可。标签得分按词匹配,而不是问整个查询是不是某个标签的子串(旧测试里「回复语言」对标签「语言」得 0 分——标签本来就是为了服务这些查询,结果恰恰服务不了)。片段得分减半,让片段必须累积。标签得分现在需要佐证:查询里还得有别的词出现在记录内容中。另外 fuseRRF 会对每个全文命中重新过一遍打分器——没有最后这一条前三个改动没有带来任何变化,因为单靠 BM25 排序就足以被召回。在 60 条记录的存储上实测:召回率不变,仍是 5/5;MRR 不变,仍是 1.0000;对抗性查询的结果从 5 条降到 0 条。

英文支持(issue #1)。 每个字符串都是硬编码的中文字面量。真正要紧的部分不在外观:插件会注入 相关记忆 这个标题,并另外指示模型去找这个块,所以英文环境收到的是中文标记。这是行为上的差异。

语言默认跟随 DSH 宿主 locale(ctx.settings.get('locale')),也可以在插件自己的设置里用 [follow-host | en | zh] 显式覆盖,因此中文系统上跑英文界面是可行的。检测不到任何语言时默认英文;已有安装会一次性迁移到 zh,这样升级时没人会看到界面突然变样。中文搜索的内部实现——90 条停用词表和 CJK 二元分词——没有改动,也保持原样:它们属于检索机制,不是显示文本。

能真正失败的闸门。 这个项目过去用来找同义反复断言的工具,在零处包含 process.exit、process.exitCode 和顶层 throw。它打印结果然后返回成功;CI 看到的是绿色。一个不会失败的闸门和一个什么都不守的闸门,从外面看没有区别。

仓库里现在有三个债务扫描器,每个都有冻结的范围、候选数量哨兵,以及一个必须始终被捕获的自检夹具——否则「列表是空的」和「扫描器不再看了」就是同一个结果。两套变异矩阵跑它们:0 个漏洞,0 个误报。

十个固定字符数的文本窗口没了,换成基于范围的辅助函数。它们在两个方向上都出过错:126 个字符的注释让一项顺序检查拿 -1 去比较(对无行为变化的改动永久报红),而一个否定断言在超过 2000 个字符后悄悄不再检查。

原子写入。 lib/fsync.js 从 v0.6.0 起就写明 openSync(file, 'w') 会截断,绝不能使用。writeMarker 恰恰这么做了,而且是对一个正在使用的文件,没有任何检查。固定名临时文件带来两个实测后果:植入的符号链接把一次技能保存重定向到目录之外,且不报错;两个并发写入者让其中一个留下截断的文件,也不报错。现在十个位置共用一个实现,带随机后缀和独占创建,禁令变成了一条测试,而不是一句注释。

持久性策略上移到发布层。哪些 fsync 结果应该中止发布,过去隐含在两张错误码表里,所以当 v0.6.4 把 EROFS 放进其中一张而没放进另一张时,「只读对象不得中止发布」对那个错误码就反了过来,而没有任何东西能看见。

378 个测试。上面的检索数字是在一个私有的 60 条记录存储上测的,所以仓库里也带了一份合成语料(test-fixtures/retrieval-corpus.json,源码树里造出的记录,不是安装包里的记录,能复现同样的故障和同样的修复——精度主张可被检验,无需任何人公开自己的记忆。

边界

与 v0.6.x 一致,也仍是你实际会碰到的行为:一个进程持有 evolve 工作区的实例锁。另一个进程共享该工作区时,读取不受阻,但它的自动工作会停摆——后台整理降级为只给建议,不会背着持有者软删除;受控清理则直接拒绝。手动工具在两种情况下都可用。这就是为什么自动工作看起来什么都没做,而 UI 其他方面却正常。

新增配置

| 键 | 默认值 | 作用 |
| language | follow-host | follow-host、en 或 zh。跟随 DSH 宿主语言环境,除非覆盖 |

v0.6.x 里所有可配置项仍然照旧生效:

| 键 | 默认值 | 作用 |
| disposalMode | manual | manual、suggest 或可恢复的 tidy |
| tidyMaxPerRun | 5 | 每次空闲运行自动软删除的上限 |
| idleMinutes | 5 | suggest/tidy 的空闲延迟 |
| skillProposalMode | inherit | 跟随记忆审批模式,或显式选择技能模式 |
| skillAutoMaxChars / skillMaxChars | 10000 / 40000 | 自动/人工技能正文上限 |
| approvalPromptEnabled | false | 在回合内询问是否直接写入高价值记忆 |
| approvalPromptMaxPerTurn | 1 | 每个会话回合的弹窗预算 |

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 }
(the store gets a snapshot; the settings page silently stops working)

config-liveness.test.mjs 4/4 pass <- missed it
all 326 contract tests 0 fail <- missed it
all four e2e suites pass <- missed it

/state 和 set-config 的回复都从 readConfigView(getConfig()) 渲染——正是 setConfig 写入的同一个对象。对二者任一断言,只能证明路由回显了自己的补丁。v0.6.4 删掉的那个机制测试确实能抓住这种形态,所以在那一个维度上 v0.6.4 是退步,而发布说明说的正相反。

现在存储自己作答:测试通过真实路由把 maxPendingQueue 收紧到 1,然后调用注册的 memory_remember 工具两次。store.remember() 读取 this.config.maxPendingQueue(store.js:399)来执行该上限,队列满后返回 null,所以第二次写入必须被拒绝。一个存储构造时拷贝仍认为上限是 50,并接受它。

实测结果:快照缺陷变红,向拷贝赋值变红,把存储回退到构造函数快照会让三条断言失败,而等价重构(逐键赋值,不用 Object.assign)保持绿色。

这四笔债在 v0.7.0 全部还清:reconcile() 把 durability 和 unflushed 转发进报告,fsyncTree 报告每次目录 flush 的结果,scripts/schema/ 里不再有门禁按字符数判断相邻性,publish-protocols.js 的注释现在描述代码实际做的事。

v0.6.4 新变化 —— 门禁一律按行为判断

v0.6.4 是补丁版本,起因是对 v0.6.3 的一次评审:评审复现了该版本声称的每一条(15/15 变异变红,8/8 引用数字重算无误),随后找出新门禁止步的地方。

- EROFS 是死分支,还把自己的意图弄反了。 它列在 NOT_WRITABLE 里,却不在 FSYNC_SOFT_FAIL 里,而重抛门禁先执行——于是最字面地表示「这个对象只读」的那个错误码,反倒成了抛出的那个,中止全部三条发布协议。跟 v0.6.3 的修复正好相反。只读挂载和 --read-only 容器上都能触发。现在 EROFS 软失败,子集不变式在模块加载时强制,不靠测试:无法归类的成员就是文件内部的矛盾。把 ENOSPC 放进 NOT_WRITABLE——把真实故障标成权限怪癖——现在会拒绝加载。
- 配置门禁会误杀正确的重构。 它拿 /Object\.assign\(\s(\w+)\s,/ 去匹配 index.js 并比较标识符,所以把一行改写成 for (const [k,v] of Object.entries(patch)) cfg[k] = v——行为逐字节相同——会变红,而真正的缺陷只是靠 >= 2 计数顺带抓到。误杀正确工作的门禁,只会教人无视红色。现在它把真实的 set-config 动作 POST 到真实路由,读真实存储;实测:等价重构通过,向拷贝赋值失败。
- fsync 扫描有四处盲区,全部实测。 双引号的 openSync(p, "r") 看不见(引号风格不是语义);计算出的 mode 被当作合规,而不是无法判断;flush 必须出现在 400 字符以内,而本仓库已有单行模块比这更宽;发现逻辑只读 lib/ 顶层,将来任何 lib/ops/ 都会漏掉。现在:引号归一化,计算出的 mode 上报,基于作用域的前瞻,递归扫描。
- 唯一的运行时证据能被悄悄关掉。 让只读探测返回 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 只要有任何文件拒绝刷盘就拒绝发布,于是技能树里一个 0444 文件就能直接搞坏 crystallize / refine / rollback。这把两件不同的事混为一谈:平台不支持这类 fsync,和文件是只读的。两者都不意味着字节缺失 —— 数据在尝试刷盘之前就已写入并关闭,标记的关键性质是它最后写入,而不是每次 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 —— 超过真实命中两倍多。最后这条正是任何下限都修不好的原因,也是棘轮现在断言的内容。此前棘轮会在「真实命中被杀掉」时变红,而下限改动会触发这一点,同时让漏洞大开。
- 配置接线也要断言,不只是其机制。 存储持有一个实时

object was tested; that the host hands it the same object every write path mutates
was only confirmed by reading three lines of index.js. Now asserted.
- injectionCount has one definition again. The budget tie-break read the
persisted field while the rest of the store used the effective count.

Retrieval precision itself is unchanged and still tracked as issue #2.

What's new in v0.6.2 — The guards get judged by behaviour, not by wording

v0.6.2 is a patch release: no new features, no retrieval behaviour change. It acts
on an external review of v0.6.1 that attacked the guards added in that release and
got past two of them.

- All fsync logic now lives in one module. Four copies existed, and two of them
were missing ENOTSUP from the soft-fail list, so the same unsyncable filesystem
made the transaction layer throw while the proposal layer shrugged. lib/fsync.js
is now the only place a path is opened in order to be flushed, and a test refuses
any other module doing it — discovered by scanning lib/, never a hand-written list, because a hand-written list left a brand-new module with the identical bug completely unread. (v0.6.2 shipped this claim while lib/skills.js still held one such fsync that the gate's regex could not see; fixed in v0.6.3.)
- The guard no longer trusts variable names. It used to decide "is this a file
or a directory?" by regex-matching the identifier, so renaming a parameter to
dir while reverting 'r+' to 'r' restored the original Windows bug with every
test still green. The rule is now checked at the call site, and separately proved
at runtime: on a read-only file 'r+' cannot be opened at all, so a helper that
had slipped back to 'r' reports success where the real one reports refusal.
- A failed flush can no longer be published as a success. fsyncTree returns
which files refused, and all three publish protocols check it before writing the
commit marker. The marker's entire meaning is "these bytes are on disk"; writing
it after a refused flush is a lie that recovery later trusts. On Windows this is
observable rather than silent for the first time.
- Governance limits are adjustable while running. store.js copied the config
object at construction, so lowering maxPendingQueue from 50 to 10 in the
settings page returned 200, /state showed 10, and the flood defence kept
admitting 50 until the process restarted. The store now holds the host's own
object. Reported by two consecutive reviews before it was fixed.
- A misleading comment and two flattering assertions are corrected.
lib/search.js claimed unrelated records "score exactly 0 — a wide safety gap". They score 1.41. The two smoke.mjs precision assertions that appeared to guard that gap pass only because their fixture happens to omit the shared 2-gram, and now say so and point at the failing test.todo that records the real state.
- The gates' Python dependencies are declared in the repository. They existed
only inside the CI workflow, so test:contracts on a fresh clone died with
ModuleNotFoundError — and the reason rfc3339-validator is load-bearing rather than optional was knowledge trapped in a yml file. Now scripts/schema/requirements.txt, which CI installs from, so the pins cannot drift apart.
- files no longer declares a directory that does not exist (assets).

Six mutations were run against the rewritten guards, including the two the review
used to defeat them; every one turns a guard red.

What's new in v0.6.1 — Windows platform fix and cross-OS CI

v0.6.1 is a patch release: no new configuration, no behaviour change on Linux or macOS.
It fixes one platform bug and closes the verification gap that let it ship.

- Skill proposals no longer throw on Windows. ProposalStore.create() fsynced
its files through an O_RDONLY handle and fsynced directories with no guard.
Windows FlushFileBuffers requires write access, so it raised EPERM — and since
create() is the single entry point of the proposal pipeline, skill_rollback and
every crystallize/refine/fold/converge in the default manual/balanced modes
threw instead of returning {proposed:false, reason}. Files now open r+; directory
fsync failures soft-fail through the same code list the transaction layer already
used (EINVAL/EACCES/EPERM/EISDIR/ENOTSUP).
- fsyncTree actually flushes files again. It synced regular files through the
directory helper, whose soft-fail list swallowed the resulting EPERM. On Windows
the files were therefore never flushed — silently, which is worse than the throw, because protocol C/D recovery treats a written marker as proof the tree is durable.
- CI exists. A ubuntu-latest + windows-latest matrix runs typecheck, build,
the full suite and the contract gates. v0.6.0 was green on 303 tests on one Linux
machine and still shipped the bug above; nothing short of a second OS would have
caught it.
- The built client is gated, not hand-checked. lib/client.js is a committed
artifact and files ships only lib/, so CI rebuilds and diffs it. A stale
artifact used to be caught only by remembering to run one command before tagging.
- A known retrieval hole is now visible instead of implied. A precision red-line
in smoke.mjs passed only because its fixture happened not to contain the shared
2-gram it was guarding against; phrased the ordinary way, an unrelated query
false-matches. It is recorded as a failing test.todo in
scripts/schema/f3-precision-hole.test.mjs with the measurements showing why a
threshold change alone cannot fix it. Retrieval behaviour is unchanged in this
release — the fix lands in v0.7.0 with recall/MRR evidence.

What's new in v0.6.0 — Tidy memory and governed skill evolution

v0.6.0 adds the missing safety half of self-evolution: automation may act, but every
non-trivial write has a deterministic boundary and a recovery path.

- Tidy disposal tier. manual | suggest | tidy now share one eligibility rule.
Tidy automatically soft-deletes at most tidyMaxPerRun ordinary, low-importance
memories that have never been recalled or injected and have passed the cool-off.
Pinned, importance-3, preference, decision, pending and rejected records are
never automatic subjects. Soft-deleted records remain visible and restorable.
No tier physically deletes memory. Tombstone GC is not part of v0.6.0.
- Durable operations with recovery. Every skill mutation runs as a transaction
with a manifest, a write-ahead log and a single commit point, so an interruption
leaves a state the next start can finish rather than a half-written skill.
Publishing uses the protocol the change actually needs — a new directory is one rename, a body rewrite commits the operation id inside the file it rewrites, a rollback goes through a retired intermediate, and an archive is a pure move. Cross-filesystem moves fail closed instead of degrading to copy-then-delete.
- An exit from stuck operations. A conflict or a partially-completed merge is
frozen rather than guessed at, keeps its authorization so nothing else can touch
the same target, and appears in the settings page for a roll-forward or roll-back
decision. After the commit point nothing rolls back: a converge whose second
source could not be archived reports the partial state and keeps the live merge,
because "cleaning up" would destroy work that already succeeded.
- Archives addressed by id. Several archives of one skill coexist, each with a
timestamped archiveId, and restore names the generation it wants. skill_rollback
now only ever creates a proposal, and pins the chosen backup by content hash at
proposal time so a later backup cannot change what comes back.
- Skill proposals. In manual and balanced modes, crystallize/refine/fold/converge
create a proposal instead of changing the live catalog. The settings page is the
only apply/reject surface; model tools cannot approve their own work. Select an
explicit autonomous skillProposalMode if you want immediate writes after all
safety checks.
- Stale and ownership protection. Proposal apply binds independent SHA-256
hashes for prose and semantic state. Any human edit or competing mutation makes
the proposal stale with zero overwrite. Skills are bound to a random per-install
owner id; legacy skills require an explicit claim in the Web panel.
- One mutation throat. Model tools, Web actions, rollback and automatic archive
all pass structured ownership, policy, size, secret, backup and receipt gates.
Automatic skill bodies are capped at 10,000 characters; human paths at 40,000
by default. An already oversized skill can only be rewritten smaller.
- Secret persistence guard. Strong GitHub/AWS/OpenAI/Anthropic/Slack/Bearer/PEM
patterns are blocked before memory, skill, mirror or Git persistence. Source
context and audit fields are redacted; incidents store only hashes and masked
snippets, never the original token. Ordinary prose about “password” or “token”
remains valid knowledge. Approving a quarantined finding binds to the exact
occurrences reviewed — including repeated copies — plus the scanner and normalization versions, so a re-scan that finds more cannot be waved through by an older approval.
- Objective background review. Review requires substantial foreground work.
Completed/interrupted turns qualify; error/blocked/aborted turns do not. State is
isolated per session, and successful skill-tool use issues short-lived,
single-use receipts for autonomous refine/fold/converge.
- Optional turn-open approval. When enabled, a direct high-value
memory_remember can ask yes/no inside the active turn. This deliberately does
not cover background review: that runs after turn/end, where DSH forbids an
approval request. Background suggestions continue to use the settings review
queue. The popup is off by default and limited to one per turn by default.
Cancelling or dismissing leaves the memory pending — an unanswered prompt is not consent — and declining reports the memory as rejected rather than saved.
- Web replay protection. Privileged Web actions use short-lived, same-origin,
single-use capabilities. This is CSRF/replay protection and an audit anchor; it
is not presented as proof that a human clicked. Retrying the same operation id
replays its receipt instead of being refused, so a client that lost its response
is never pushed into publishing the same change twice.

Operational boundaries:

- Two processes may point at one evolve workspace without corrupting it: the first
takes an instance lock and the second degrades to read-only for automatic work — tidy lists candidates instead of deleting them, and pruning refuses. A lock left by a crashed process is reclaimed as soon as that process is gone, not after a timeout. Running one DSH instance per workspace is still the recommended setup.
- There is an unavoidable, very small POSIX window between the final stale check
and atomic rename. Do not hand-edit the same skill while an apply is in flight.
- The plugin still ships blank; no memory, proposal, incident or owner id is in the
package. Runtime JSONL/proposal/operation files are excluded from workspace Git.

New configuration

| Key | Default | Effect |
| disposalMode | manual | manual, suggest, or recoverable tidy |
| tidyMaxPerRun | 5 | Maximum automatic soft-deletes per idle run |
| idleMinutes | 5 | Idle delay for suggest/tidy |
| skillProposalMode | inherit | Follow memory approval mode or explicitly select a skill mode |
| skillAutoMaxChars / skillMaxChars | 10000 / 40000 | Automatic/human skill-body limits |
| approvalPromptEnabled | false | Ask in-turn for direct high-value memory writes |
| approvalPromptMaxPerTurn | 1 | Popup budget per session turn |

What's new in v0.5.2

Fix: injected notices no longer make DSH refuse to load the session history.

Every message this plugin injects (memory recall, the always-on preference snapshot, checkpoint and nudge notices) is tagged source.form: 'notice'. DSH's released-v0 session format requires a notice source to also carry a string summary; this plugin never set it. Harnesses up to 0.1.0-rc.x did not validate that field, so the logs looked fine — but DSH 0.1.5-rc.2 added a v0→v1 migration that validates every event on load and refuses the entire log:

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

The result is 历史加载失败 / "history failed to load" on every conversation this plugin ever injected into — which, with Tier 1 always-on, is effectively all of them.

- All 8 injection sites now set a short source.summary. No behaviour, config, or API change; the summary is metadata DSH shows when a notice is collapsed.
- Upgrading fixes new sessions only. Logs already written are still on disk with the missing field, and the harness still refuses them. To repair those, see below.

Repairing session logs written by v0.5.1 and earlier

scripts/repair-session-logs.mjs rewrites the offending events in place. Stop the harness first, then:

see what would change, without writing
node scripts/repair-session-logs.mjs --all ~/.dsh/sessions --dry

repair in place (each modified log is backed up to <file>.bak.<timestamp>)
node scripts/repair-session-logs.mjs --all ~/.dsh/sessions

Requires Node ≥ 22 — it needs the zstd support in node:zlib that Node 20 lacks. Use the same runtime your harness runs on (e.g. ~/.local/node22/bin/node).

It is safe to re-run: repairs are idempotent, event count and seq numbering are preserved exactly (a session log's seq is dense, so nothing is ever deleted — only rewritten), and the concatenated-zstd-frame container layout is kept intact. The script self-verifies its own product and refuses to write if anything is off.

Besides the missing summary, it also repairs two unrelated refusals in the same pass, in case your logs have them: unknown historical event types written by other plugins (rewritten to a known no-op type, original payload preserved as text — note that DSH 0.1.5-rc.2 no longer accepts these even when marked ignorable), and subagent/descriptor events still on version 2.

What's new in v0.5.1

Fix: the always-on preference snapshot now reaches every new conversation.

The Tier 1 always-on snapshot — the durable user preferences/facts block injected at the start of each turn — was deduplicated with a process-global last-key. Because durable preferences rarely change, the snapshot text stayed identical, so after the first conversation injected it, every later conversation's first turn was silently suppressed and never received the block at all. The per-step relevant-recall injector had the same class of cross-session leak on its repeat-suppressor.

- Dedupe is now per-session, keyed by the session via a WeakMap. Each new conversation gets the always-on block on turn 1; within a single conversation an unchanged snapshot is still skipped (the prompt-cache protection that dedupe was meant to provide is preserved). The WeakMap is reclaimed with the session — no manual cleanup, no leak.
- Regression test drives the real apply(ctx) with two independent sessions and asserts both the cross-session injection and the within-session suppression. Retrieval baseline unchanged (5/5 recall, MRR 1.0, R6 drift 0).

No config or API changes; no migration.

What's new in v0.5.0

Autonomy becomes a user-chosen dial, and Chinese retrieval is fixed at the root.

Earlier versions hard-wired how much the memory could decide on its own. v0.5.0 makes that a product setting, on both the ingest and the disposal side — deliberately asymmetric, because an ingestion mistake is an addition (visible) while a disposal mistake is a subtraction (invisible).

Ingestion autonomy — approvalMode (three tiers)

- manual — every model write waits for your confirm. balanced (default) — reversible writes that are anchored to a literal user utterance or near-duplicate of a confirmed memory auto-confirm; everything else is pending. autonomous — any reversible, non-conflicting write auto-confirms.
- autonomous still forces conflicts and high-importance (imp 3) memories to pending — the tier split sits after the conflict/importance scan, so it's a structural guarantee, not a fragile if.
- Bounded so it can't flood the store: at most reviewMaxAutoPerTurn auto-confirms per background-review turn (rest fall to pending), and a hard maxPendingQueue cap on the one region that can be losslessly refused. Confirmed memory is char-budget bound, pending is count-bound — neither pool grows without limit.
- Background review can no longer take the anchored auto-confirm shortcut on its own say-so (anchoredToUser is caller/store-derived, never model self-report).

Disposal autonomy — disposalMode (two tiers)

- manual (default) — nothing proposed automatically. suggest — when idle, recompute and surface low-value candidates for your review. Zero auto-deletion in any tier — heat stays a read-only ordering signal, physical deletion is never automatic; you still act on candidates through the two-stage prune panel.
- Candidate rule is objective and non-heat: never injected and never recalled (both channels zero) + past an explicit cool-off (disposalMinIdleDays), excluding pinned / protected-kind / pending / recent. Skills never enter any automatic tier (fold/archive stay manual). The tidy tier (bounded auto soft-delete) is deferred to v0.6.x alongside tombstone GC.

Retrieval (Chinese recall fixed)

- R1/R2 — tokenizer bug fixed. A greedy {2,} regex used to swallow an entire Chinese query into one token, so any multi-word paraphrase scored zero. Now runs match fully or fall back to down-weighted 2-gram fragments (stopword-filtered, capped), with a query-length-adaptive threshold. Recall up, precision held (adversarial false-match set stays at zero).
- R3 — tags fold into the FTS index, bridging part of the synonym gap at zero new dependency. R5 — retrieval degradation is now visible (fused vs bigram-only vs fts-degraded) instead of silently dropping quality. R6 — extended CJK ranges (Ext-A / Compatibility), verified to cause zero drift in the adjudicator's similarity thresholds on the real store (reproducible via pnpm run test:baseline).

Observability / audit

- Background review runs land in the JSONL audit. Pending records carry the source-context snippet they were drawn from. The prune preview is tabular.

All new config is conservative by default (balanced / manual) — existing behavior is unchanged until you opt in via the two new blocks on the settings page.

What's new in v0.4.2

The missing half of "self-evolving": the human-facing pruning page.

v0.4.0/v0.4.1 gave you the evolution loop (tiered approval, reinforcement, anti-bloat convergence, background review). v0.4.2 closes the loop on the human side — there was previously no UI to act on prune candidates, only back-end tools. You can now prune from the settings page:

- Soft-delete (reversible). Forgotten memories get a forgottenAt tombstone and disappear from recall / injection / crystallization, but stay in the store until you restore them. The MEMORY.md mirror gets a separate "## Forgotten (recoverable)" section so they never silently mix with active memories.
- pinned — three-tier protection. Pin a memory and it is locked from every code path: never enters prune candidates, never overwritten by near-duplicate reinforcement, never deleted without an explicit confirm=true. The protection lives in the data layer (one of the two places every delete goes through), so it holds regardless of whether the delete came from the panel, a tool call, or a future code path.
- Protected-kind review area. preference and decision memories are not direct-deleteable — the panel shows them in a read-only "Protected records (special review needed)" section rather than giving a button that does nothing.
- Heat is a read-only ordering signal. Each memory gets a power-law coldness score H = 1 / (1 + λ·Δt)^α. Time basis is accessedAt || createdAt — never updatedAt (merging / refining bumps updatedAt but that is not "access"; treating such a bump as decay would silently demote actively-used memory). Heat only orders prune candidates; it never archives anything automatically.
- Two-stage panel: preview → execute. Stage 1 (POST /prune/preview) builds an in-memory plan and returns a planDigest. Stage 2 (POST /prune/execute) consumes it. The plan registry uses atomic claim (synchronous consumed-flag flip before the applyPlan await) so double-click / retry / resend cannot re-execute — without it, skill-converge would create duplicate umbrella skills under load.
- Per-target ETag staleness check. Each target carries the etag it had at preview time. If something else mutates it before execute, that target is skipped (not-found / stale) with a reason; the rest of the plan still applies. No whole-plan failure.
- JSONL audit, fail-open + amortized ring-trim. Every run is appended to .evolve-audit.jsonl (500-row cap). The audit write is fail-open — a disk error warns, never blocks the prune.

A2 layout in the settings page: approval queue (existing) at top, then the new controlled-prune block (candidates + preview/execute + protected area + forgotten list), then overview below. Pinned rows render their checkbox disabled.

Excluded by design: local vector models, semantic search, knowledge graphs (too heavy for an optimization, not a rewrite). All four pure-logic mechanisms adopted — heat, JSONL audit, two-stage preview→execute with registry, idle refresh — were chosen because they add zero new dependencies and respect the "detect automatically, dispose explicitly" principle. The community is chenzheshushi-commits/dsh-evolve on GitHub; issue reports welcome.

License

MIT
预览分享卡片长什么样 ↓chenzheshushi-commits/dsh-evolve
分享 · DeepSeek Harness Hub
chenzheshushi-commits/dsh-evolve

为 DeepSeek Harness 提供自我演化的记忆与技能生命周期。

这是你的仓库?认领条目

回到顶部