dsh-wikiskill-experience
跨会话、跨项目的经验编译器:把 agent 踩过的坑与验证过的打法,编译成一份不可篡改的持久 wiki,并在之后的会话里以一段短描述性索引的形式注入;在此之上再叠一个证据闸门控制、永不自动发布的程序性回路(提案 → 用户批准 → 可回滚的 SKILL.md)。
设计来源:WikiSkill: Compiling Agent Experience into Persistent Knowledge for Skill Evolution(arXiv:2608.27454v1)+ 本仓库的双回路改造。Host-only Cordis bundle,无运行时依赖、无网络访问、插件内部不调用 LLM。
English summary. A Host-only Cordis bundle for DeepSeek Harness that compiles agent experience into a persistent wiki, injects a short descriptive index into later sessions, and adds a gated procedural loop (P2 proposals, P3 user-approved
SKILL.mdpublication) that can never self-publish and can be rolled back independently of the wiki. Four tools:wikiskill_record,wikiskill_hint,wikiskill_propose,wikiskill_release.
1. 它解决什么问题
一次会话里学到的教训,默认活不过这次会话;写进 AGENTS.md 又会被下一次"优化"冲掉,且无法回滚、无法整体重来。
本插件把经验拆成两层,两层走完全不同的演化路线:
| 回路 ① 描述性(P0 + P1) | 回路 ② 程序性(P2 + P3) | |
|---|---|---|
| 产出 | wiki:raw/ → patterns/ → index.md |
SKILL.md(可执行技能) |
| 默认 | 常开 | 常开,但闸门 + 只干预演 |
| 失败代价 | 低:只是"看过什么根因"的知识 | 高:会真的改变 agent 行为 |
| 回滚 | 永不回滚(它是审计底账) | 可以回滚(删 SKILL.md 即可) |
| 谁能触发 | agent 调 wikiskill_record |
提案:agent;发布:只能用户本人 |
关键隔离:门控结果永不回写 patterns/。wiki 和 skill 是两条独立可审计的账,互不污染。
2. 安装
要求:DeepSeek Harness(带 plugin_manager),Node.js ≥ 20。插件是 Host-only bundle,不需要重启进程,装完即生效。
版本窗口:engines.node >= 20,engines.dsh = ">=0.2.2-rc.1 <0.3.0-0"(本地实测运行时是 0.2.2-rc.1;DSH 会在安装前就按这个范围拦不兼容版本,不会等装完才炸)。
方式 A:从本地目录安装(已验证)
plugin_manager action=install_bundle target="<绝对路径>/wikiskill-plugin"
方式 B:从打包产物安装
cd wikiskill-plugin
npm pack --pack-destination dist # 产出 dist/dsh-wikiskill-experience-0.1.0.tgz
然后把 dist/*.tgz 的绝对路径作为 install_bundle 的 target。
方式 C:从 GitHub 直装(git 渠道,已发布)
plugin_manager action=install_bundle target="git+https://github.com/CHIPINGHSIEN/dsh-wikiskill-experience#<commit-sha>"
不给 #<commit-sha> 就用默认分支 HEAD(不推荐:内容会随仓库变动)。固定 commit 才是可复现的安装,市场索引里的 git 条目也是这个形态。
本机(
github.com:443不通)请用 SSH/443 等价形式,已实测装通:plugin_manager action=install_bundle target="git+ssh://git@ssh.github.com:443/CHIPINGHSIEN/dsh-wikiskill-experience.git#ca7fa719b62cdf6be1a25e5d005ba1f7ecde7db1"上面的
git+https形式在能访问github.com的网络上是标准写法,本机无法验证。
方式 D:从 npm 安装
plugin_manager action=install_bundle target="dsh-wikiskill-experience" registry="https://registry.npmjs.org/"
不写版本号装 latest;要可复现就写 dsh-wikiskill-experience@<version>。
装完怎么确认
cordis_inspect_query host / Tool / listTools里应出现 4 个工具:wikiskill_record、wikiskill_hint、wikiskill_propose、wikiskill_release(后两个由p2Enabled/p3Enabled控制)。- 数据根目录被创建:默认
<DSH_HOME>/experience/wiki/。 - 插件管理页的 bundle 详情应显示标题 "WikiSkill experience" 与本地化描述、自有图标(
locale/en.json、locale/zh.json、icon.svg)。
卸载
plugin_manager action=remove_bundle target="dsh-wikiskill-experience"
卸载只移除插件:<DSH_HOME>/experience/wiki/ 里的数据不会被删(那是你的经验底账),已发布的 SKILL.md 也留在 skill root,需要时用 wikiskill_release 的 rollback 单独处理。
3. 四个工具
| 工具 | 作用 | 会写文件吗 |
|---|---|---|
wikiskill_record |
记录一条经验(九个结构化字段);追加 raw/YYYY-MM-DD.jsonl + logs.md,然后重编译 wiki |
会(只写自己的 root) |
wikiskill_hint |
只读:返回最近轮次观测到的候选触发信号(工具失败 / step 报错 / 疑似用户纠正) | 不会 |
wikiskill_propose |
P2:status 报资格闸 / draft 产原子草案进 p2/deferred-proposals.md / reset 清队列 |
draft 时写队列,绝不写 SKILL.md |
wikiskill_release |
P3:status / publish(默认 DRY-RUN,需用户 token,且只发布队列里已存在的草案)/ rollback / receipts |
仅经用户批准后写/删一个 SKILL.md |
wikiskill_record 的九字段
patternId、kind(failure/strategy)、title、errorDescription、rootCause(必须回答 WHY)、when(可迁移的场景条件)、general(策略级回避方法)、projectContext(只属于本项目的上下文)、evidence(证据指针);另有 transfer(universal / conditional / project-only)。
rootCause 讲不出 WHY、general 写成底层 workaround 的记录,就是坏记录——而 wiki 永不回滚,坏记录会永久留下。所以语义判断由 agent 做,插件只做确定性编译。
P2 资格闸(三条阈值 + rubric 冻结)
minCases ≥ 20 且 最大重复次数 ≥ 5 且 去重场景数 ≥ 3 且 rubric.md 已冻结,四条全过才允许 draft。参数可用 minCases / minRepeat / minScenes 显式覆盖,覆盖值会在返回值里明确报告,不静默。
P2 打开 ≠ 绕过闸门:真实库只有 4 条记录时,
status会返回eligible:false与4 < 20,按规则"停止、不启动演化"。这是设计,不是故障。
USER-APPROVED 契约
publish / rollback 只有在用户本人在自己的指令里给出 approvalToken: "USER-APPROVED" 时才真正执行;否则一律 DRY-RUN。工具描述里写死了 "agent tools cannot self-approve"——agent 自己伪造这个 token 等同于不生效。
4. 硬保证
- 会话日志只读;不新增任何
SessionEvent类型。 - 确定性信号只进内存 hints,绝不自动写入
raw/或index.md。 - 可靠性契约:可选服务故障永不让工具调用 reject;
ok:true时raw/与logs.md始终一致;编译/读取失败显式诊断,绝不谎报"空库"、绝不把陈旧索引当当前状态;同输入编译出同字节。 - wiki 永不回滚;门控结果永不改写
patterns/。 - 发布出去的
SKILL.md落在 watched skill root,删掉即可回滚,不牵动 wiki。 - 插件只写自己的
root(及配置的 skill root);不读写 profile 的cordis.patch.yml。 - 所有注册都由 effect 托管,卸载即清理。
5. 配置
bundle 自带 cordis.patch.yml,默认值如下。要改就在 profile 的 cordis.patch.yml 里用同一 id(wikiskill-experience)覆盖——注意:覆盖会替换整个 config,请复制整块再改。
| 键 | 默认 | 说明 |
|---|---|---|
root |
'' |
'' = <DSH_HOME>/experience/wiki;也可给绝对路径 |
enabled |
true |
false 仅关掉注入与工具注册 |
injectSection |
true |
是否每步注入短索引 |
mirrorProjectLayer |
false |
另在 <cwd>/.dsh/experience/raw/ 写一份镜像(尽力而为,失败不阻塞主写入) |
maxIndexLines |
12 |
注入索引最大行数(1–50) |
topN |
8 |
注入条目上限(1–20) |
p2Enabled |
true |
注册 wikiskill_propose |
p2MinCases |
20 |
闸门:最少标注案例数 |
p2MinRepeat |
5 |
闸门:单一模式最大重复次数 |
p2MinScenes |
3 |
闸门:去重场景数 |
p3Enabled |
true |
注册 wikiskill_release + 命中回执 |
p3SkillRoot |
'' |
'' = <DSH_HOME>/skills(rank 400 的 watched root,写入即热加载) |
数值型配置在激活时会被夹到合法区间(越界不报错,取边界),所以手写配置不会把插件弄崩。
6. 数据布局
<root>/ 默认 <DSH_HOME>/experience/wiki
├── raw/YYYY-MM-DD.jsonl 不可变经验记录(append-only,内容视为 untrusted data)
├── patterns/<patternId>.md 一页一模式(确定性编译产物)
├── index.md 短目录:PROBLEM + ROOT CAUSE + FIX
├── logs.md append-only 演化日志
├── stats.md 只读统计(绝不作为闸门输入)
├── manifest.json schemaVersion / 启用阶段
├── README.md 说明
├── skills/ 永远为空 —— 描述性回路与程序性回路的分界线
└── p2/ rubric.md / deferred-proposals.md / ...(仅 p2Enabled)
<DSH_HOME>/skills/wikiskill-*.md (仅 P3 发布后)
p3/ 目录(releases.md、hit-receipts.md、README.md)在启用 P3 时创建。
7. 验证状态(诚实版)
已在真实环境验证:
- 插件以
dsh-wikiskill-experience@0.1.0在 Desktop profile 中link安装并激活(application: applied、warnings: []);Tool.listTools中四个工具各出现恰好一次(无新旧重复注册),profile 的 bundles 列表已无旧名。 - 端到端 P3 实机链路:资格闸在默认阈值下正确拒绝(
4 < 20; max repeat 2 < 5)→ 显式覆盖被报告 → 无 token 时 DRY-RUN → 用户给出USER-APPROVED后写出SKILL.md→skill工具成功加载 → skill 目录里出现该技能 → 命中回执0 → 1→ wiki 未回滚。 node tools/verify.mjs:默认 50/50 通过(注册面 / 布局 / 描述回路写入一致性 / 闸门拒绝 / dry-run 不落盘 / 输出 schema 一致性);node tools/verify.mjs --publish64/64 通过(额外覆盖「无草案的批准发布被拒绝」→ 显式降阈值造草案 → 批准发布 → 回滚)。- 打包物自证:
npm pack产出 10 个文件 / 33.3 kB;把 tgz 解到独立临时目录后node --check index.js与node tools/verify.mjs --publish64/64 通过 —— 打出来的包自包含、可自证。 - 改名重装不影响数据:
<DSH_HOME>/experience/wiki的记录/patterns/p2/p3 与已发布 skill 均未被触碰。
未验证 / 已知盲区:
- 工具返回值最终由 Harness 的
defineTool按output.schema校验(additionalProperties:false)。随包自检只能断言顶层 schema 一致性,无法复现该层;真实校验以 Harness 运行结果为准。 files白名单只对npm pack生效;本地目录安装是 link 整目录,不受files过滤。- 无 Client UI、无设置面板。
settings.section等槽位可用,但 Client 半边的数据通道未在本安装中确证,按"无证据不猜"不实现。 - P2 闸门从未在真实数据上放行过(4 < 20),
draft只在测试与显式降阈值时跑通过。 - 改名重装后本次进程内无法区分「新代码代际」是否已生效(不真做一次批准发布就无法观察守卫分支);进程重启后必然加载新代际。
- Windows 下无法用
chmod造出真实的 EACCES,权限类失败路径只有代码级保证。
8. 已知边界与设计取舍
- Host 插件没有 LLM:论文里 "Wiki Maintainer" 的根因分析由 agent 调
wikiskill_record时填九个字段承担;插件只做确定性编译与注入,每步 0 次模型调用。 - 触发不等于自动写经验:确定性信号只产生候选 hints,语义判断留给 agent。否则 wiki 会被低质量记录永久污染(它永不回滚)。
cwd/sessionId归属是 best-effort,取不到记unknown,不影响主流程。- 每条 raw 记录带
wikiInjected,标记该会话是否真的看到过注入索引,供将来筛"干净 rollout"。 - 发布名规范化:
wikiskill-<patternId>,_/.转-,以满足 skill 名[a-z0-9]+(-[a-z0-9]+)*的硬约束(不满足会被静默跳过)。
9. 开发
node --check index.js # 语法
npm run verify # 自检(临时目录,不碰真实 wiki)
npm pack --dry-run # 查看真正会被发布的文件
源码刻意保持纯 ASCII(Windows 上的字节级编辑曾两次破坏 UTF-8);中文只出现在 locale JSON、README 与文档里。index.js 不 import 任何 @deepseek-ai/*——本地 link 安装无法解析 profile 的 node_modules,所以一切通过 ctx.* 服务与 Node 内置模块完成;export const inject 必须声明每个用到的 ctx.<service>。
10. 版本与许可
- 版本策略:SemVer。当前
0.1.x——首个公开版本,配置键与工具名已稳定,但 P2 放行路径尚无真实数据验证,故意不标 1.0。 - 许可:MIT。第三方图纸/素材若引入须保留署名;本包图标为原创。
- 改了什么:见 CHANGELOG.md。
11. 发布(给维护者)
社区现状(2026-11-09 实测)
DSH 插件有两条真实分发路径,DSH 都能装:
- npm 公共 registry(
https://registry.npmjs.org/)——主流。社区插件索引 1000 条里绝大多数是这个来源,install target 形如name@version+ registry。 - Git 直装——少数。install target 形如
git+https://github.com/<repo>#<commit>&path:/...,固定 commit,不需要 npm 账号,但每发一版都要手换 commit、没有 semver 升级。
社区收录走 awesome-dsh-plugin 列表聚合(自动抓 GitHub 上带 dsh-plugin topic 的项目,再人工复核后收录),收录不代表安全审查。
两条渠道各自管什么
| 渠道 | 安装 target | 适合谁 | 怎么升级 |
|---|---|---|---|
| git(GitHub 直装) | git+https://github.com/CHIPINGHSIEN/dsh-wikiskill-experience#<sha> |
想看到源码、固定 commit、不依赖任何 registry | 手工换成新 commit |
| npm | dsh-wikiskill-experience@<version> + registry |
一条命令装、按 semver 收更新 | plugin_manager 的 update / listVersions |
两者不冲突:git 仓库是源码与历史,npm 包是可升级的制品。市场索引按包名一条记录,同一个包通常只会展示其中一个来源。
本机网络约束(实测,会影响你复制命令)
| 目标 | 结果 |
|---|---|
api.github.com:443(gh CLI 走这个) |
✅ 通 |
ssh.github.com:443 |
✅ 通,且已有 SSH key 完成认证 |
github.com:443(git over HTTPS 走这个) |
❌ 20 秒超时,不通 |
所以:推送用 SSH/443(仓库 remote 已设为 ssh://git@ssh.github.com:443/CHIPINGHSIEN/dsh-wikiskill-experience.git);安装时 git+https://github.com/... 在本机会卡住,等价可用的形式是 git+ssh://git@ssh.github.com:443/...#<sha>。市场索引里记录的 canonical 形式是 git+https://github.com/...——那在能访问 github.com 的网络上是标准形式,本机无法验证,不要把两者混为一谈。
前置条件
- git 侧不需要单独配 git token:本机
gh已登录 GitHub(token scope 含repo),仓库内已配置credential.https://github.com.helper = !gh auth git-credential,推送直接用已有登录态。只有要在别的机器上推送时才需要新凭据(gh auth login或 SSH key)。 - npm 账号并已登录:
npm whoami --registry=https://registry.npmjs.org/。本机当前返回ENEEDAUTH(未登录),需要npm adduser(交互式,2FA 会要 OTP)或 granular access token。 - 包名可用:
npm view dsh-wikiskill-experience version --registry=https://registry.npmjs.org/→ 返回 404 才说明没被占。 - registry 要对:本机 npm 默认 registry 是
https://registry.npmmirror.com(国内镜像,不能 publish),发布必须显式--registry=https://registry.npmjs.org/。 - 清单已就绪:无
private、有license/README/CHANGELOG/LICENSE、files白名单、dsh.bundle.patch、exports含./locale/*.json与./icon、无构建步骤(纯 JS)、engines.dsh已声明。 - 建议补:
author、repository、homepage、bugs(npm 页面与插件详情页会用到;当前留空)。
步骤
node --check index.js
node tools/verify.mjs --publish # 64/64
npm pack --dry-run # 复核真正会发布的文件列表
npm publish --registry=https://registry.npmjs.org/
发布后用户侧安装:
plugin_manager action=install_bundle target="dsh-wikiskill-experience@0.1.0" registry="https://registry.npmjs.org/"
npm 上同一个版本号不可复用:0.1.0 一旦发出去,后续改动必须升版本。
No comments yet. Be the first to write one.