第 6 章 · 会话后端:tmux 参考后端
本章目标:理解会话后端(runtime backend)在舰队体系中的角色,掌握 tmux 作为 verified reference backend 的安装、窗口拓扑、监督操作与存活探测机制。
6.1 会话后端是什么
每个 crewmate 都是一个自主运行的 agent 进程,而 agent 进程需要一个可见、可观察、可介入的会话端点(session endpoint)。会话后端就是承载这些端点的终端基础设施:
┌─ backend = tmux ──► tmux window (参考实现)
firstmate 派生任务 ──┼─ backend = herdr ──► herdr tab (实验)
├─ backend = zellij ──► zellij tab (实验)
├─ backend = orca ──► Orca terminal (实验, macOS)
└─ backend = cmux ──► cmux workspace(实验, macOS)后端决定三件事:任务端点落在哪里、captain 如何观看(watch)、以及 firstmate 如何投递指令与读取状态。下一章我们会逐一认识四个实验性后端;本章先吃透参考实现——tmux。
6.2 后端选择链
FirstMate 按以下优先级决定使用哪个后端:
1. config/backend 文件显式指定 ← 最高优先级(本地 gitignored 配置)
2. FM_BACKEND=<name> 环境变量 ← 仅本次启动生效
3. runtime auto-detection ← 自动检测(仅部分后端参与,见第 7 章)
4. tmux ← hard default 兜底也就是说:什么都不配置时,tmux 就是默认答案。反过来,在 config/backend 里写入 tmux 或用 FM_BACKEND=tmux 显式选择,同时也是退出 Herdr/cmux 自动检测的开关——这一点在混合环境里非常实用。
# 方式一:持久选择(写入本地配置,gitignored)
echo "tmux" > config/backend
# 方式二:一次性选择
FM_BACKEND=tmux claude
# 方式三:直接用自然语言要求 firstmate 使用 tmux
> 请用 tmux 作为会话后端6.3 安装与前置条件
tmux 本体一行命令即可安装:
brew install tmux # macOS
# 或使用你平台的包管理器,如 apt install tmux除 tmux 外还需满足通用工具链要求(configuration.md 的 toolchain 一节统一约定):
- 一个已验证的主 harness CLI:Claude Code、Grok、Pi(或 pi-signed)、Codex、OpenCode、Cursor Agent CLI 之一;
- Git 与 GitHub CLI,且已通过
gh auth login完成认证; - 所选后端的依赖(tmux 场景即 tmux 自身)。
tmux 后端的一大优点是零预备步骤:官方文档明确写着 "No provisioning is required before the first task",装好就能跑。
6.4 窗口拓扑:任务即窗口
tmux 后端推荐的体验是把主 harness 启动在一个 tmux session 里:
tmux new -s firstmate # 创建并进入名为 firstmate 的 session
claude # 在其中启动主 harness(也可用 grok --trust / pi 等)此后每个 crew 任务都成为这个 session 里的一个窗口,命名格式为 fm-<id>:
# 查看舰队当前的所有任务窗口
tmux list-windows -t firstmate
# 输出示意:
# 0: main* 1: fm-a1b2- 2: fm-c3d4如果主 harness 运行在 tmux 之外也没关系——FirstMate 会自动创建或复用一个名为 firstmate 的 detached session:
tmux attach -t firstmate # 随时附着查看舰队6.5 监督而不附着
日常监督不需要逐个 attach 进窗口。FirstMate 提供两个轻量入口:
# 偷看某个任务的最近输出(有界 tail,不刷屏)
bin/fm-peek.sh <task-id>
# 向任务端点投递一条转向指令(需显式 FM_HOME)
FM_HOME=<home> bin/fm-send.sh <task-id> '改用方案 B,注意保留现有测试'这里有一条与第 4 章硬规则呼应的红线:如果你亲自 attach 到任务窗口里打字,那属于 authoritative direct intervention(权威的直接介入)——你的输入立即生效,但 firstmate 会在下一次监督评审时 reconcile 这次场外指挥。日常还是走 fm-send.sh,让通信保持单一联络人模型。
6.6 Agent 存活探测(liveness probe)
"窗口还在"不等于"agent 还活着"。tmux 后端的存活探测分两层:
第一层:目标存在性检查 —— pane 还在吗?
第二层:进程名身份识别 —— pane 里跑的是 harness 还是裸 shell?第二层是关键。探测器组合多个独立来源读取进程名:#{pane_current_command}、pane tty 前台进程组的内核 comm 值、甚至 argv[0] 的安装路径成分。之所以要多源交叉验证,是因为不同平台上哪个字段保留可执行文件真实名字并不确定。
探测结果分为五类判定:
| 判定 | 含义 | 是否触发恢复 |
|---|---|---|
alive | 识别出已知 harness 进程(Claude/Codex/OpenCode/Pi/pi-signed/Grok/Kimi/Cursor/Muse) | 否 |
dead | 前台只是普通 shell | ✅ 是 |
missing | 窗口权威性地不存在 | ✅ 是 |
unreadable | 状态不可读 | 否 |
ambiguous | 其他未知进程 | 否 |
注意一个精妙的设计约束:只有 dead 和 missing 授权恢复。因为一次误判的 "dead" 可能导致在同一个 worktree 上再拉起一个重复 agent——这比漏掉恢复严重得多。所以任何单一来源都无法单独给出负面结论,必须前台进程组可读且证据一致才行。
还有一个反直觉的细节:探测器把范围限定在前台进程组而非 pane 的全部后代进程。这是刻意的——一个残留在后台的 harness 同名进程,不应让一个其实空闲的 pane 被误读成"agent 还活着"。
6.7 当前行为与限制小结
官方文档为 tmux 后端记录了完整的回归测试入口,包括冒烟测试、存活探测测试、composer 幽灵文本测试等:
tests/fm-backend-tmux-smoke.test.sh # 后端冒烟
tests/fm-tmux-agent-liveness.test.sh # 存活探测
tests/fm-composer-ghost.test.sh # composer 判定
tests/fm-tmux-submit-busy.test.sh # 提交与忙碌状态需要记住的限制与定位:
- tmux 是 reference path,也是唯一完整支持 secondmate homes 的基线;
- 忙碌状态不从渲染文本猜测,而是走语义 busy-state 契约(
bin/fm-busy-lib.sh); - 投递确认采用严格标准:只有被证明为空的 composer 才算投递成功,模糊状态一律保守处理,绝不重打文本。
6.8 验证安装
一切就绪后,用最小任务验证整条链路:派生一个小任务,确认它的 fm-<id> 窗口出现在预期的 session 中即可。
$ tmux list-windows -t firstmate
0: bash 1: fm-e5f6*看到新窗口出现、fm-peek.sh <id> 能读到 agent 输出,说明 tmux 后端工作正常。
本章小结
- 会话后端决定 crewmate 端点的位置与监督方式;tmux 是 verified reference backend 与 hard default;
- 选择链为:config/backend 显式 > FM_BACKEND 一次性 > 自动检测 > tmux 兜底,显式选 tmux 同时退出自动检测;
- 推荐把主 harness 跑在
tmux new -s firstmate内,任务窗口命名为fm-<id>;主 harness 不在 tmux 内时会创建/复用同名 detached session; - 日常监督用
bin/fm-peek.sh与bin/fm-send.sh,不必 attach;attach 后打字属于权威介入,将在下次监督评审时 reconcile; - 存活探测输出 alive/dead/missing/unreadable/ambiguous 五类判定,只有 dead 与 missing 触发恢复,以避免重复 agent 风险。
🧪 随堂测验
点击你认为正确的选项。答错时会展示正确答案与原因解析。
1. 什么都没配置时,FirstMate 使用哪个会话后端?
2. 主 harness 未运行在 tmux 内时,FirstMate 如何处理?
3. 存活探测的五类判定中,哪些会触发恢复动作?
4. 为什么存活探测要把进程名来源限定在前台进程组而非 pane 的所有后代?
🛠️ 动手实践
- 安装 tmux 并执行
tmux new -s firstmate,在其中启动你最常用的 harness,然后另开一个终端用tmux list-windows -t firstmate观察 session 结构。 - 通过 firstmate 派生一个极小的 scout 任务(例如"调查某仓库的 LICENSE 类型"),用
bin/fm-peek.sh <id>跟踪它,记录窗口名fm-<id>的出现时机。 - 阅读
docs/tmux-backend.md的 Agent liveness probe 一节,画出五类判定的决策流程图,并解释为什么ambiguous不授权恢复。