DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

wjingshan /

wjingshan/dsh-plan-guard

Topic repository only

DSH 的规划 skill + 写时断言插件:前者让模型动手前想清楚,后者在它重踩旧坑时当场拦住。不建通用体系,只固化真实发生过的事。

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

dsh-plan-guard

中文 | English

License: MIT DeepSeek Harness Agent Skills

给 DSH 用的规划 skill + 写时断言插件:前者让模型在动手前把问题想清楚,后者在模型把踩过的坑再踩一遍时当场拦住。两半都不建通用体系 —— 只固化真实发生过的事。

这个仓库不是从零设计的。它是两台视频的落地产物:一台讲「写代码之前怎么想清楚」(Grilling / Brainstorming / Explore 三种规划框架),一台讲「写完怎么知道没坏」(把判断对不对从肉眼变成自动断言)。看完之后的结论是:第一条视频的落点是提示词工件,加 skill 就够;第二条视频的落点是工程架构,加 skill 解决不了 —— 得挂到 DSH 的拦截缝上。 这个仓库把两句话各做出了实物。


两半是什么

规划(skills/) 断言(plugins/)
解决的问题 动手之前问题没想清楚 动手之后悄悄改坏了
形态 提示词工件(SKILL.md) DSH 插件(挂 tools/pre-execute / tools/post-execute)
生效时机 你或模型主动加载 每次写文件时自动
可移植性 开放 Agent Skills 格式,Claude Code 等也能直接用 DSH 专有

一句话:skills 管「想」,plugins 管「别改坏」。


目录结构

dsh-plan-guard/
├── skills/                        ① 规划:三个 skill
│   ├── grilling/                  SKILL.md + references/question-bank.md
│   ├── brainstorming/             SKILL.md + references/design-doc-template.md
│   └── explore/                   SKILL.md + references/ascii-diagrams.md
├── plugins/                       ② 断言:两个 DSH 插件
│   ├── dsh-skill-lint/            写 SKILL.md 时的三条断言
│   └── dsh-script-lint/           写 shell / PowerShell 时的三条断言
├── CONTRIBUTING.md                给想改它的人:架构 + 加一条判据的完整例子
├── CHANGELOG.md                   改了什么,以及为什么
├── docs/background.md             来龙去脉 + 每条设计决定为什么这么做
├── install.sh / install.ps1       装 skills
├── uninstall.sh / uninstall.ps1   卸 skills
├── install-plugins.sh             装两个插件进 profile(复制路线)
├── verify.sh                      检查「装上去的」和「仓库里的」是否一致
└── update.sh                      拉取 + 重装 + 校验

安装

规划 skill

macOS / Linux

git clone https://github.com/wjingshan/dsh-plan-guard.git
cd dsh-plan-guard
bash install.sh

Windows

git clone https://github.com/wjingshan/dsh-plan-guard.git
cd dsh-plan-guard
powershell -ExecutionPolicy Bypass -File .\install.ps1

装到 $DSH_HOME/skills(默认 ~/.dsh/skills),这是 DSH 的用户级 skill 根,对所有项目生效。 装完不需要重启 —— DSH 监听这些目录,新 skill 下一个对话步骤就出现在目录里。

想只给某个项目用:把 skills/ 下的目录复制到 <项目根>/.dsh/skills/(优先级更高,会盖住全局)。

断言插件

插件有两种装法。推荐 bundle 安装 —— 它由 profile 的包管理器管理,能被 dsh plugin 正常更新,也不会被别的包管理操作清掉。

路线 A:bundle 安装(推荐)

在 DSH 里用 plugin_manager 工具的 install_bundle 动作(Web 界面侧栏的 Plugins 页是同一个入口):

action : install_bundle
target : github:wjingshan/dsh-plan-guard#path:/plugins/dsh-skill-lint

再装另一个:

action : install_bundle
target : github:wjingshan/dsh-plan-guard#path:/plugins/dsh-script-lint

#path: 是 pnpm 的 git 子目录语法 —— 仓库根是一个项目,每个插件是它的一个子目录,所以必须指到子目录上。

成功的返回是 "application": "applied";profile 的 patchReload 是 live,不用重启。

钉住版本:默认取的是默认分支的 HEAD,每次重新解析。想钉死在某个发布上,把 git ref 放在 &path: 前面:

action : install_bundle
target : github:wjingshan/dsh-plan-guard#v0.2.0&path:/plugins/dsh-skill-lint

顺序反了(#path:...&tag=v0.2.0)会失败,报 Could not resolve ... commit —— 这是实测的。 ref 可以是 tag、分支名或 commit SHA。

⚠️ 别用 dsh plugin add。 CLI 的 plugin 子命令只是把参数原样转发给 pnpm(dsh plugin --profile web add <pkg> 等于在 profile 目录里跑 pnpm add <pkg>)—— 包是装上了,但不会登记进 dsh.profile.bundles,于是这个 bundle 的 patch 不生效、插件根本不会被加载。这个差别我们实测过,包装好了但缝不工作。

install_bundle 会做三件事:跑 pnpm 安装、把包登记进 dsh.profile.bundles、验证 bundle 能加载。除此之外,它对 GitHub 地址会先用 git ls-remote 探一次连通性,装完还会校验 DSH peer 版本兼容性。

路线 B:复制安装(离线、或想改源码时用)

bash install-plugins.sh

路线 B:复制安装(离线、或想改源码时用)

bash install-plugins.sh

它把两个包复制进 <profile>/node_modules/,再往 <profile>/cordis.patch.yml 追加 insert 条目。

⚠️ 这条路不持久,实测翻过车。 手动放进 node_modules/ 的包不是包管理器管理的,会被当成"多余的包"。我们遇到过:profile 上跑了一次 pnpm install(由别的插件触发),一个插件被清掉、cordis.patch.yml 里两条 insert 也被一并重写掉了 —— 两个插件静默失效,没有任何提示,直到有人去查才发现。

所以这条路只适合临时试用或改源码调试。长期使用请走路线 A。

想改源码调试,用软链更省事(插件零运行时依赖,所以软链能正常解析):

ln -s "$PWD/plugins/dsh-script-lint" "$PROFILE/node_modules/dsh-script-lint"

Windows

路线 A 的 dsh plugin 命令一样(在 PowerShell 里跑)。路线 B 手动做:把 plugins 下两个目录复制进 <profile> 的 node_modules,再往 <profile>/cordis.patch.yml 追加 insert 条目。

装完怎么确认

./verify.sh

它检查「装上去的」和「仓库里的」是否一致,并区分 bundle 安装 / 手动复制;还会在「patch 有条目但包不在」时报错 —— 那种情况会让 DSH 直接加载失败。装完顺手跑一次,能省掉「以为装上了其实没有」。

更新

./update.sh            # 拉取最新 + 只重装装过的 + 校验
./update.sh --no-pull  # 已经自己拉过了
./update.sh --check    # 只看上游有没有新提交,不做改动
./verify.sh            # 只检查,不改动

为什么不能只 git pull:安装是把文件复制进 node_modules / skills 的,拉下来的新代码不会自动替换装上去的旧副本。update.sh 补的就是这一步。

bundle 安装的插件由 dsh plugin 管,update.sh 会打印出该跑的 dsh plugin add 命令而不是替你猜。

三个规划 skill

skill 比喻 干什么 什么时候用
grilling 咄咄逼人的面试官 一次只问一个问题,沿设计树追问到底,不接受「差不多」 你已有初步想法,想快速找出漏洞
brainstorming 严格的项目经理 九步流程,强制产出设计文档 + 自审查 项目要上线、多人协作、决策要可追溯
explore 好奇的思维伙伴 先读代码、比较选项、画 ASCII 图,默认不产出任何工件 面对一团乱麻的旧系统,不知道从哪下手

装完可以直接 /grilling、/brainstorming、/explore,也可以说「帮我拷问一下这个方案」让模型自己加载。

grilling 的收尾是硬要求:必须用不超过 5 行复述「已达成的关键决策 + 理由」。 brainstorming 有一份 12 节的设计文档模板和四组自审查清单(完整性 / 一致性 / 歧义 / 风险)。 explore 有六类 ASCII 图模板 —— 结构图、时序图、状态机、数据流、决策树、对比图 —— 以及「什么时候不该画图」。


两个断言插件

dsh-skill-lint —— 写 SKILL.md 时

DSH 的 skill 加载器有两个沉默的失败模式:失败了,但你看不出来。

判据码 拦什么
FM_INVALID 第一行不是 ---,或 frontmatter 没有收尾的 ---
NAME_MISSING 缺 name
NAME_NOT_KEBAB name 不是 kebab-case
NAME_MISMATCH name 与所在目录名不一致
DESC_MISSING 缺 description 或它为空
BOOL_INVALID disable-model-invocation / user-invocable 写了非布尔值
SIZE_OVER 正文码点数 ≥ sizeLimit(默认 8192,对齐 dsh-compaction-tool-result-pruner 的 thresholdChars)

前六条任意一条成立,DSH 都会静默丢弃整个 skill —— 模型端分不清「这个 skill 不存在」和「这个 skill 写错了」,日志里只留一条 warning。

dsh-script-lint —— 写 shell / PowerShell 时

三条判据全部来自真实事故,不是编的:

判据码 拦什么 来自哪次事故
SHELL_ERREXIT_TRAP set -e 下 x=$(... grep ...) 失败会无声终止整个脚本 一个打包脚本无任何报错地 exit 1,排查很久
SHELL_GREP_UNQUOTED_PATH 递归 grep 用了没加引号的 $VAR grep -rn ... $D 且 $D 为空 → 把整个 workspace 递归搜了一遍
PS1_NO_BOM .ps1 含中文却没有 UTF-8 BOM PowerShell 5.1 按 ANSI 解码,中文全乱码

SHELL_ERREXIT_TRAP 是这里最费心的一条,因为它编码的是 bash 语义 —— 位置和 shell 选项都会改变结论:

写法 set -e 下
x=$(grep a f) $() 退出码就是赋值的退出码 ❌
echo $(grep a f) / [ -n "$(…)" ] / for f in $(…) 不影响外层退出码 ✅
x=$(ls | grep v | wc -l) 无 pipefail 只有最后一段作数 ✅
同上 有 pipefail 任何一段失败都算 ❌
x=$(grep a f || true) 显式吞掉了失败 ✅
x=$(grep a f) | cat 跑在子 shell,杀不了整个脚本 ✅
cat f | { x=$(grep a f); } 复合命令返回非零,照样致命 ❌

所以它报的错会点名管道里所有脆弱段,不只第一段 —— 只说第一段会让人去修错行。


三条设计决定

1. 判据与缝分离。 每个插件的 src/ 都分成两半:纯函数判据(lint.mjs / rules.mjs,零依赖、可单独测试)和缝接线(index.mjs,只负责挂到 DSH 事件上)。测量错了、判据错了可以分别审计,互不掩盖。这套分层学自 dsh-design-audit 自述的「测量与判据分离」。

2. 两条缝语义不同 —— 这是设计要点,不是实现细节。

  • write 走 tools/pre-execute → deny:内容还没落盘,坏文件根本不产生。
  • edit 只能走 tools/post-execute → block:edit 的入参是 {old_string, new_string},新的全文在调用前不存在,无法预判,只能事后复读磁盘报告。而它撤销不了已经写下去的东西。

我们故意不撤销。一个声称「我帮你回滚了」但其实没回滚的断言,比明说「文件已改坏」危险得多。

3. 宁可多报,但判据做窄。 漏报是沉默的,多报至少看得见 —— 所以默认不限制路径,任何 SKILL.md 都查。但多报到让人关掉插件,就等于没有,所以每条判据只报高置信度的形态,并且都拿现有真实脚本验过零误报。


自测

# skill 断言:24 条
node --test plugins/dsh-skill-lint/test/*.test.mjs

# shell 断言:39 条
node --test plugins/dsh-script-lint/test/*.test.mjs

dsh-script-lint 的头号测试夹具就是那次真实事故的代码 —— 修之前必须被拦住,加了 || true 之后必须放行。另有一条测试把现有全部脚本当「必须零误报」夹具。


已知边界

说清楚,别指望它更多:

  1. 只拦 DSH 的 write / edit 工具。 用 cp、编辑器、或任何 shell 命令直接写文件完全绕过。它保护的是「模型在写文件的时候」,不是「任何东西进这个目录的时候」。
  2. 不是 bash 解析器。 逐行 + 引号感知扫描,eval、${!x} 这类动态构造看不出来。
  3. 两个插件都挂 tools/pre-execute,瀑布里第一个 deny 会短路 —— 一个文件同时踩两边的坑时,一次只见一条报告,改完再写才见另一条。
  4. 这不是回归测试体系。 没有用例库、没有 scoreboard、没有 flag 开/关对比、没有覆盖度。断言只保证「不重复踩同一个坑」,不保证「这次改动没弄坏别的」。

第 4 条是刻意的:那套东西(非确定性、成本、LLM 裁判的信噪比)比这个难一个数量级,规模不到就别上。


出处

两个视频,都值得看:

  • 「你的AI编程总是翻车?因为你少做了一步:设计隔离 | 拆解 Grill-me,Superpowers,Openspec 的第一步」—— 规划那一半的来源
  • 「我做 AI Agent 一年,90% 在做表面功夫——直到我换了思路」—— 断言那一半的来源

这个仓库没有抄它们的实现,是把它们的问题意识落到了 DSH 上。

许可

MIT

—/ 5

No ratings yet

Manifest verification required

Commit 63c7d14bf75a

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