DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

yangyiqun747 /

yangyiqun747/dsh-plugin-playbook

Verified

Playbook for DeepSeek Harness: turn a successful task into a reusable SOP + pitfall list, then replay it on similar tasks as native DSH skills.

★ 0 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHub
READMESource: main@c6527091

dsh-plugin-playbook

DeepSeek Harness 的经验复用 + 交付闸门插件:一次任务成功跑完后,把「可复用的 SOP + 踩过的坑」沉淀成一条 playbook;下次遇到同质任务时,它作为原生 Skill 出现在技能目录里,模型按需加载并照着做。 同一个任务族累计到足够样本后,SOP 可以升级成交付闸门:执行前必须让用户 review, 交付前必须逐项拿到客观证据,否则写文件的动作会被硬拦截。

一句话:成功经验 → 结构化 playbook → 同质任务自动召回 → 用户确认成闸门 → 交付前强制达标。

它做了什么

贡献 说明
5 个经验工具 playbook_save / playbook_search / playbook_get / playbook_promote / playbook_feedback
6 个闸门工具 gate_status / gate_propose / gate_confirm / gate_start / gate_check / gate_finish
1 个硬拦截守卫 tools/pre-execute 上拦住 write / edit / present,直到已确认的 L2+ 闸门逐项通过
1 个 Skill Provider active 状态的每条 playbook 都以 playbook-<id> 出现在技能目录,用内置 skill 工具加载
1 个斜杠命令 /playbook list | show <id> | promote <id> | deprecate <id> | draft <id> | stats | gates [id]
2 段系统提示 经验库用法(playbook:usage)+ 当前闸门状态播报(playbook:gates)

存储

工作区内的纯 Markdown,可 git、可手改、可分享:

<workspace>/.dsh/playbooks/<id>.md     # 经验
<workspace>/.dsh/gates/<id>.md         # 闸门
---
id: "windows-sandbox-build"
title: "Windows 沙箱里跑构建"
status: "active"          # draft | active | deprecated
scope: "project"
tags: ["windows", "sandbox", "build"]
whenToUse: "需要在沙箱内执行 pnpm/node 构建时"
created: "2026-01-01T00:00:00.000Z"
updated: "2026-01-02T00:00:00.000Z"
sourceSession: "abc123"
stats:
  uses: 3
  ok: 2
  fail: 1
  lastUsed: "2026-01-02T00:00:00.000Z"
  lastOutcome: "ok"
---

# Windows 沙箱里跑构建

## 何时使用
...
## 前置条件
## SOP
## 坑
## 验证
## 证据

文件名 <id> 会被规整成 ASCII kebab-case:因为 active 条目要变成原生 Skill, 而 skill 名(playbook-<id>)必须是 ASCII。规则是抽掉标题里的 ASCII 字母数字拼成 kebab (「为 DSH 开发…Host 插件」→ dsh-host);标题里完全没有 ASCII 时退回 pb-<8位内容哈希>。 中文标题本身不受影响,完整保留在 frontmatter 的 title 字段里,检索和展示都用它。

生命周期

playbook_save  →  draft        只有你(用户)确认后才转正
playbook_promote → active      active 才会作为 Skill 暴露、才会被召回
             ↓ 复用
playbook_feedback(ok|fail)     写回 stats
             ↓ 连续失败
        自动降级 → draft / deprecated

自动降级规则(只在 active 上触发):

  • fail >= 2 且 ok === 0 → deprecated(从来没成功过,直接淘汰)
  • fail >= 3 且 fail > ok * 2 → deprecated(成功过但基本不灵)
  • fail >= 2 且 fail > ok → 退回 draft(需要修订)

顺序不能反:draft 分支必须排在最后,否则条目在第 2 次失败时就离开 active, 后面那些 active 专属的 deprecated 判断会变成永远够不到的死代码。

召回方式

  1. Skill 目录:active 条目以 playbook-<id> 出现,description 用 whenToUse,模型自己判断相关性后加载。
  2. 主动检索:playbook_search 按 tags(权重 6/4)+ 关键词(标题 5、标签 4、何时使用 3、正文 1)打分, 并按 stats.ok/fail 微调——已验证有效的排在前面。
  3. 全文:playbook_get。

交付闸门

经验库解决「怎么做」,闸门解决「做完敢不敢交」。闸门的定义只能由用户确认,插件只能提议。

闸门等级与风险分

风险分把一个任务族量化成 R,再由 R 决定门有多硬:

D = clamp01( mean(改动面, 链路长度, 认知密度) × (有客观验证手段 ? 0.7 : 1) + (不可逆 ? 0.3 : 0) )
P = runs === 0 ? 0.5 : passed / (runs + reworks × 2)
R = 0.5 × D + 0.5 × (1 − P)
R 等级 行为
< 0.25 L0 不设闸门
0.25 – 0.5 L1 逐条自检并列证据(软提醒,不拦截)
0.5 – 0.75 L2 客观验证,write/edit/present 被硬拦截
≥ 0.75 L3 同 L2,另外要求独立验证者:至少一个必过项必须由别的 agent 自己调 gate_check 记录

P 里用户返工(reworks)的权重是普通成功/失败的 2 倍——用户被迫纠正的代价比一次失败更大。

流程

1. gate_status            看本会话与工作区里有哪些闸门、历史通过率
2. gate_propose           提议一条闸门(写入时为「未确认」,不拦截任何动作)
3. gate_confirm           通过原生提问通道直接问用户;用户同意后才落库
4. gate_start             先通过原生提问通道把本次方案交给用户 review;
                          用户点「开始执行」后才启用闸门(顺带尽力切进原生 plan mode)
5. gate_check ×N          每项记录客观证据(命令 + 退出码 + 输出摘要)
6. gate_finish(pass)      全部必过项就绪 → 放行交付,写回统计
                          (L3 时另外要求第 5 步里至少一项由别的 agent 记录)

不想经过模型时用斜杠命令直接看:/playbook gates 列出工作区里的闸门(等级、是否已被用户确认、 通过率、按当前数据建议的等级),/playbook gates <id> 看单个闸门的检查项与历史。

闸门状态按工作区存放,不按 agent

gate_start 把会话建在工作区的闸门目录上,所以同一个工作区里的所有 agent 共用一条闸门:

  • 用原生 subagent 派出去的子 agent 落地在同一个会话,它自己调 gate_check 记的证据会被标记 verifier: <子 agent id>,并计入 independent;
  • 子 agent 的 write/edit/present 一样会被硬拦截;
  • gate_finish 只有开启闸门的那个 agent能调,子 agent 会被告知改用 gate_check。

这是 L3「独立验证者」的实现方式——不是让模型声明「我找了人复核」,而是让另一个 agent 自己 调用工具、由宿主填上它的身份。模型无法伪造。

四条不变量

  1. 不许自证放行:gate_confirm(确认闸门定义)和 gate_start(执行前 review 方案)都用 ctx.userQuestions.ask 直接问用户,答案由人在界面上给出,模型说了不算;模型只能在原生通道 不可用时用 user_confirmed 兜底,且兜底这件事会记进 history / 工具输出(confirmed_via / reviewed_via)。
  2. L2 以上必须有客观证据:gate_check 要求命令 + 退出码 + 输出摘要,自评不算证据; L3 还要求至少一条证据的记录人不是开启闸门的那个 agent。
  3. 闸门定义只能由用户确认后变更:gate_propose 写出的永远是 confirmed_by_user: false; 连等级被改动都要重新确认。
  4. 必须有熔断与逃生舱:同一个闸门连拦 2 次(MAX_BOUNCES)后自动打开熔断、放行并把判断权交回用户; 用户说「这次不用闸门」时用 gate_finish(exempt) 出闸,豁免不计入统计。

失败时的行为(降级保护)

守卫自己出错时绝不会静默放行:它会把错误写进闸门状态段落、警告用户,然后按「未通过但放行 + 警告」处理。

与已有机制的关系

  • 不造轮子:执行前 review 用原生 ctx.userQuestions.ask(与内置 ask_user_question 同一条 通道);动作级阻断用原生 tools/pre-execute(纯数据通道);闸门状态播报用原生 ctx.systemPrompt.section。插件不 import 任何 @deepseek-ai/*。
  • plan mode 只是尽力而为:首次真实运行里 ctx.get('planMode') 在插件上下文返回空 (详见下面「实测记录」),所以 gate_start 不再依赖它——用户 review 走的是提问通道, plan mode 能拿到就顺带切、拿不到就把原因写进 plan_mode 字段。
  • 不叠门禁:任务已经跑在 AgentTeams 团队里时,用它的 requirements/review verdict, 闸门只负责把 verdict 回写成 gate_check 的证据。
  • 信号共用:playbook_feedback 的 ok/fail 同时是闸门升降级的输入。

配置

cordis.patch.yml 的 config:

- insert:
    - id: playbook
      name: dsh-plugin-playbook
      config:
        dir: .dsh/playbooks      # 经验库,相对工作区
        gateDir: .dsh/gates      # 闸门库,相对工作区
        promptSectionOrder: 140  # 系统提示段落排序
        slashCommand: true

安装

dsh plugin --profile desktop add <本目录的绝对路径>

卸载:dsh plugin --profile desktop remove dsh-plugin-playbook。

profile 被 pnpm 卡住时:如果 install_bundle 报的错跟本插件无关(例如 ENOENT ... dsh-plugin-whale-maid-1.0.0.tgz),那是 profile 的 pnpm-lock.yaml 里 某条 file: 依赖指向了已删除的本地压缩包——pnpm 每次 install 都会去读它。 修法:在对应源目录执行 pnpm pack --pack-destination <lockfile 期望的目录>, 再用 SHA512 重算并更新 lockfile 里该条目的 integrity。

测试

npm test
# 等价于 node --test "tests/*.test.mjs"

注意别写成 node --test tests/,Node 会把它当模块路径而报 MODULE_NOT_FOUND。

闸门层的实测记录

以下都是真实宿主里的运行结果,不是设计推测:

机制 实测结论 证据
tools/pre-execute 硬拦截 ✅ 生效 闸门激活时 write 被拒,错误原文含 交付闸门「…」(dsh-host, L2) 尚未通过,已拦截 \write`。缺证据:syntax, unit, no-native-import, module-import, activation, restart`;探针文件未被创建
ctx.userQuestions.ask 确认闸门 ✅ 生效 gate_confirm 返回 已确认为 L2(确认来源:user-question),用户在界面上点的按钮被真实记账
gate_status / gate_propose / gate_check / gate_finish ✅ 生效 完整跑通 propose → confirm → start → check×7 → finish(fail)
ctx.get('planMode') ❌ 插件上下文取不到 gate_start 曾返回 plan mode:unavailable;官方 Service 目录写的访问方式是 optional: {expression: 'ctx.get("planMode")', requiresUndefinedCheck: true},但同一个 ctx.get 取 userQuestions 是成功的 → 改为「尽力而为 + 失败原因写进输出」
gate_propose 的 factors 落盘 🐛 曾有 bug,已修 首次真实调用写出 factors: 全 0,而同一处 assess 算出 D=0.86 → 漏传 factors,normalizeGate 补了默认零值;修法:导出 normalizeFactors() 并显式写入,回归测试 gate_propose persists the risk factors it scored with
optional 检查项失败 不阻塞 pass readme 记为 failed 时 gate_check 返回 证据为失败:(无)——failedEvidence 只统计 required 项
L3 独立验证 ✅ 生效 派原生 subagent 复跑验证:它的 gate_check 返回 检查项 \unit` → passed(记录人:adacdbbe-dc41-4b51-806c-56c3b920a2e9,独立验证)(root 是 session-d509ba29-8737-45c1-b9be-9a18e2fb151a,两者 id 不同),提示段落随之出现 L3 独立验证已覆盖:unit;它自己跑出的 tests 68 / pass 68 / fail 0` 与我的记录一致
gate_finish(pass) 拒绝放行 ✅ 生效 activation 记为 failed 后调用,返回 Error: cannot pass: missing evidence for []...; failed items [activation],没有放行
提示段落对 failed 项的播报 🐛 曾有 bug,已修 旧版 sectionText 把「有记录」当「已通过」:activation 已是 failed 仍播报「必过项证据已齐」。现在会播报 ⚠ 必过项证据为 failed:activation(补一份通过证据,补不上就只能 gate_finish(outcome="fail"),不许放行);回归测试 the gate section names failed items instead of announcing the gate is ready
重复 install_bundle ⚠ 会返回 application: failed 包已 link 到 profile 时再装,返回 {"stage":"install","enabled":true,"changed":false,"application":"failed","error":{"code":"ambiguous-install"}}。这不代表插件没激活:node_modules/dsh-plugin-playbook 仍是指向本目录的 Junction、profile 的 dsh.profile.bundles 仍含它、新工具照常可调用
闸门会话的生命周期 ⚠ 随每次 apply 重建 lib/gate-tools.js:215 的 const sessions = createGateSessions(); 在 registerGates 内 → set_bundle 开关或任何重装都会清空在飞的闸门证据。闸门激活期间不要重装
/playbook gates 斜杠命令 ✅ 生效 对着真实闸门文件跑:列表给出 ✔ L3 dsh-host 为 DSH 开发并热装本地 Host 插件 + 通过率 0%(跑 2 · 过 0 · 失 2 · 返工 2)· R=0.918;gates <id> 打出全部 7 个检查项的 [必过]/[可选] 标记与历史;未知 id 与拿不到工作区目录各有明确报错

闸门自己的三次运行结果记在 .dsh/gates/dsh-host.md:第一次 通过 0/1 · 失败 1 · 返工 1;第二次 通过 0/2 · 失败 2 · 返工 2;第三次 通过 1/3 · 失败 2 · 返工 2——第三次是干净的 pass。 第二次的失败不是插件缺陷:syntax / unit / no-native-import / module-import / restart 全部通过 (其中 unit 还由独立 subagent 复跑确认),只有 activation 这一项按字面要求 application: applied, 而重复安装拿不到——这是检查项措辞写成了不可重跑的形式,教训是「写检查项时要让它在同一工作区里 能重复执行」。把该项改为「插件已 link 进 profile 且新工具此刻真的可调用」之后,第三次一次性通过, 并且这次 unit 与 no-native-import 由独立 subagent(记录人 6a69ac69-…,root 是 session-d509ba29-…)亲自复跑并记录。等级仍是 L3(D=0.837 · P=0 · R=0.918)。

开发与热加载

  • 插件以 symlink / Windows Junction 形式安装(node_modules/dsh-plugin-playbook → 本目录),所以改代码不用重装。

  • 改 lib/*.js 的代码,必须重启 DSH 才生效(实测两次,见下);只有 cordis.patch.yml 里 的 config 变化能靠重装即时生效:

    • set_bundle(false) → set_bundle(true) 返回 applied,但只重跑 apply,不重新 import 模块。
    • remove_bundle → install_bundle 同样返回 applied,也不重新 import 模块。
    • 证据:在 playbook_search 的空结果文案里加标记 【RT3】,重装后调用它——文案里没有标记; 同一时刻新加的工具 gate_status 调用报 unknown tool "gate_status"。
    • 原因:Node 按文件 URL 缓存 ESM 模块,symlink 不改变 URL,重装不构成 cache bust。
  • 全新安装只要包能被 import,一次 install_bundle 就是 application: applied,不需要任何手动补刀。 如果第一次就失败,先查包解析(见下),而不是急着补刀。已经装好的包再装一次只会拿到 application: failed + ambiguous-install(见上表),别把它当成激活失败。

  • 重装会动 profile 的依赖与挂载表,仍建议先用 npm test 把逻辑测透再重装。

  • 插件顶层不要 import @deepseek-ai/*:symlink 之后 Node 按真实路径解析依赖,那些包只在 宿主运行时里存在,装了也会在激活阶段报 failed to import。自检方法:

    cd ~/.dsh/profiles/desktop
    node --input-type=module -e "import('dsh-plugin-playbook').then(m => console.log(m.name))"
    

设计取舍

  • 纯 Host、纯 ESM、无构建链:不引入 TypeScript/esbuild 步骤,改完代码直接生效(不需要编译,但要重启 DSH)。
  • 手动为主:不在 turn/end、workflow/end 上自动复盘。自动写入要额外模型调用,且容易产生噪音条目; 先用手动路径验证经验质量,再考虑加自动草稿。
  • 工作区级:不写全局目录,避免项目相关经验污染其他项目。
  • 不依赖 @deepseek-ai/* 运行时导入:工具参数直接写标准 JSON Schema。没有 Config schema 时 cordis.patch.yml 的 config 依然会原样传给 apply(ctx, config)——已用「把 dir 改成 .dsh/playbooks-probe,观察系统提示里的路径同步变化」实测确认。
—/ 5

No ratings yet

Verified DSH bundle

Commit c6527091e15c

Community comments

No comments yet. Be the first to write one.

DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

CommunityResourcesAPIAbout