☰
Firstmate × Grok 后台通知监督协议:用跟踪后台任务守护待机周期
2026/10/9 5:54:45 网站建设 项目流程

【免费下载链接】firstmate

Talk to one agent. Ship with a crew.

项目地址:https://gitcode.com/gh_mirrors/fi/firstmate
点击查看免费下载

导读

本文讲解 Firstmate 在 Grok 主表面(primary surface)上的监督协议:当 Grok 会话拥有监督权(owns supervision)且离开模式(away mode)未激活时,如何通过一次**跟踪后台任务(tracked background task)**完成 watcher 的挂载(arm)、等待与再挂载,从而让 Grok 在待机期间持续守护工作队列。读完本文,你将掌握bin/fm-wake-drain.sh的排水与--ack-through确认语义、run_terminal_command后台挂载的精确命令形态、watcher: started / attached / FAILED状态行解读、background-task-completed提醒的处理流程,以及 Grok Stop hook 后备(backstop)的能力选择机制——并能对照源码与测试理解每一环节的底层实现。


一、为什么 Grok 需要一套独立的监督协议

Firstmate 的“Talk to one agent. Ship with a crew”理念要求主会话结束一轮后,后台仍有一个 watcher 持续观察任务队列、分支结果、检查项与 Relay 轮询,并在出现可操作事件时唤醒主会话。不同 harness 的唤醒机制不同:

Harness监督/唤醒模型文档
ClaudeStop钩子 +asyncRewake自动挂载turnend-guard.md
Codex前台有界 checkpoint 轮询codex.md
Cursorstop钩子 park(挂起等待 watcher)turnend-guard.md
Pi / omp / OpenCode扩展/插件在子进程关闭后自动再挂载watcher-continuity.md
Grok跟踪后台任务 + 后台任务完成通知本文

Grok 没有asyncRewake,其 TUI 会话在 turn 结束后无法由 Stop 钩子前台挂起一个长生命周期 watcher;但它支持“跟踪后台任务”并能在后台任务完成时注入一条synthetic_reason: task_completed的合成用户消息。因此 docs/supervision-protocols/grok.md 定义了“background-notify supervision”(后台通知监督)模式:监督本身作为 Grok 的一个后台任务运行,任务完成通知就是唤醒信号。

与之对照,Codex 选择前台有界 checkpoint(bin/fm-watch-checkpoint.sh),因为 Codex 在工具调用运行期间无法推理,必须有界地交还控制权;而 Grok 可以直接消费后台任务的完成通知,见 codex.md。


二、核心协议:Grok background-notify 监督(10 条规则)

当本会话拥有监督权、且离开模式未激活时,协议由以下步骤与硬性约束组成(完整契约见 docs/supervision-protocols/grok.md):

1. 先排水:bin/fm-wake-drain.sh

任何挂载之前,先运行:

bin/fm-wake-drain.sh

处理完所有发出的 wake、并核对OPEN DECISIONS(开放决策)与UNREAD STATUS(未读状态行)之后,必须原样执行 drain 打印的WAKE_ACK_REQUIRED那一行所给出的--ack-through命令。在确认之前,这些工作保持“可持久、可幂等重放”(durable for idempotent re-handling after interruption)——即使会话中途被打断,排水与确认都是可重复执行的。

从实现看,bin/fm-wake-drain.sh的确认语义是“按 actor 消费队列,而非按全局截止点消费”:--ack-through <SEQ>只删除调用方已认领(claimed)的、序号不高于截止值的行;只有--recovery-generation绑定恢复期(recovery episode)的退役。序号更高、随后追加的 wake 会继续留在队列中待呈现(watcher-continuity.md)。

2. Relay 激活时先 source 环境

若 Relay(中继轮询)处于激活状态,先执行:

source __FM_X_MODE_ENV__

其中__FM_X_MODE_ENV__是协议模板中的占位符。协议文本由bin/fm-supervision-instructions.sh生成,脚本在输出前会把__FM_GROK_ARM__等占位符替换为当前 home 解析出的真实 arm 命令(见 bin/fm-supervision-instructions.sh 的line=${line//__FM_GROK_ARM__/$grok_arm})。也就是说,你在会话启动块里看到的实际命令已经是替换好的可执行形态。

3. 首次周期:用跟踪后台工具挂载

第一次挂载必须作为 Grok 自己的独立调用,使用run_terminal_command并携带background: true:

run_terminal_command with background: true on: [ -f __FM_X_MODE_ENV_SH__ ] && . __FM_X_MODE_ENV_SH__; exec __FM_GROK_ARM__

这条命令的含义是:若 X-mode 环境脚本(__FM_X_MODE_ENV_SH__)存在则先 source 之,然后用exec替换进程执行 arm(__FM_GROK_ARM__,即解析后的bin/fm-watch-arm.sh调用)。用exec是为了让后台任务进程本身就是 watcher arm,而不是 arm 的父 shell——这样任务完成通知直接对应 arm 的生命周期。

4. 只信任 arm 的一行状态输出

挂载后,arm 只输出一行状态,Grok 必须只依据这一行判断:

  • watcher: started ...—— 一个新的 watcher 周期已启动,存在 live 周期;
  • watcher: attached ...—— 已附着到既有健康周期;附着后,后台任务会跟随经过身份校验的继任者(verified identity-matched successors),而不是在第一个周期结束时退出;
  • watcher: FAILED ...—— 监督已宕(down),只有在失败或无周期时才需要修复并重新挂载。

这是“arm 层周期契约”的一部分:bin/fm-watch-arm.sh永不返回干净的空成功。子进程返回可操作输出时,arm 正常返回该 reason;返回零/空输出时,arm 重查 home 锁与 beacon,附着到已验证的健康继任者,或对照 watcher 的有界终结投递账本(state/.watch-deliveries.log)解决关闭(watcher-continuity.md)。

5–10. 挂载后的行为约束

  • 成功 start/attach 后结束本轮:后台 arm 保持为 live 等待,直到它返回可操作的 wake 或失败;
  • 等待是静默的:不要在等待期间主动输出或轮询;
  • 绝不使用 shell&做 firstmate 监督;
  • 绝不把 arm 捆绑到其他命令上:shell&、截断管道(truncating pipe)或捆绑调用会被 PreToolUse seatbelt 自动拒绝——当本项目的 Grok 钩子被信任时,bin/fm-arm-pretool-check.sh负责这条安全带(bin/fm-arm-pretool-check.sh)。

为什么禁止&与捆绑?Firstmate 的连续性架构刻意把“必须持续存在的监督”放在进程边界之上:Pi/omp/OpenCode 由适配器在子进程关闭后自动再挂载,Claude 由 Stop 钩子再挂载,而 Grok 依赖跟踪后台任务的生命周期。fire-and-forget 的&无法被 Grok 跟踪,也无法在完成时触发task_completed通知,所以是被拒绝的反模式(watcher-continuity.md)。


三、background-task-completed提醒的处理流程

Grok 在后台 arm 完成时,会注入一条携带synthetic_reason: task_completed的合成用户消息。当你看到针对该 arm 的“后台任务完成”系统提醒时,按以下顺序处理:

  1. 先运行bin/fm-wake-drain.sh(与挂载前相同,处理并确认队列);
  2. 可选:用get_command_or_subagent_output(<task_id>)获取 arm 输出,读取 reason 行;
  3. 若 reason 是signal、stale、check或heartbeat,按AGENTS.md中定义的 harness 无关契约(harness-neutral contract)处理;
  4. 普通 wake:若 home 仍需要监督,用与首次相同的后台__FM_GROK_ARM__调用重新挂载下一周期——正如bin/fm-supervision-lib.sh所定义的那样;
  5. 不要仅凭一行 attach 状态凭空发明一个 wake:先排水,只对真实 wake 记录、drain 的OPEN DECISIONS/UNREAD STATUS条目,或真实 watcher reason 行采取行动。重新挂载时,若已存在健康周期,就附着它并跟随其已验证的继任链。

关于“仅凭 attach 状态不要发明 wake”的底层原因:arm 层周期契约保证——若 attach 状态行对应的是可操作 reason,该 reason 在打印前已被 watcher 连同 PID 与进程身份写入state/.watch-deliveries.log;只有 PID 与身份都匹配,附着 arm 才能在 wake 已被处理并确认后报告投递结果并退出零。没有匹配投递记录的周期才会输出watcher: FAILED - cycle ended without an actionable reason并以非零退出。所以 attach 状态本身不是 wake 证据(watcher-continuity.md)。

等待语义与“One-shot”设计

watcher 刻意保持 one-shot:一个可操作 reason 关闭一个 watcher 周期。连续性(continuity)现在构建在这个进程边界之上,而不是依赖模型记住“再挂载一步”。这正是 Grok 协议中“普通 wake 后重新挂载下一周期”成为强制步骤的原因——重挂载不是可选优化,而是连续性的必须环节(watcher-continuity.md)。


四、监督主机(Supervision Host)在场时

若 home 运行监督主机(config/supervision-host-off可关闭,设计文档见 supervision-host.md),Grok 的跟踪后台 arm 会在普通 arm 的位置运行监督主机:

bin/fm-supervision-host.sh park

其余一切照旧,但有如下补充(supervision-host.md 的{grok}分支):

  • Attended(无 away 记录):每条 wake 都会原样到达你(因为该 harness 尚无已验证的对话镜像可供监督会话消费);
  • Away(存在 away 记录且无 daemon):主机把每条 wake 交给 headless away 会话按 away 记录运行监督分支契约,你被 park;只有主机交还的 wake 才会到达你——表现为 arm 的background-task-completed通知,其输出携带关闭信息加一行supervision-host: <why>;
  • supervision-host: cycle boundary ...:主机在其 park 边界结束本轮,你需要运行bin/fm-wake-drain.sh,处理其呈现的内容,运行其打印的确认命令(空队列会打印--ack-through 0),然后用同一条后台主机调用重新挂载;
  • 第 7 条红线:预工具 seatbelt 不会对主机命令分类,所以必须保持它恰为上面那一条后台调用——绝不 shell&、绝不接管道、绝不捆绑其他命令;
  • /afk只写记录:本 home 上bin/fm-afk-launch.sh start-native会拒绝 away daemon;/quiet遵循 quiet 技能。

主机把 wake 交还给你时,该 wake 是自动监督而非队长的回归:按 away 姿势排水并处理,绝不从它运行回归流程。回归后若出现命名“队长回归”的supervision-host:行,说明该轮有可见结果未包含在回归简报中,需要把每条supervision-host: outcome ...转达给队长(这些行也保留在bin/fm-branch-outcome.sh list中),再排水处理任何排队 wake 后确认。


五、Stop 钩子后备:bin/fm-turnend-guard-grok.sh的能力选择

主项目 Stop 钩子运行bin/fm-turnend-guard-grok.sh作为后备(backstop),而非正常 wake 路径。它解决的是“turn 结束时没有 live watcher”的盲区:bin/fm-guard.sh是拉取式警告,只在其他监督命令调用它时运行;而 turn-end 守卫在主会话自己的边界上堵住剩余缺口(turnend-guard.md)。

能力选择逻辑(源码级)

bin/fm-turnend-guard-grok.sh从每一条正在运行的 Stop payload中做恰好一个类型化能力决策(bin/fm-turnend-guard-grok.sh):

  1. 读取 payload(cat);payload 为空或jq缺失 →exit 0;
  2. 用jq --stream校验 payload 中sessionId、stopHookActive、stop_hook_active各恰好出现一次,否则exit 0;
  3. 能力判定优先级:
    • 布尔字段stopHookActive(camelCase)出现 →native(camelCase 有类型化优先级,两种拼写同时出现时以它为准);
    • 否则布尔字段stop_hook_active(snake_case)出现 →native(兼容旧拼写);
    • 两者皆缺 →legacy(保留一个 pre-native 的grok --resume兜底);
    • 字段类型非布尔、payload 畸形、jq缺失等 → 不启动任何延续路径,直接放行。
  4. native 路径:把 payload 直接管道给bin/fm-turnend-guard.sh,将其退出码 0 或 2 原样返回给同一 Grok 进程——绝不启动grok --resume;
  5. legacy 路径(仅真正 pre-native payload 可达):若GROK_TURNEND_GUARD_ACTIVE已设置则放行;提取字符串sessionId、确认grok可执行,运行共享守卫并捕获 stderr;当守卫返回 2 时,用fm_operational_input_encode turn-end-guard ...编码一条“TURN WOULD END BLIND”操作提示,然后执行:
GROK_TURNEND_GUARD_ACTIVE=1 \ GROK_HOME="${GROK_HOME:-$HOME/.grok}" \ grok --resume "$SESSION_ID" \ --cwd "$ROOT" \ --output-format plain \ -p "$PROMPT"

注意 legacy 兜底有意省略--permission-mode,且受GROK_TURNEND_GUARD_ACTIVE保护,保证一个 turn 只触发一次延续(turnend-guard.md)。

为什么要有这个后备

守卫在 turn 边界上,当“工作/进程事件源/注册检查/Relay 轮询需要监督”且“没有身份匹配且 beacon 新鲜的 watcher”同时成立时动作。Grok 的 native 路径可以像 Claude/Codex 一样用 exit 2 阻塞;legacy 路径则以有界的一次grok --resume延续兜底 pre-native 构建。任何强制延续之后,都需要按上面的后台协议重新挂载 watcher。

该后备还解释了 turnend-guard.md 中的一个关键历史教训:Grok 的 Claude 兼容 settings 加载在GROK_AGENT或GROK_HOOK_EVENT存在时被判定为惰性(inert)——两个标记都必须存在,因为 Grok 不会向每种进程注入相同的变量。若只按GROK_AGENT判定,grok 1.0.0 的钩子进程携带的是GROK_HOOK_EVENT/GROK_HOOK_NAME/GROK_SESSION_ID/GROK_WORKSPACE_ROOT而没有GROK_AGENT,守卫会停止触发,导致 Claude 专属的asyncRewake在 Grok 下同步运行、foreground 等待声明为 28800 秒的超时,Grok turn 永不结束。同时绝不能把守卫扩大到GROK_SESSION_ID——Grok 会把它注入每个子进程,它会存活进 Grok 启动的 Claude 会话,静默禁用 Claude 自己的连续性(turnend-guard.md)。

钩子注册与信任

Grok 注册Stop钩子于.grok/hooks/fm-primary-turnend-guard.json。项目钩子要求 checkout 以/hooks-trust或启动时--trust被信任;真正的 pre-native 构建可以从隔离的全局钩子目录运行同一跟踪钩子。对 grok,fm-spawn.sh还会在$GROK_HOME/hooks/(GROK_HOME未设置时为~/.grok/hooks/)安装一个 firstmate 拥有的全局 turn-end 钩子,并在 worktree 中放置每个任务的.fm-grok-turnend指针令牌,teardown 时移除任务令牌与指针(docs/configuration.md)。


六、支持的表面与明确边界

  • 交互式 TUI 会话是 Grok 主表面的受支持形态;
  • headlessgrok -p可能等待后台进程退出,但不会可靠地完整呈现自动唤醒的模型输出——不要将 firstmate 主会话作为一次性 headless 进程运行(docs/supervision-protocols/grok.md);
  • 这一限制与其他 harness 同类:OpenCode 的目标是持久 TUI 会话而非 headlessopencode run,Cursor 的stop步骤在 headlesscursor-agent -p下不触发(turnend-guard.md);
  • 守卫在无监督需求时静默退出(默认跨 harness 模式);secondmate home、child crewmate/scout worktree 的适用范围由bin/fm-primary-scope-lib.sh判定;
  • 没有任何 harness 适配器用 shell 与号来制造监督。

七、回归测试与验证

Grok 监督路径由以下测试钉住(pin):

  • tests/fm-turnend-guard.test.sh:覆盖 Grok native 与 legacy 能力选择、类型化字段优先级、畸形输入、恰好一条路径的安全性,以及全部五种主 harness 注册;
  • tests/fm-grok-harness.test.sh:Grok harness 适配器测试,被 bin/fm-test-isolation-proof.sh 列入隔离证明清单;
  • tests/fm-watch-arm.test.sh:arm 层周期契约——持久队列重放、世代绑定确认、持久 live 继任者、可处置 checkout 拒绝等;
  • tests/fm-wake-queue.test.sh:按 actor 的混合队列消费、陈旧确认补救、呈现截止点、分支持有行的守卫计数;
  • 可选 live 测试:tests/fm-grok-continuity-live-e2e.test.sh 与 tests/fm-grok-stop-live-e2e.test.sh(见 bin/fm-test-run.sh 的 opt-in 列表),在真实 Grok 安装上验证后台任务通知协议与 Stop 钩子后备。

跨 harness 的实证证据与精确的 opt-in 命令记录在 docs/verification/supervision.md。


八、快速上手:Grok 会话的监督操作清单

  1. 挂载前:bin/fm-wake-drain.sh,处理OPEN DECISIONS/UNREAD STATUS,执行打印的--ack-through确认命令;
  2. Relay 激活时:source__FM_X_MODE_ENV__;
  3. 首次周期:run_terminal_command(background: true)执行[ -f __FM_X_MODE_ENV_SH__ ] && . __FM_X_MODE_ENV_SH__; exec __FM_GROK_ARM__;
  4. 只看一行状态:watcher: started/watcher: attached即视为 live;watcher: FAILED才修复并重挂;
  5. 结束本轮,静默等待;绝不使用 shell&,绝不捆绑其他命令(seatbelt 会自动拒绝);
  6. 收到task_completed提醒:先 drain,可选抓取 arm 输出读 reason,按signal/stale/check/heartbeat或普通 wake 分别处理,然后重新挂载下一周期;
  7. 监督主机在场:arm 位置运行bin/fm-supervision-host.sh park,cycle boundary时 drain + 确认 + 用同一条后台调用重挂;
  8. turn 结束被 Stop 钩子拦下:按 native(exit 2)或 legacy(grok --resume有界延续)路径强制延续后,回到步骤 3 重挂 watcher。

这条协议把 Grok 的原生“跟踪后台任务 + 合成完成通知”能力与 Firstmate 的持久、幂等 wake 队列结合起来,让 Grok 主会话在待机期间获得与 Claude、Codex、Cursor 等 harness 同等强度的监督连续性,同时保持“只信任一行状态、绝不 shell&、绝不捆绑”的硬性纪律。

【免费下载链接】firstmate

Talk to one agent. Ship with a crew.

项目地址:https://gitcode.com/gh_mirrors/fi/firstmate
点击查看免费下载
上一篇:GraphQL APIs项目结构分析:如何高效组织和管理API资源
下一篇:Logseq|双向链接笔记:把想法拆成可互相引用的块

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询