DSH WorkBuddy Kit
中文 · English
DeepSeek Harness 负责想清楚并验收,本机 WorkBuddy 负责动手做:一次派发、等到终态、自己复核证据、按完整 sessionId 归档。
一个本机工具包,把「DSH 派活」和「WorkBuddy 干活」接成闭环。两个前门共用同一张工具表:
- 原生 DSH 工具(Cordis 插件
dsh-workbuddy-kit,注册 wb_* 到 ctx.tools)
- stdio MCP 服务(
dsh-workbuddy-mcp,任何 MCP 客户端可用)
两者行为完全一致,因为它们调用的是同一份 src/tools.mjs。
这是插件、技能,还是 MCP 服务?
四个形态,共用同一张 src/tools.mjs,所以行为一致;区别是谁在用和怎么装:
| 形态 | 文件 | 怎么装 | 作用 | 改完要重启吗 |
|---|
| DSH 插件(主体) | plugin/index.mjs + cordis.patch.yml | dsh plugin --profile add . | 把 18 个 wb_* 注册进 ctx.tools,在 DSH 里直接调用 | 要(工具表在启动时快照) |
| 技能(附带,可选) | skills/delegate-to-workbuddy/SKILL.md | 拷到 <DSH_HOME>/agents-home/skills/ | 教 agent 何时派发、怎么等终态、怎么复核证据、怎么按 ID 归档 | 不要(热加载) |
| MCP stdio 服务 | mcp/server.mjs | 写进任意 MCP 客户端配置 | 给非 DSH 的客户端(Claude / Codex / 自研)用同一套工具 | 不要 |
| CLI | in/wb.mjs | | | |
| ode bin/wb.mjs … 或 | | | | |
| pm i -g | 手工验证、脚本化,不接任何客户端 | 不要 | | |
插件 = 能力(工具),技能 = 行为指南(什么时候用、按什么顺序用)。 插件可以单独用;技能离开插件没有意义。只想要工具就装插件;想让 agent 自觉按「派发 → 等终态 → 复核 → 归档」的规矩办事,再叠加技能。
解决什么问题
| 没有它的时候 | 有了它 |
|---|
| 想让 WorkBuddy 干活,只能把上下文、路径、要求手打一遍,还得自己盯着它跑完没有 | 一次派发拿到 runId,wait_run 拉到终态;state / stopReason / toolCalls / workspaceChanges 都是结构化字段,超时不算终态 |
| 「它说做完了」= 做完了? | 工具返回的是证据:git 前后对比、工具调用数、完整转录、sha256 归档副本;调用方自己复核才算完 |
| 派出去的会话在桌面 App 里看不见,等于没发生过 | 默认自动登记进 App 索引,会话就出现在同一个工作区下(跟随 DSH 当前目录),点开就是完整对话 |
| 想批量盯桌面 App 的定时任务,只能一个个点开看 | 三个只读工具直接读 workbuddy.db:任务清单、每次运行、成功率与失败码、逾期任务 |
| 它的权限边界靠猜 | 实测过的矩阵写死在文档里:工作区内读写用 acceptEdits;跨目录读、WebFetch/curl 要 bypassPermissions;WebSearch 无头下不可用 |
它控制的是什么
本机 WorkBuddy 桌面版(腾讯,实测 5.8.3)在自己的安装目录里自带一个 CodeBuddy agent CLI:
D:\Program Files\WorkBuddy\resources\app.asar.unpacked\cli\
bin\codebuddy # @genie/agent-cli 入口(实测 2.161.0)
dist\codebuddy-lite-wb.mjs # 当前发行只带 lite-wb 包
这个 CLI 支持无头运行:-p/--print、--output-format stream-json、--session-id、--permission-mode、--model、--max-turns、--effort、--mcp-config……本工具包就是把这条通道变成一组可验收的工具:
| 工具 | 作用 |
|---|
wb_doctor | 只读自检:CLI、Node、数据目录、版本、自定义模型、最近是否撞到登录墙 |
wb_list_capabilities | 真实可用的 permission mode / 自定义模型 |
wb_list_projects / wb_list_sessions | 找到 WorkBuddy 的工程目录与会话 |
wb_start_review | 只读派发(--permission-mode plan,并拒绝 Write/Edit/NotebookEdit) |
wb_start_run | 实施派发(默认 acceptEdits) |
wb_wait_run / wb_get_run | 盯到终态;超时不算终态(hostMustCallWaitRunAgain) |
wb_cancel_run | 终止整个子进程树 |
wb_list_runs | 本机派发台账 |
wb_read_session | 直接读对话记录(消息、工具调用、模型),自己复核 |
wb_archive_session | 按完整 sessionId 归档:带 SHA-256 的副本 + manifest + 索引 |
wb_list_automations | 桌面 App 调度器:定时任务清单(节奏/下次触发/最近结果/模型/权限/推送) |
wb_get_automation_runs | 某个定时任务的运行历史、成功率、失败码 |
wb_automation_health | 调度器体检:生效 vs 软删、总运行/失败率、失败码分布、过期未触发 |
调度器三个工具只读 workbuddy.db(automations / automation_runs / automation_runtime_state),不写任何调度状态。
最后效果
真实跑过一次的形态(这就是本仓库在制作机上的验收记录):
你 ❯ 用 WorkBuddy 只读核对 notes.md 里的标记,别改文件
DSH ❯ wb_start_review { workspace:"E:\\Code\\demo",
task:"读出形如 DWB-ACCEPT-XXXX 的标记,原样引用,不要修改任何文件" }
→ runId, sessionId:<uuid>, permissionMode:"plan", state:"running"
wb_wait_run { runId } → state:"succeeded", stopReason:"end_turn", toolCalls:3, durationMs:22485
(assistantText 里就是 "DWB-ACCEPT-9F3A,位于第 3 行",自己去文件对一遍)
wb_archive_session { sessionId:"<uuid>" }
→ archived:true, bytes:15124, sha256:a0c6cc74…, target:…\\session-archive\\<date>\\e-Code-demo\\
拿到的不是「已完成」四个字,而是:结论 + 工具调用次数 + 真实 sessionId + 归档摘要。
安装
前置:本机已装 WorkBuddy 桌面版;Node ≥ 22.19(跑 DSH 用,本工具包自身零依赖)。
A. 丢给 AI(推荐,零手工)
把下面这段原样发给任何有终端权限的 AI(DSH / Claude / Codex 都行):
``text
请安装并验收 https://github.com/ksoulness/dsh-workbuddy-kit 这个 DSH 插件。
先读 https://raw.githubusercontent.com/ksoulness/dsh-workbuddy-kit/main/AGENTS.md 并按它执行;读不到就按下面四步:
- 前置检查:node -v 需 >= 22.19;git、dsh 可用;确认本机存在 WorkBuddy 的 CLI 目录
(Windows: C:\Program Files\WorkBuddy\resources\app.asar.unpacked\cli\bin)。
- 安装:git clone 仓库后 dsh plugin --profile <我的profile> add .,
再用 dsh --profile --dump-config 确认出现 dsh-workbuddy-kit 行。
- 验收:
pm test(应 pass 65 / fail 0)、
pm run verify(应 18 tools / 0 failures)、
ode bin/wb.mjs doctor(应 found true)。
4. 报告:用表格列出每一步的命令、真实输出、结论;最后告诉我是否需要重启 DSH。
铁律:不要提权、不要 sudo、不要写 workbuddy.db、不要改我的 models.json 和会话文件、
不要调用 wb_publish_session、不要在没有亲眼看到输出时声称成功。失败就贴原始报错。
``
装完记得重启 DSH(工具表在启动时快照);技能是热加载的,改了立刻生效。
B. 原生 DSH 工具(手工)
git clone <this repo> dsh-workbuddy-kit
cd dsh-workbuddy-kit
dsh plugin --profile web add .
dsh --profile web --dump-config | grep -n workbuddy
重启 DSH(Web 端刷新页面)后,wb_* 就是原生工具。
C. MCP stdio(任何 MCP 客户端)
cordis.patch.yml 里追加一行,不要在同一个 profile 同时开 A 和 B(工具名会重复):
- id: mcp-workbuddy
name: '@deepseek-ai/dsh-mcp-client'
config:
serverName: workbuddy
transport: stdio
command: node
args: ['E:\\Code\\dsh-workbuddy-kit\\mcp\\server.mjs']
D. 离线 tarball(不联网、不装 npm 包)
每次 Release 都附带 dsh-workbuddy-kit-.tgz,内含 in/ mcp/ plugin/ src/ docs/ skills/ scripts/ LICENSE README*:
sh npm pack # 或直接从 Release 下载 npm i -g ./dsh-workbuddy-kit-0.1.0.tgz # 拿到 dwb / dsh-workbuddy-mcp 两个命令 dwb doctor
不装全局也行:解包后
ode package/bin/wb.mjs doctor 就能用。
E. 手工验证(不接任何客户端)
node bin/wb.mjs doctor
node bin/wb.mjs review --workspace E:\Code\demo --task "只读核对 README 第 1 节,给出精确行号" --wait 300
node bin/wb.mjs sessions --limit 5
关键约束(都是实测出来的,不是猜的)
- CLI 必须指向 WorkBuddy 的数据目录:不设
CODEBUDDY_CONFIG_DIR / WORKBUDDY_CONFIG_DIR,CLI 会去读 ~/.codebuddy,那里没有登录态。本工具包自动指向 ~/.workbuddy。
- 当前发行只带
lite-wb 包:必须带 CODEBUDDY_FORCE_LITE_WB_BUNDLE=1,否则启动器会去找不存在的 dist/codebuddy。工具包自动判定。
- 无头 CLI 用不了桌面版的登录态:账号默认模型会直接返回
Authentication required。工具包默认挑 <configDir>/models.json 里的第一个自定义模型(本机实测 custom-local:cn:space-bunny 可用),并把这个选择记在 modelSource 里;用 DWB_DEFAULT_MODEL 可覆盖。
- 无头下工具调用要
-y:腾讯文档明确「-y 是非交互模式必需参数」,否则读写/命令会被拦(本仓库实测:plan 模式下 Bash 被拒,模型改走 Grep/Read)。wb_start_run 提供显式的 skipPermissions: true,从不默认打开;HIGH/CRITICAL 命令仍可能要求确认。
- 会话落在
<configDir>/projects/<工程名>/<sessionId>.jsonl,工程名是工作目录的映射(E:\Code\acme-app → e-Code-acme-app)。归档就是对这个文件做带摘要的副本。
- 归档不动厂商数据:默认
copy,WorkBuddy 自己的会话列表不变;move 是显式的可逆选项。
桌面 App 的调度器(定时任务)
定时任务不在文件里,在 ~/.workbuddy/workbuddy.db 的三张表(automations.db 是 0 字节的遗留空文件):
| 表 | 内容 |
|---|
automations | 任务定义:名字、完整 prompt、状态、rrule、next_run_at、last_run_at、模型、权限模式、工作区、推送渠道、deleted_at |
automation_runs | 每次触发:thread_id、状态、result_success、failure_code、reason_code、标题 |
automation_runtime_state | running、last_error |
node bin/wb.mjs automations # 生效中的任务
node bin/wb.mjs automations --all # 含软删除
node bin/wb.mjs automations --prompt # 附带 prompt 预览(默认不返回)
node bin/wb.mjs automation-runs --name "研究流水线监护" --limit 5 --failures
node bin/wb.mjs automation-health
两个必须知道的坑(实测):
- 软删除行
status 仍是 ACTIVE:真正的活性信号是 deleted_at。本工具包输出 softDeleted 与 live 两个显式字段,避免把僵尸任务当活跃任务。
- prompt 全文就在库里(很长、很私人):默认只返回
promptBytes,要预览得显式 includePrompt: true,且截断到 2000 字符。
读法是 readOnly: true 打开 SQLite(WAL 读者不影响正在运行的桌面 App)。调度器只读:暂停/改 RRULE/新建/删除都要走桌面自己的 IPC 或 UI,直写会让界面与库不一致。
让派发的会话出现在桌面 App 里(写库,可撤销)
默认情况下 CLI 会话不会出现在桌面 App 的会话列表里:它只写 projects/<slug>/<id>.jsonl,不写 App 自己的索引。桌面列表的查询是:
SELECT … FROM sessions
WHERE transport = 'local' AND deleted_at IS NULL
AND (user_id = ? OR user_id = '')
AND id IN (…)
所以转录再完整,没有那一行 sessions 记录就是不可见。补上那一行(外加一行 session_usage)就会出现:
node bin/wb.mjs publish --session <sessionId> --title "【DSH 派发】…"
node bin/wb.mjs published # 本工具包发布过哪些
node bin/wb.mjs unpublish --session <sessionId> # 只删自己插的那两行
工具:wb_publish_session / wb_unpublish_session / wb_list_published。
publish 也接受 --run <runId>,直接从派发台账解析 sessionId。默认就会发布:派发跑完自动登记,结果记在运行的 publishResult 字段里,发布失败不会改写运行的终态。要不污染 App 列表就显式传 publishToApp: false(CLI 是 --no-publish),此时只写转录、不进 App。
工作区归属 = DSH 会话当前的工作目录(不是写死的路径)。省略 workspace 时插件每次调用都会向 workingDirectory 服务要当前目录,所以你在 DSH 里 cd 到哪,WorkBuddy 就在哪开工;解析不到就报错,不会退回 harness 安装目录。workspace 只在你需要故意换目录时显式传。
工作区归属由 workspace 决定:桌面 App 按会话的 cwd 分组,所以派发时把 workspace 设成你平时用 DSH 的那个目录(例如 E:\Code\acme-app),这个会话就会出现在同一个工作区下;换成别的目录,就会多出一个新工作区。wb_start_run / wb_start_review 现在 workspace 可省略,省略时用当前 DSH 会话的工作目录(插件注入 workingDirectory 服务);解析不到时直接报错而不是退回 process.cwd()——那是 harness 安装目录,发到那里会让 App 多出一个垃圾工作区。
写什么:一行 sessions(id、cwd 归一成 E:/Code/x、user_id 取当前登录用户、title、status、created_at/updated_at/last_activity_at、transport='local'、source_mode='craft'、mode='craft'、model)+ 一行 session_usage(size = 转录字节数)。转录文件一个字节都不改。
安全边界:
- 会话不存在、读不到
cwd、或库里已有该 id → 拒绝并说明原因;
- 每次插入记进
<stateDir>/published.jsonl;unpublish 只删账本里登记过的行,且不动其他会话行;
- 建议先备份库(
docs/setup.md 有一条实测命令);
- 手法不是本文独创:GitHub 上的
workbuddy-account-migrate 用同样方式(写 sessions/session_usage + 搬 projects/<slug>/)做跨账号会话复制,并明确写了「不写 sessions 行,客户端就找不到」。
与已有项目的关系
搜过一圈,方向不同,没有一个在做「DSH 派活给 WorkBuddy 并验收」:
安全与边界
permissionMode: plan 与拒绝写工具是给模型的声明,不是进程级沙箱:CLI 仍以自己的权限运行,Bash 之类的工具能做什么由它自己的策略决定。
- 派发内容是「任务描述」,不是源码:只说工作区、范围、授权、验收标准,让 WorkBuddy 自己去读文件。
- 不读取、不打印、不落盘任何 token / cookie / API key;
models.json 只取 id、vendor 这类身份字段。
- 归档在会话仍活跃、或本工具包没有该会话的终态记录、或目标文件已存在时会拒绝并给出原因,不伪造
archived:true。
- 本包不是腾讯 / DeepSeek 官方产品。
已验证 / 未验证
制作机(Windows、Node v24.19.0、WorkBuddy 5.8.3、CLI 2.161.0、DSH 0.2.1-alpha.2)实测:
- ✅ 真实只读派发 →
succeeded / end_turn / 3 次工具调用 / 22.5s,assistantText 与工作区文件一致;
- ✅ 真实实施派发 →
succeeded / end_turn,工作区里确实多出 hello.txt,内容与任务要求逐字一致(DWB-RUN-OK);
- ✅ 真实归档两次:
archived:true,15124 / 7973 字节,sha256:a0c6cc74… / 9887ba08…;
- ✅
wb_doctor 正确识别安装路径、自带 Node、liteBundleOnly、自定义模型;
- ✅
node --test 65/65:流解析、工程名映射、schema 子集、MCP 握手、归档的全部拒绝分支、调度器只读读取(含软删除与失败码)、git 侧改动证据、发布/撤销/默认发布;
- ✅ MCP stdio 真实握手(
initialize + tools/list);
- ✅ 在真实 cordis 里挂载插件(
inject: ['tools', 'workingDirectory'])→ 18 个工具全部通过 dsh-tools 自己的 assertObjectJsonSchema / assertSupportedJsonSchema 校验(npm run verify);
- ✅ 委派真实产出:WorkBuddy 按任务在
E:\Code\demo 写出 CHEATSHEET.md,其中 5 条命令逐字核对全部命中源文档(README.md:71/72/85/94/95);另一次运行由 workspaceChanges 抓到新增 demo-workspace-change.md(addedCount: 1);
- ✅ 跟随 DSH 工作目录:同一会话在 E:\Code\acme-app 时省略 workspace → 落在 E:\Code\acme-app;把 DSH cwd 切到 E:\Code\dsh-workbuddy-kit 后再派发 → 落在 E:\Code\dsh-workbuddy-kit(projectSlug: e-Code-dsh-workbuddy-kit),没有写死路径;
- ✅ 诚实的失败样本:跨
--add-dir 目录读取被拦(即使 -y),运行层仍 succeeded 但零改动 —— 证明「终态 ≠ 完成」,必须看 workspaceChanges / 文件;
- ✅ 桌面调度器真实读取:6 条生效 + 3 条软删、累计 1000+ 次运行(成功率约 0.91)、失败码分布与桌面 App 界面一致;
- ✅
dsh plugin --profile web add . 装进本机 profile,dsh --profile web --dump-config 出现 dsh-workbuddy-kit 行。
未验证:其他 WorkBuddy 版本 / 其他平台的路径、--acp 与 --serve 通道、move 归档对桌面端索引的影响。
目录结构
src/discover.mjs 安装/CLI/Node/数据目录定位,工程名映射
src/cli.mjs 组装无头调用、spawn、终止进程树
src/parse.mjs stream-json 与 session JSONL 解析
src/runs.mjs 派发台账、终态判定、恢复与取消
src/sessions.mjs 会话枚举/读取/精确归档
src/automations.mjs 桌面调度器只读(automations / runs / runtime_state)
src/tools.mjs 唯一工具表(两个前门共用)
plugin/index.mjs 原生 DSH 插件
mcp/server.mjs stdio MCP 服务(零依赖)
bin/wb.mjs 手工 CLI
cordis.patch.yml DSH bundle 层(只插一行)
skills/delegate-to-workbuddy/SKILL.md
docs/ 接入、架构、安全
tests/ 37 个 node:test 用例
文档
许可
MIT。WorkBuddy、CodeBuddy、DeepSeek Harness 不在本包内,各按其自身许可与条款。