dsh-compound-engineering
Verifieddsh-compound-engineering · v0.1.4 · MIT
Every 的 compound-engineering 方法论技能包 —— brainstorm → plan → work → review → compound,让每一次改动都让下一次更容易。DeepSeek Harness 移植版。
Install
dsh plugin add dsh-compound-engineering Confirm the layer applied with dsh --profile default --dump-config — see the install guide.
Source
Tags
Creators
Readme
dsh-compound-engineering
English | 简体中文
把 Every 的 compound-engineering 方法论搬进 DeepSeek Harness 的技能包。
核心想法:大多数 AI 编程工具让每次任务都从零开始。compound-engineering 改成复利——每次解决的问题都沉淀成仓库里的一份文档,下一次遇到同类问题时直接读到,于是每一轮改动都让下一轮更容易。
brainstorm → plan → work → review → compound
└─ 把这次学到的东西写进仓库
36 个技能全部随包分发,安装后无需任何配置即可使用。
可选依赖 jq。 有六个脚本会调用它:cross-model 系列(ce-work、ce-code-review、ce-doc-review、ce-pov)以及 elevation-dispatch(ce-plan、ce-brainstorm)。没有 jq 时它们都不会中断所在技能,但降级方式分两种:
ce-code-review/ce-doc-review/ce-pov:打印jq not installed; skipping后退出码 0,该轮多模型审查直接跳过。ce-work的 cross-model:报transport unavailable (pre-egress, shared): jq not found并以退出码 2 结束,外层按“跨模型通道不可用”处理。elevation-dispatch:输出status:failed的结果信封,外层降级为内联执行。
你也就失去了多模型交叉复核这一层。想启用就装上:
winget install jqlang.jq # Windows
brew install jq # macOS
apt install jq # Debian/Ubuntu
安装
dsh plugin --profile web add dsh-compound-engineering
web 换成你实际用的 profile 名(headless、tui 等)。这条命令会自动把这个包加进 dsh.profile.bundles,不用手工改配置。
也可以手工两步:在 profile 的 package.json 里加依赖,再把它加进 dsh.profile.bundles。
{
"dependencies": { "dsh-compound-engineering": "^0.1.1" },
"dsh": { "profile": { "bundles": ["dsh-compound-engineering"] } }
}
装好后重启 DSH。会话里敲 /ce-plan 就能看到技能。
常用技能
| 技能 | 什么时候用 |
|---|---|
/ce-brainstorm |
想法还模糊,先把它逼成明确的方案 |
/ce-plan |
需求清楚,要一份能执行的计划 |
/ce-work |
按计划动手实现 |
/ce-code-review |
提交前找人挑刺(可以并行多模型对照) |
/ce-compound |
收尾:把这次排查出的非显然结论写进仓库 |
/ce-debug |
卡住了,系统性定位根因 |
/ce-commit-push-pr |
一次走完提交、推送、开 PR |
/lfg(let's f***ing go)把 brainstorm 到 PR 的全流程串起来。
其余 28 个技能见 skills/ 目录,或直接问模型"有哪些技能"。
ce-compound 是这套东西的差异点
别处的"记忆"插件记住的是对话。ce-compound 记住的是仓库:
- 跑起来会先读本机的 dsh 历史会话文件,把当时踩过的坑挖出来
- 产出写在
<repo>/docs/solutions/下,随代码一起提交、一起 review - 下次任何人(或任何模型)在同一个仓库工作时都会读到它
它刻意不记录"改了哪几行"——那从 git 里就能看出来。它记录的是"为什么这么改"这类从代码和测试里读不出来的东西。
在 DeepSeek Harness 上的适配
上游是给 Claude Code 等 14 个宿主写的。移植时做了这些事:
平台能力靠"能力"匹配,不硬编码工具名。 上游正文本来就用 "the host's blocking question tool" 这类措辞,所以 36 个技能的正文几乎原样可用。补的只是 DSH 这一档的具体名字(ask_user_question、todo_write、subagent、web_fetch、web_search)。
会话历史多了 dsh 平台。 skills/ce-compound/scripts/session-history/dsh_session.py 能读 DSH 自己的会话文件。这里有个坑值得记:DSH 的 session.v4.jsonl.zstd 是多个 zstd 帧首尾拼接(每次 append 追加一帧),标准的 zstd -d 或 compression.zstd.decompress 只解第一帧就返回,会静默丢掉整个会话。所以脚本自己扫帧边界,逐帧解压。需要 Python 3.14+;更老的解释器上会安静降级成"没有 dsh 会话可读"。
会话历史三个提取脚本只认 dsh。 extract-metadata.py、extract-skeleton.py、extract-errors.py 只解 dsh 会话,原来的 Claude Code / Codex / Cursor / Pi / oh-my-pi 分支全部删掉,净减约 845 行。discover-sessions.sh 保留了其它平台探测(混合工具仓库仍能列文件),但文档里的管道固定带 --platform dsh。dsh 会话只记 cwd 不记 git 分支,所以过滤按工作目录走,不按分支。
dev server 配置优先读 .dsh/launch.json。 ce-polish 需要知道怎么起本地服务,查找顺序是 .dsh/ → .claude/ → .vscode/。
host 身份白名单加了 dsh。 几个 cross-model 脚本原来只认 codex|claude|grok|cursor|opencode|antigravity|omp,如实上报 dsh 会被拒。
任务追踪、子代理、网页抓取都补了 DSH 的对应物。子代理在 DSH 上直接 subagent 派生,不必造一个假的 subagent_type。
Windows 上 ce-work 的 unit 流水线现在能跑通。 这条路线上游只做了 POSIX,改动了四处,移植同类代码时都会撞上:
fcntl不存在。加锁改用msvcrt.locking,但它是非阻塞的,抢不到锁直接抛异常而不等待,所以封装层做了指数退避重试,最长 30 秒。- Windows 上
os.open()打不开目录(缺FILE_FLAG_BACKUP_SEMANTICS,内核直接拒绝)。所有open(path, O_DIRECTORY)+fstat(fd)式的属主校验,改成走路径版的GetNamedSecurityInfoW。dir_fd同样不可用,于是"目录句柄"在 POSIX 上是真 fd、在 Windows 上是路径,由close_dir_handle()抹平差异。 - mode 位是合成的:
mkdir0o700 实测报 0o777,chmod0o600 实测报 0o666。任何st_mode != 0o700的闸门在 Windows 上必然失败。改为比对当前用户 SID,私密性靠加固过的 ACL(icacls /inheritance:r)而不是 mode。 - CRT 文本模式会把
\n变成\r\n、在读到你0x1A时截断,所以二进制打开一律带O_BINARY。
os.lstat() 在 Windows 上能给出稳定的非零 st_dev/st_ino,所以控制器记录的目录 identity 仍然有效可校验。
文本一律显式按 UTF-8 读。 中文 Windows 上 Python 默认 GBK,读上游自己的大部分技能文件都会抛 UnicodeDecodeError。
开发
npm test # JS 单元 + 集成测试,随后跑 Python 测试
npm run test:py # 只跑 Python 测试(会话读取器、Windows 兼容)
集成测试需要能找到 DSH 运行时。默认从包名 import,失败则扫描 ~/.dsh/runtime/versions/*;也可以用 DSH_RUNTIME 指过去。找不到运行时时整组跳过,不会报失败。
发版由 tag 驱动:推送 v* tag 会触发 .github/workflows/publish.yml,走 npm 的 OIDC trusted publisher 发布(无需本地 OTP、不在仓库里存 token)。完整流程与已踩过的坑见 docs/releasing.md。
改上游技能后,重新跑这两个幂等补丁脚本:
python scripts/patch-dsh-capabilities.py # 给技能正文补 DSH 档位
python scripts/patch-host-allowlists.py # 补 cross-model 的 host 白名单
用 file: 方式开发时,改完源码要刷副本
dsh plugin add file:<本地路径> 走的是 pnpm 的目录依赖,node_modules/ 里放的是拷贝,不是软链。pnpm 会把目录依赖的内容记进 lockfile(resolution: {directory: ..., type: directory}),所以改完源码之后跑 pnpm install、pnpm update、甚至重跑 dsh plugin add 都不会刷新那份拷贝——你会一直跑到旧代码,而且因为技能清单来自旧副本,lib/ 里改了什么都看不出来。
确认是否踩到(哈希不一致就是踩到了):
md5sum skills/ce-work/scripts/unit_workspace_state.py \
~/.dsh/profiles/web/node_modules/dsh-compound-engineering/skills/ce-work/scripts/unit_workspace_state.py
直接重建副本最省事:
python -c "
import shutil, os
dst = os.path.expanduser('~/.dsh/profiles/web/node_modules/dsh-compound-engineering')
shutil.rmtree(dst, ignore_errors=True)
shutil.copytree('<源码目录>', dst,
ignore=shutil.ignore_patterns('node_modules','.git','__pycache__','*.pyc','test'))
"
副本里的 skills/ 必须和源码一一对应(test/ 不随包分发)。改完 lib/ 后需要重启 DSH 才会重新加载插件。
结构
lib/
index.js 插件入口:向 ctx.skills 注册 provider
provider.js 把 skills/ 目录暴露成 SkillProvider
frontmatter.js 零依赖 YAML frontmatter 解析
skills/ 36 个技能(上游原样分发)
cordis.patch.yml 把插件插进 profile 的层栈
test/ 单元 + 集成测试
scripts/ 上游同步补丁、冒烟测试
本包不引入任何运行时依赖:技能的 YAML 用自带的解析器读,不与宿主的 YAML 版本打架。
许可
MIT,与上游一致。技能的著作权归 Every(Copyright (c) 2025 Every),见 LICENSE。