# Subagent 派活套件 (Dispatch Kit) > orchestrator(主会话)按 [PLAN.md §3 波次](./PLAN.md) 派活时,复制下面对应任务的 prompt。 > 角色/通用规则已写在 [`.claude/agents/`](../.claude/agents)(`module-builder` / `module-reviewer`)的定义里, > 此处只给**每个任务的变量部分**。`model` / `isolation` 在 `Agent(...)` 调用参数里设(见 PLAN §4),不写进 prompt。 ## 使用方法 1. 选定本波要派的任务(同波、文件不交叉,单批 ~3–5 个)。 2. 对每个任务调用:`Agent(subagent_type:"module-builder"|"module-reviewer", model:<§4>, isolation:<§4>, prompt:<下面对应块>)`。 3. **worktree 隔离的 builder 派出前,先把上一波 commit**(否则隔离工作树里没有 `types.ts`)。 4. 每个 agent 返回后:orchestrator 把它交回的日志条目**追加进 `PROGRESS_LOG.md`**,更新"当前焦点",再派下一波。 5. agent 返回 `[!] BLOCKED` → orchestrator 解歧义(必要时问用户)→ 重新派活。 --- ## 模板 A · module-builder(实现任务) ``` 执行 web-terminal 项目的 PLAN 任务 (<一句话标题>)。 先读(你的上下文是空白的):CLAUDE.md 的 "Development Workflow";docs/PLAN.md 里的任务 (看清 Owns/Depends/Steps/Accept);docs/ARCHITECTURE.md 的 ;并在 ARCHITECTURE.md 内 搜索这些锚点逐条照做:;背景看 docs/TECH_DOC.md <§>。 从 src/types.ts import 共享类型,**不要**本地另立类型。 硬边界 —— 只能创建/修改这些文件:。其它一律不碰(尤其 src/types.ts 和别的模块)。 TDD:先写覆盖每个 Step + Accept 的失败测试 → 实现到全绿 → 运行 确认。 本任务最易错的点:。 文档若留有真歧义 → 停下返回 [!] BLOCKED,**绝不猜**。不要写 docs/PROGRESS_LOG.md。 最终消息以可粘贴的日志条目块结尾(状态/改动/验证/决策偏离/遗留/阻塞/commit)。 ``` ## 模板 B · module-reviewer(只读验收/复查) ``` 复查/验收 web-terminal 项目的 <目标>。只读,不改任何源码。 先读:docs/ARCHITECTURE.md 的 <§> + §8 不变量清单 + 锚点 ;docs/PLAN.md 任务 的 Steps/Accept;docs/TECH_DOC.md <§>。 按优先级核:不变量 → 相关 M*/L* 修订是否真落地 → Accept 与 Steps 覆盖 → 编码风格(不可变/小文件/ 错误处理);对抗性地找能打破它的输入/时序/边界。只跑只读或测试命令(vitest run / git diff / grep)。 最终给 findings 报告:verdict PASS / CHANGES NEEDED;每条 finding 标 severity + file:区域 + 违反了哪条不变量/M*/Accept + **路由给哪个 owning task** 去修。无真问题就判 PASS,不要凑数。 ``` --- ## W0 · 基础(串行,主会话直接做或单个 builder) ### T1 — 脚手架 + 装齐依赖 · `Agent(module-builder, model:"sonnet")` ``` 执行 PLAN 任务 T1(脚手架 + 一次性装齐依赖)。先读 CLAUDE.md 工作流、PLAN 任务 T1、ARCHITECTURE §6(S1)。 硬边界 —— 只创建:package.json、tsconfig.json、tsconfig.web.json、.gitignore、vitest.config.ts、空目录骨架。 要点:**一次性**声明全部依赖(运行时 express ws node-pty @xterm/xterm @xterm/addon-fit;开发 typescript tsx vitest @types/node @types/ws @types/express),避免后续并发 npm install 冲突;后端 tsconfig(NodeNext/strict) + 前端 tsconfig.web(lib DOM);.gitignore 含 node_modules/dist;**验证 node-pty 原生编译通过** (npm install 无错 + node -e "require('node-pty')")。Accept:npm install 成功、npm test 能跑、node-pty 可 require。 歧义则 [!] BLOCKED;不写 LOG;结尾给日志条目。 ``` ### T2 — 冻结共享契约 · `Agent(module-builder, model:"sonnet")` ``` 执行 PLAN 任务 T2(共享类型契约 src/types.ts)。先读 PLAN 任务 T2、ARCHITECTURE §3 全部接口定义。 硬边界 —— 只创建:src/types.ts(全局唯一契约源,完成即冻结)。 要点:逐个从 ARCHITECTURE §3 誊写为可编译 TS:Config(含 maxPayloadBytes、allowedOrigins)、 ClientMessage/ServerMessage/ParseResult、Dims、SessionMeta、Session(含 lastOutputAt/exitedAt/exitCode)、 RingBuffer、IPty 子集(pid,cols,rows,onData,onExit,write,resize,kill)、前端 mountKeybar(onSend) 类型; 各模块对外函数签名以注释列出做 import 锚点。Accept:tsc --noEmit 通过,纯类型无实现。 歧义则 [!] BLOCKED;不写 LOG;结尾给日志条目。 ``` ### T3 — mock IPty · `Agent(module-builder, model:"haiku", isolation:"worktree")` ``` 执行 PLAN 任务 T3(mock IPty 测试替身)。先读 PLAN 任务 T3、ARCHITECTURE §7,从 src/types.ts import IPty。 硬边界 —— 只创建:test/helpers/mock-pty.ts。 要点:createMockPty() 实现 IPty,可手动触发 emitData(s)/emitExit(code);记录收到的 write/resize/kill 供断言。 Accept:自带 smoke 测试(emitData 后监听者收到、kill 被记录)。歧义则 [!] BLOCKED;不写 LOG;结尾给日志条目。 ``` > **派 W1 前:`git add -A && git commit` W0 产物**,worktree builder 才能看到 types.ts。 --- ## W1 · 叶子模块(并行,单批 ~3–5 个) ### T4 — config · `Agent(module-builder, model:"sonnet", isolation:"worktree")` ``` 执行 PLAN 任务 T4(config.ts)。先读 PLAN 任务 T4、ARCHITECTURE §3.1,并在 ARCHITECTURE.md 搜 "M1" 照做; 从 src/types.ts import Config。硬边界 —— 只创建:src/config.ts、test/config.test.ts。 要点(M1):loadConfig 读 env 给默认值;**allowedOrigins 由 os.networkInterfaces() 各网卡 IPv4 + localhost + 可选主机名推导(绝不从 bindHost,结果不含 0.0.0.0)**,再并入 ALLOWED_ORIGINS;非法值 fail-fast 抛错; 返回对象 Object.freeze。测试须断言 allowedOrigins 不含 0.0.0.0、含注入的假网卡 IP(mock networkInterfaces)。 Accept:vitest run config 全绿。歧义则 [!] BLOCKED;不写 LOG;结尾给日志条目。 ``` ### T5 — protocol · `Agent(module-builder, model:"sonnet", isolation:"worktree")` ``` 执行 PLAN 任务 T5(protocol.ts)。先读 PLAN 任务 T5、ARCHITECTURE §3.2,搜 "M7" 照做;背景 TECH_DOC §4; 从 src/types.ts import ClientMessage/ServerMessage/ParseResult。硬边界 —— 只创建:src/protocol.ts、test/protocol.test.ts。 要点:export SESSION_ID_RE(UUID v4);parseClientMessage **永不抛异常**,错误全走 ParseResult.ok=false; 校验 JSON→type 白名单→resize cols/rows 1–1000 整数→input.data 必为 string 原样→attach.sessionId 为 null 或 匹配 SESSION_ID_RE(M7:abc123 必须被拒、合法 UUID 通过);serialize 三种 server 消息。 Accept:vitest run protocol 全绿、模糊输入不抛。歧义则 [!] BLOCKED;不写 LOG;结尾给日志条目。 ``` ### T6 — ring-buffer · `Agent(module-builder, model:"opus", isolation:"worktree")` ``` 执行 PLAN 任务 T6(ring-buffer.ts)。先读 PLAN 任务 T6、ARCHITECTURE §3.4 的 RingBuffer 段,**重点搜 "M2" 全文照做**; 从 src/types.ts import RingBuffer。硬边界 —— 只创建:src/session/ring-buffer.ts、test/ring-buffer.test.ts。 要点(M2,最易错):内部用 Buffer('utf8')按**真实字节**计量(非 string.length);超容量时**按 chunk 边界整体淘汰 最旧块**,绝不在多字节 UTF-8 码点或 ANSI 转义序列中间截断;snapshot() 开头补软复位 \x1b[0m。 测试须覆盖:容量内全量回放、超容量淘汰、多字节中文不被截断、ANSI 序列不被切断、按字节计量。 Accept:vitest run ring-buffer 全绿。歧义则 [!] BLOCKED;不写 LOG;结尾给日志条目。 ``` ### T7 — origin · `Agent(module-builder, model:"sonnet", isolation:"worktree")` ``` 执行 PLAN 任务 T7(http/origin.ts)。先读 PLAN 任务 T7、ARCHITECTURE §3.3、TECH_DOC §7(CSWSH)。 硬边界 —— 只创建:src/http/origin.ts、test/origin.test.ts。 要点:isOriginAllowed(origin, allowed) **host+port 双匹配**;undefined Origin 默认拒绝(集中决定,不散落 if)。 测试:白名单命中放行、域名/端口不符拒绝、undefined 拒绝、evil.com 拒绝。 Accept:vitest run origin 全绿。歧义则 [!] BLOCKED;不写 LOG;结尾给日志条目。 ``` ### T8 — index.html · `Agent(module-builder, model:"haiku", isolation:"worktree")` ``` 执行 PLAN 任务 T8(public/index.html)。先读 PLAN 任务 T8、ARCHITECTURE §5。 硬边界 —— 只创建:public/index.html。要点:终端容器 #term、键栏挂载点 #keybar、移动端 viewport meta; **按 PLAN §1 前端构建约定**用 `