第 17 章 · 实战二:多项目并行交付流水线
本章目标:同时推进三个不同项目的任务,掌握 firstmate 的并行路由、dispatch profiles 选型与分项目的合并权限管理,把「一支舰队」用成一条交付流水线。
17.1 场景设定:三个项目、三种任务形态
单任务串行只是起步。FirstMate 的真正价值在于:你描述清楚要做什么,firstmate 把每个请求路由到独立的会话端点 + 独立的 git worktree,互不阻塞。本章设定三条并行工作线:
项目 A(web-api) :ship 任务——修复一个偶发 500 的 bug
项目 B(data-pipeline):scout 任务——只读架构审计,产出报告
项目 C(cli-tool) :ship 任务——新增一个小的 --version 子命令三条线覆盖了第 8 章学过的两种任务形态和第 10 章的三种项目模式,是日常使用的典型缩影。
17.2 一次下达多个任务
不需要排队逐个交代。用一条自然语言消息把三件事一起说清:
> 三件事并行:
> 1) web-api 仓库修掉 /search 偶发 500 的 bug,走完整校验出 PR;
> 2) data-pipeline 只做架构审计:数据流、模块边界、技术债清单,
> 出报告不要动代码;
> 3) cli-tool 加一个 --version 子命令,本地验证后走 local merge。你应该看到什么:firstmate 逐条复述并确认理解(包括每条的任务形态),随后派生最多三个船员,tmux 里出现多个 fm-task* 窗口;各窗口各自推进,完成顺序不必一致。
这里隐含两条机制值得回顾:
- worktree 隔离(第 9 章):三个船员即使涉及同名文件也不会互相踩踏,因为每人一份干净 worktree;
- 零 token 监督(第 11 章):watcher 睡在后台,谁完成、谁卡住才唤醒 firstmate 向你汇报,等待期间不烧 token。
17.3 用 dispatch profiles 给不同任务选不同的 harness
默认情况下所有船员都用同一个 crewmate harness(config/crew-harness)。当不同任务的性质差异很大时,可以启用 dispatch profiles:一个可选的本地 gitignored 文件 config/crew-dispatch.json,里面写自然语言规则,由 firstmate 在派发前阅读并用判断力匹配。
{
"rules": [
{
"when": "bug 修复或需要跑完整测试流水线的 ship 任务",
"use": [{ "harness": "claude", "effort": "high" }],
"why": "修复类任务需要强工具调用与长上下文"
},
{
"when": "架构审计、代码调研类 scout 任务",
"use": [
{ "harness": "pi", "model": "deepseek-chat" },
{ "harness": "grok" }
],
"why": "调研以低成本大吞吐优先,数组形式做配额感知的备选"
}
],
"default": [{ "harness": "claude" }]
}官方 schema 要点:
- 每条规则必须有
when与use;use和顶层default都接受单个 profile 对象或非空数组(数组经 quota-array-dispatch 做配额感知选择); model、effort(low|medium|high|xhigh|max)与规则级why都是可选,省略即用该 harness 自身默认值;- shell 脚本不解析语义——匹配规则靠 firstmate 的判断,脚本只负责把选中的
--harness/--model/--effort具体参数传给fm-spawn.sh并校验 JSON 形状(bootstrap 用jq验证,非法配置报CREW_DISPATCH: invalid ...诊断而不是被悄悄绕过)。
两个必须知道的行为变化:该文件一旦存在,fm-spawn.sh 会拒绝任何没有显式 harness 的船员/scout 启动(config/crew-harness 不再自动兜底);secondmate 的启动豁免于此约束,仍走 config/secondmate-harness。另外这份文件会被继承进 secondmate home,让整个舰队共享同一套派发策略。
# 写好后无需重启,下次 bootstrap 自动校验生效
cat config/crew-dispatch.json | jq empty && echo "JSON OK"17.4 分项目设定合并权限:三种模式各就各位
第 10 章讲过,每个项目的常设姿态记录在 data/projects.md,本章给三个项目分别指派最合适的模式:
| 项目 | 模式 | 理由 |
|---|---|---|
| web-api | direct-PR | bug 修复希望尽快出 PR 走 CI 复核,不需要 no-mistakes 全量校验管线 |
| data-pipeline | (无 ship) | scout 任务永不 push,不存在合并问题 |
| cli-tool | local-only | 小特性本地快改,由 firstmate 在你批准后做 fast-forward 本地合并即可 |
三种模式的官方语义一句话版:no-mistakes 跑完整校验管线、direct-PR 跳过该管线直接开 PR、local-only 停在本地直到 firstmate 执行一次经批准的 fast-forward 合并。可选的 +yolo 标志授予合并自治权——本章刻意不用它,让每一次合并都过你的手。
还有一个安全细节:若某个 ship 任务的执行严格度低于该项目登记的姿态,spawn 时会打印 deviation notice 并继续——登记不是摆设,偏差会被显式暴露。
17.5 决策积压处理:/ahoy 与 /bearings file include PRs
并行任务越多,升级到你面前的决策就越多。两个内置技能构成你的「值班仪表盘」:
> /bearings file include PRs这条命令生成四段式摘要的同时,把带日期的版本报告写入 data/status-report-<YYYY-MM-DD>.md,并通过实时 PR 信息增强内容——适合作为每日开工的第一条指令。
> /ahoy/ahoy 会回顾自你上一条真实消息以来的会话事件,加上未被回应的 captain 决策,然后按影响顺序一次一个引导你把悬而未决的事项处理完。并行场景下建议养成节奏:开工 /bearings,收工前 /ahoy 清空决策队列再离开。
17.6 故意制造冲突:亲眼看 unlanded-work 保护
现在做一个受控实验来理解硬规则 3。趁某个船员还在 worktree 里干活时,你在同一仓库的主 checkout 手动改动文件并保持未提交状态,然后催促任务收尾。
预期行为链:
- 船员的产出照常落地为它的分支/PR——不受你本地脏状态影响(隔离的价值);
- 但任何涉及你未提交改动的 teardown/landing 动作都会被拒绝:uncommitted changes are never landed;
- 只有当你明确授权丢弃那部分工作时,才可能绕过拒绝(且
--force类操作仍需点名的授权)。
这个实验的结论是:FirstMate 对「未落地的劳动」采取保守保护——宁可停下来问你,也不静默销毁或代你提交。
17.7 收尾与复盘
三条线全部到达终点后,逐项复盘:
> /bearings对照检查:A 的 PR 是否带着 risk 标注与 CI 结论?B 的报告是否落在 data/<id>/report.md 并附 decision inventory?C 是否在你批准后完成了 fast-forward 合并而没有产生远程分支?最后让 firstmate 对空闲船员做 teardown——记住空闲的 pane 是健康状态,只有存在 in-flight 工作时 teardown 才会拒绝。
本章沉淀出的流水线节拍可以固化为习惯:开工 /bearings file include PRs → 一句话下达批量任务 → 中途 /ahoy 清决策 → 合并逐个过手 → 收工复盘 + teardown。
17.8 本章小结
- 多任务并行只需一条结构清晰的自然语言消息,路由、隔离、监督全部由 firstmate 负责;
config/crew-dispatch.json用自然语言规则按任务性质选 harness/model/effort,文件存在后 spawn 必须携带显式 harness,配置由 jq 校验且可被 secondmate home 继承;- 项目模式是合并权限的最小授权单位:
no-mistakes全量校验、direct-PR快速出 PR、local-only本地 fast-forward,严格度偏差会有 deviation notice; /ahoy按影响顺序逐一清理决策积压,/bearings file include PRs是并行期的标准日报;- unlanded-work 保护在人为制造冲突时依然成立:未提交的工作绝不静默落地或销毁。
🧪 随堂测验
点击你认为正确的选项。答错时会展示正确答案与原因解析。
1. 关于 config/crew-dispatch.json 的规则匹配,正确的说法是?
2. 一旦 config/crew-dispatch.json 存在,下列哪个说法正确?
3. cli-tool 项目采用 local-only 模式,其官方语义是?
4. 船员仍在工作时,你手动在同一仓库留下未提交改动并催促收尾,firstmate 会如何处理这部分改动?
🛠️ 动手实践
- 为你的舰队编写一份包含至少两条规则和一个 default 的
config/crew-dispatch.json(规则覆盖 ship 修复类与 scout 调研类),用jq empty验证语法,然后重新启动 primary 观察是否有CREW_DISPATCH诊断输出。 - 同时向两个自己的项目下达一 ship 一 scout 两个任务,期间运行
/bearings file include PRs,核对生成的data/status-report-*.md内容是否正确区分了两类任务的进度。 - 复现 17.6 的冲突实验:在船员工作期间向同一仓库主 checkout 写入未提交改动,观察 teardown 的拒绝行为,最后明确授权丢弃后再确认清理成功,并把全过程记录成一篇笔记。