dsh-work-crew
IdentifiedDSH 插件:把任务派给本机豆包 / WorkBuddy / ZCode / Qoder,用任务板与产物锁组织一支有纪律的 AI 班组。
dsh-work-crew
One prompt. A working team.
一个指令。一支有纪律的本机 AI 班组。
简体中文 · English
dsh-work-crew is a DeepSeek Harness plugin that turns the AI apps already
installed on your machine — Doubao, WorkBuddy, ZCode, Qoder — into a crew with a task board.
DSH stays the orchestrator. It does not write your code itself; it plans, dispatches, enforces locks, collects receipts and keeps the books. The crew does the typing.
Why
One model reviewing its own work is the weakest link in every AI coding session:
| Failure | What the crew does instead |
|---|---|
| Self-review blind spot — the model checks its own output | A different model reviews it; the implementer never signs off on itself |
| Concurrent edits — writing and reviewing the same file at once | Artifact locks: write:landing:hero and read:landing cannot overlap in time |
| Lost progress — who is waiting for whom, asked again next session | A task board on disk (.dsh-team/) with dependencies, locks and timeline |
Install
# from GitHub
dsh plugin --profile desktop add github:yxyusage/dsh-work-crew
# from a local checkout
dsh plugin --profile desktop add "E:\path\to\dsh-work-crew"
Then fully quit DSH (tray → Quit) and reopen it.
Quick start
team_init → create .dsh-team/ (mission, roles, board, outbox)
team_add_task → title, worker, dependsOn, write/read locks, expect
team_dispatch → builds a brief, enforces locks, sends it (queues when busy)
team_collect → wait for receipts; takes taskIds, returns whoever finishes first
team_status → board: who is running, what is queued, which locks are held
A typical plan:
T1 implement hero WorkBuddy write:landing:hero
T2 review landing Doubao read:landing ← waits for T1 (write×read)
T3 product discussion Doubao — ← runs in parallel with T1
T4 docs Qoder write:docs dependsOn: [T1, T2]
Tools
| Tool | When to use |
|---|---|
team_init | first time in a project; records reference dirs and required docs |
team_status | who runs what, queue depth, last activity, held locks |
team_add_task | declare worker, dependencies, locks, deadline, expected artifacts |
team_dispatch | send a brief; takes taskIds to dispatch several in one step; queues when a worker is busy |
team_collect | wait for receipts: taskIds returns whoever finishes first |
team_reassign | move a task to another worker, keeping brief and history |
team_reopen | a false completion → back to running, without re-sending |
team_resubmit | artifacts now exist → re-check expect instead of re-dispatching |
team_release | close a task (refuses done while expected artifacts are missing) |
team_split_html | split a single-file page into html/css/js so three workers can edit in parallel |
team_shot | screenshot to a file, path only — device emulation for mobile widths |
team_workers | status / preflight / restart / ping |
Workers
| id | App | Good at | Debug port |
|---|---|---|---|
workbuddy | WorkBuddy | implementing, running commands, verifying builds | 9332 |
doubao | Doubao | visual review, ideas, reading screenshots | 9331 |
zcode | ZCode | implementation / second opinion (limited free quota) | 9334 |
qoder | Qoder | implementation / read-only audits (VS Code family) | 9335 |
How it works
- Driven over CDP. The plugin launches each app with
--remote-debugging-portand types into its chat box. Windows can stay offscreen; nothing steals your mouse. - Completion is a hard signal. WorkBuddy's "已完成" badge; Doubao/ZCode/Qoder's
@@END@@sentinel. No guessing from text stillness. - File handoff. Workers write reports to
.dsh-team/outbox/<id>.mdand reply with one line. The body never enters the orchestrator's context — that is where the token savings come from. - Locks with hierarchy.
landingcoverslanding:hero; siblings (hero,meta) run in parallel. - Queue, not stuck. A busy worker queues the task (
queued, no locks, no timeout) and promotes it when the current one is collected. - Budget.
deadlineMin(default 45) flags a stalled task; at twice the budget it is blocked and its locks released. - Artifacts are checked.
expectpaths must exist before a task counts as done; the outbox file is added automatically.
Screenshots: two traps that produce false reviews
Use team_shot — it already avoids both traps and returns only a path:
team_shot { "target": "index.html", "out": "shots/mobile-390.png", "width": 390, "mobile": true }
Trap 1 — capturing mid-animation. A headless shot without a virtual clock lands on the fade-in, so the page looks
half-transparent. team_shot emulates prefers-reduced-motion: reduce and waits for the layout to settle.
Trap 2 — resizing the window instead of emulating the device. --window-size=390,844 sets the window, but the
layout keeps the desktop viewport (~980px), so the shot is a cropped desktop page. That reads as "the layout overflows"
and sends a reviewer chasing a bug that does not exist. Device emulation is the only honest mobile shot, and
team_shot checks scrollWidth for you: if it equals the viewport, the layout is fine.
Guardrails
Six checks stand between "the model says it is done" and "the task is done":
| Guard | What it does |
|---|---|
review: true | The reviewer gets requirement + git diff + rubric only. It is told not to read the implementer's report — a reviewer that inherits the author's narrative inherits the author's blind spots. |
| Snapshot review | The changed files are copied to .dsh-team/snapshots/<id>/ and the reviewer reads the copy, so the review takes no read lock and the next implementation starts immediately. Diffing starts from the implementer's recorded baseCommit, so committed work still shows up. |
verify: "pnpm build" | The acceptance command runs in the project before the task may close. A red build blocks the task; no green build, no done. |
risk: "high" | High-risk work (auth, payments, CI, secrets, installers) never self-approves: collecting it only reports "awaiting approval" until a human re-collects with confirm: true. |
rubric.md + review round counter | team_init writes the project's acceptance rubric; every review carries it. From the 4th review of the same artifact, the brief asks whether the plan is wrong instead of requesting another patch list. |
crossCheck: true | After a review, a second reviewer gets the findings and votes on each one: holds / false positive / not enough evidence. Only confirmed issues survive. |
Knowledge base
"Make it look good" produces nothing. "Look at this, apply it like so, ship when these three rules hold" changes the output.
team_knowledge ships curated references; the matching ones are injected into the brief automatically — authors do not have to remember to ask.
| Entry | What it enforces | Source |
|---|---|---|
de-ai-slop | no purple gradients, no three-card hero, no emoji icons, real content instead of filler | anti-slop checklist |
frontend-ui | component structure and the four states (default/hover/focus/disabled) | shadcn AI Elements |
motion | shared-element transitions, 120–360 ms, transform/opacity only, reduced-motion fallback | smooth-option-switcher |
empty-states | why it is empty, what to do now, what you will get | Carbon patterns |
typography-color | modular scale, 16–18px body, 4.5:1 contrast, no pure black | type-scale |
copywriting | verbs on buttons, examples instead of adjectives, no judgement | NN/g microcopy |
a11y | keyboard path, visible focus, button semantics | web.dev a11y |
Beyond the interface, the same mechanism covers backend and review work:
| Entry | What it enforces | Source |
|---|---|---|
api-design | plural resources, RFC 9457 errors, idempotent writes | Google AIP |
backend-patterns | 12-factor, when splitting a service is justified | microservices.io |
sql-data | index by query, read the plan before touching indexes | use-the-index-luke |
testing | test pyramid, regression test per bug | Fowler |
code-review | five things to look at, two grades of comment | Google eng-practices |
security | server-side validation, auth at every entry, secrets out of logs | OWASP Top 10 |
observability | structured logs, metrics, actionable alerts | OpenTelemetry |
technical-writing | one page, one purpose (tutorial/how-to/reference/explanation) | Diátaxis |
web-performance | measure first: LCP/INP/CLS | HPBN |
Matching: explicit tags on the task win; otherwise keywords in the title and brief decide. The worker matters too —
Doubao is held to design/motion, Qoder to security/structure, ZCode to copy/docs, WorkBuddy to implementation. At most 4
entries, each rendered as link + how to use + what not to do + 3 rules.
And the loop closes at review time: a review task receives the checklist the implementer was given, up to 8 rules,
each to be judged done / not done (with location) / not applicable. That turns "check it" into findings you can act on.
Project-specific entries go in .dsh-team/knowledge/<id>.md and override built-ins by id:
team_knowledge { "action": "add", "id": "brand-guide", "title": "品牌规范", "tags": ["frontend","color"],
"url": "https://...", "use": "配色只从这 5 个色里选", "avoid": "自创渐变",
"rules": ["主色 #1f6feb,只用于主按钮", "正文色 #0f1115 / #e6e8eb"] }
Workflow
flowchart TB
A["team_add_task<br/>tags · locks · expect · verify · risk"] --> B{"能否并行?<br/>不同文件 / 不同 worker"}
B -- 是 --> C["team_dispatch taskIds<br/>一次派多个"]
B -- 否 --> D["team_dispatch"]
C --> E["简报 = 需求 + diff + 参考资料 + 对照清单"]
D --> E
E --> F["worker 干活<br/>正文写 outbox/<id>.md · 聊天只回 DONE"]
F --> G{"收单闸门"}
G -- 控制台报错 / 溢出 --> H["blocked 打回"]
G -- expect 缺失 --> H
G -- verify 命令失败 --> H
G -- 知识库机械规则 --> H
G -- 全部通过 --> I["评审:快照 + 对照清单逐条判"]
I --> J{"通过?"}
J -- 否 --> K["修复任务<br/>按文件并行"]
K --> F
J -- 是 --> L["team_bundle 合并单文件<br/>自动复检"]
L --> M["交付"]
Four gates stand between "the model says done" and done: artifacts exist (expect), the build passes (verify),
the page actually runs (console errors + overflow + mechanical gates), and a reviewer judges the same checklist the
implementer was given. Any failure blocks the task instead of passing it downstream.
Token economics
Measured on a real run (18 tasks, one landing page). Method: UTF-8 3 bytes per Chinese character, 1 token ≈ 1.5 characters.
| Quantity | Measured | Why it matters |
|---|---|---|
| Worker output kept on disk | 115,188 bytes in 17 outbox files ≈ 25.6k tokens | With chat delivery this enters the orchestrator's context and is re-sent on every later step |
| Briefs sent to workers | 57,864 bytes ≈ 12.9k tokens | Sent over CDP straight into the apps — never touches the orchestrator's context |
| Average single output | 6,776 bytes ≈ 1.5k tokens | One read costs more than the whole dispatch brief |
| Dispatch calls | 8 calls for 18 tasks (taskIds batch) | ~10 fewer steps than one call per task |
| Collect calls | 10 calls for 18 tasks (taskIds batch) | Whoever finishes first returns; no polling loop |
| Restarts | 1 call for four apps (restart all) | Was 4 steps, each re-sending the conversation |
| Screenshots | path only, image never read | Each image read costs ~1–2k tokens and stays in context |
The arithmetic that matters: a step costs context size × 1. Keeping 25.6k tokens of worker prose out of the context saves that amount on every subsequent step. Over a 40-step run that is roughly a million token-equivalents of context traffic that never happens (mostly cache reads — cheap, but not free).
What it costs: each dispatch carries ~800 bytes of references plus a ~2k-token checklist to the worker. That is paid to the worker's API, not to the orchestrator.
Requirements
- Windows with DSH Desktop (or DSH Web + Node 22+).
- At least one of the four apps installed and logged in.
- In each app: select the project folder as its workspace, and allow auto-approval / full access.
- The plugin launches the apps itself; an app already running without a debug port must be restarted
(
team_workers {"action":"restart","worker":"doubao"}), which is also the fix when a port goes stale.
Limits
- Selectors are tied to each app's UI. App updates can break them; every worker carries a
specversion andteam_workers {"action":"ping"}tells you whether the chain still works. - Quota cannot be read from any of the four apps. A worker that runs out mid-task is detected by timeout and
is meant to be re-dispatched with
team_reassign. - One app can hold only one in-flight task. That is a property of a single input channel, not a bug.
- Kimi desktop is not supported: it rejects both
--remote-debugging-portand--remote-debugging-pipe.
Layout
index.js tools + the /dsh-work-crew/state route for the panel
lib/team.js board, locks, briefs, roles, queue
lib/cdp.js CDP sessions, launch, typing, reading, completion rules
client.js sidebar panel (React, conversation.composer.dock)
locale/ zh + en metadata
License
MIT
Comments
Loading…