Firstmate OpenCode TUI 插件监督唤醒协议:session.idle 驱动的后台 Watcher 连续再武装

📅 发布时间:2026/10/9 1:51:18
Firstmate OpenCode TUI 插件监督唤醒协议:session.idle 驱动的后台 Watcher 连续再武装
【免费下载链接】firstmateTalk to one agent. Ship with a crew.项目地址https://gitcode.com/gh_mirrors/fi/firstmate点击查看免费下载本指南以 firstmate 的 OpenCode 监督协议 为核心讲解在 OpenCode 持久化 TUI 会话中fm-primary-watch-arm.js插件如何把session.idle事件转化为一次受控的 watcher 再武装从而在无需模型记忆、无需 shell 后台符的前提下维持监督的连续性。读完本文你将掌握 OpenCode 主控场景下唤醒排空、再武装所有权、有限指数退避、失败呈现与 PreToolUse 约束的完整协议并能在 watcher-continuity.md 与 arm-pretool-check.md 的配合下排查监督空窗。背景OpenCode 在 firstmate 中的定位firstmate 支持多种主控 Agent 工具而 OpenCode 是其中被验证支持的一类。项目 README 明确把 OpenCode 列为 verified primary agent harness 之一同时指出其监督方式与其他主控存在差异OpenCode uses a TUI pluginREADME.md。与 Codex 采用有界前台检查点、Grok 保留原生后台通知不同OpenCode 的监督完全依赖持久化 TUI 插件运行时——这正是本篇协议文档的开篇论断OpenCodes persistent TUI plugin runtime is the wake mechanism.这意味着 OpenCode 模式下唤醒不是由模型工具调用、也不是由 shell 后台任务驱动的而是由插件在 OpenCode 会话进入空闲态时自动发起的。协议文档同时划定了适用范围插件在主 primary 检出目录与 secondmate 自己的 home 中生效只在 child crewmate 与 scout 工作树中保持静默。唤醒协议总览九步受控流程docs/supervision-protocols/opencode.md以 Mode: OpenCode TUI plugin background wake 定义了完整的后台唤醒协议。当会话拥有监督权且 away 模式未激活时依次执行以下九步先排空再处理用bin/fm-wake-drain.sh排空。处理完所有已发射的唤醒、调和 open decisions 与未读状态行之后必须执行WAKE_ACK_REQUIRED打印出的精确--ack-through命令在此之前工作保持持久化中断后可幂等重处理。首轮再武装首个周期让.opencode/plugins/fm-primary-watch-arm.js在 OpenCode 会话进入空闲后武装监督。插件监听空闲事件插件监听session.idle在空闲处理器中不等待地派生bin/fm-watch-arm.sh --restart并接管此后每一次后继启动successor launch。动作化子进程关闭后的再检查一次动作化actionable子进程关闭后插件先复查会话锁session-lock所有权、验证存在单一后继然后才调用client.session.promptAsync其有界回退bounded fallback定义于 docs/watcher-continuity.md。普通唤醒不要求模型再武装因为连续性由插件拥有普通唤醒场景下不要请求模型重新武装。意外关闭进入有界指数退避意外的子进程关闭进入有界指数退避退避耗尽或失去会话锁时以 watcher 失败watcher failure形式浮现而不是悄悄消失。失败或缺失周期的手动恢复仅当插件报告 watcher 失败时排空排队唤醒、检查失败文本并把bin/fm-watch-arm.sh仅作为一次短暂恢复探针手动使用。禁止 shell后台监督武装机制是插件所有的不是模型工具调用但手动恢复探针若对武装命令做后台化、管道化或打包会被 PreToolUse seatbelt.opencode/plugins/fm-primary-pretool-check.js、bin/fm-arm-pretool-check.sh自动拒绝。headless 边界不要在无头的opencode run中依赖此插件firstmate 主监督面向持久化 OpenCode TUI 会话。这九步构成了排空 → 再武装 → 等待 → 唤醒呈现 → 失败处理的完整闭环其中每一条都与 watcher-continuity.md 中的底层契约一一对应。唤醒排空与持久化确认第一步为何是WAKE_ACK_REQUIRED协议把bin/fm-wake-drain.sh放在流程最前并非偶然。排空drain是监督事件的消费入口而确认acknowledgement是持久化的关闭条件。根据 watcher-continuity.md一次恢复片段recovery episode是state/.watcher-down标记的一个世代generation它只能由排空打印出的WAKE_ACK_REQUIRED这条世代绑定确认来退役。排空按 actor 消费队列而非按整队截止线消费bin/fm-wake-drain.sh使用bin/fm-lease-lib.sh拥有的fm_lease_actor身份。一次确认携带两个可分离的事实队列行消费绑定到单调的--ack-through序列只有片段退役绑定到--recovery-generation。世代不匹配不会阻塞序列范围内的行消费而是作为非致命结果给出自己的补救办法重新排空再确认更新的片段。对 OpenCode 主控而言这意味着唤醒处理被中断后排空命令依然可幂等重放直到确认真正落下。插件拥有的连续性再武装所有权模型docs/watcher-continuity.md的 Ownership 一节把各主控的再武装所有者列成了一张表其中 OpenCode 的行是HarnessRe-arm ownerOpenCode.opencode/plugins/fm-primary-watch-arm.js与 Pi.pi/extensions/fm-primary-pi-watch.ts、omp.omp/extensions/fm-primary-omp-watch.ts并列这三个适配器共同构成 adapter-owned 连续性模型。每个适配器都满足四条约定的行为在呈现唤醒提示之前启动下一次武装启动时检查当前会话锁所有权任一时刻只保留一个子进程或一个已排程重试意外或失败关闭后应用有界指数退避。这与协议第 3、4 条完全吻合插件在session.idle处理器中不等待地派生bin/fm-watch-arm.sh --restart从而在 OpenCode 会话空闲的第一时刻就把后继 watcher 拉起动作化关闭之后插件必须先确认会话锁所有权与单一后继才交付唤醒。失败的后续动作永远不会取消连续性的恢复。动作化唤醒排序后继先于提示watcher-continuity.md的 Actionable wake ordering 一节进一步给出了 Pi、omp、OpenCode 三者的共同排序OpenCode 逐字适用等待前驱进程关闭启动并验证一个单一后继在调度跟进之前确认处理交接handoffPi 对照恢复自身的恢复令牌确认omp 与 OpenCode 对照当前后继确认交付原始唤醒。交接确认失败时适配器重试一次再次失败即恢复失败适配器对错误分类并浮现恰好一条类型化消息。后继未就绪时会等待一个就绪超时超时后发送 TERM并在下一次锁验证的指数退避前等待有界退役确认。这就是文档所说的 deliberate Option B ordering恢复成功时舰队先受保护再让模型处理唤醒恢复失败时模型也不会被蒙在鼓里。有界指数退避与失败呈现永不静默消失协议第 6 条要求意外关闭进入有界指数退避退避耗尽或失去会话锁时以 watcher 失败浮现。其底层依据在 bin/fm-watch-arm.sh 的注释中写得很直白NEVER fire it and forget with a shellinside another call——被工具调用回收的后台子进程会在调用返回时被收割留下已在运行的假象这个错误曾让监督静默下线约 30 分钟。因此武装必须通过可被跟踪的机制存活并以退出状态作为通知。arm 脚本对每种结局打印恰好一条无歧义状态行watcher: started pidN (beacon fresh) - 启动并确认了一个 watcher watcher: attached pidN (beacon ages) - 有存活的健康后继持锁本 arm 附着跟随 watcher: FAILED - no live watcher with a fresh beacon - 无法确认任何存活 watcher watcher: FAILED - cycle ended without an actionable reason - 干净周期结束却无唤醒且无健康后继 watcher: FAILED - attached watcher pidN stalled (beacon ages at or past hard bound bounds) - 被跟随的持锁者存活但其 beacon 到达停滞上界arm 从不基于过期 beacon 或已死/被复用的 pid 报告 started/attached/healthy单一诚实门槛是锁指向一个真实存活、且身份匹配本 home 的 watcher 进程且 beacon 在FM_GUARD_GRACE默认 300 秒内新鲜。只有一种例外需要借助终局交付账本state/.watch-deliveries.logwatcher 在打印动作化原因、释放单例锁之前会把原因连同 PID 与进程身份记录在案身份匹配的附着 arm 即使在其持久化唤醒已被处理并确认之后也能报告该原因并退出零。只有既无交付记录、又无健康后继的周期才输出watcher: FAILED - cycle ended without an actionable reason并以非零退出——失败永远是响亮的。每个被观察的 watcher 周期还会向state/.watch-cycle-exits.log追加一条 tab 分隔的生命周期记录包含 arm/watcher PID、起止时间戳、退出码与信号、分类原因、beacon 年龄、关闭前后的锁身份与后继处置文件通过FM_WATCH_CYCLE_LOG_MAX_BYTES默认 262144与FM_WATCH_CYCLE_LOG_KEEP_LINES默认 1000做大小封顶。这为失败呈现提供了可审计的证据链。PreToolUse seatbelt手动恢复探针的自动拒绝边界协议第 8 条是本篇文档最具防御性的部分手动恢复探针若把武装命令后台化、管道化或打包会被.opencode/plugins/fm-primary-pretool-check.js与bin/fm-arm-pretool-check.sh自动拒绝。这份契约的权威语义由 docs/arm-pretool-check.md 承载语义所有者是bin/fm-arm-command-policy.mjsbin/fm-arm-pretool-check.sh只是稳定传输层与输出渲染器分类器只做词法执行位置分析绝不执行、source、求值或展开命令的任何部分。OpenCode 接线.opencode/plugins/fm-primary-pretool-check.js从output.args.command读取命令以一个--command exact string参数传给检查器且只在检查器退出 2 时抛错throw。受保护命令身份bin/fm-watch-arm.sh与bin/fm-watch-checkpoint.sh是被祝福blessed的入口点bin/fm-watch.sh受保护但绝不被祝福直接执行一律以watcher-direct拒绝。后缀匹配还能静态识别$FM_HOME/bin/fm-watch-arm.sh、~/firstmate/bin/fm-watch-arm.sh等展开路径形态以及被普通引号、ANSI-C 引号、bash locale 字符串切割的命令字。拒绝原因码是稳定契约watcher-background异步列表/nohup/disown、watcher-pipeline、watcher-redirection、watcher-bundled、watcher-nested、broad-watcher-kill、unclassifiable-protected-command、watcher-direct。协议第 8 条所说的 denied automatically 正是watcher-background这类稳定码的自动映射。被祝福的语法树允许的 watcher 程序是一条线性外层命令列表——零或多个被批准的设置节点cd 一个路径词、无替换/无重定向的export NAME一个 shell 词、source x-mode 路径等后跟恰好一个直接受保护节点。tests/fm-arm-pretool-check.test.sh拥有对抗性验收矩阵每一行都同时跑过 OpenCode 形态--commandCLI与其他各主控形态的入口并验证精确的适配器字段转发与退出 2 映射。注意 seatbelt 是执行前约束不是武装后的存活性保证——武装后的监督谓词由bin/fm-guard.sh与bin/fm-turnend-guard.sh依据 watcher 锁与 beacon 另行施加。适用范围与 headless 边界协议第 9 条与结尾段共同划定了插件生效的精确边界生效于主 primary 检出目录、secondmate 自己的 home静默于child crewmate 与 scout 工作树不依赖headlessopencode run。这与 watcher-continuity.md 的 Active limits 一致OpenCode 支持目标是持久化 TUI 会话而非无头运行同时项目不承诺零延迟因为锁验证、watcher 启动与有界退避的延迟都是刻意的安全工作。tests/fm-opencode-primary-live-e2e.test.sh是一个 opt-in 的凭据化 OpenCode 连续性回归它要求FM_OPENCODE_LIVE_E2E1并依赖opencode、tmux、sqlite3在隔离项目与独立FM_HOME上通过 tmux 驱动真实 TUI 会话用capture-pane轮询断言文本出现与消失验证插件的会话启动、watcher 注入与唤醒路径tests/fm-opencode-primary-live-e2e.test.sh。而 tests/fm-pi-watch-extension.test.sh 则同时针对 Pi 与 OpenCode 的实际关闭处理器模拟动作化与空关闭并验证后继先于提示交付、单飞single-flight行为、会话锁变更触发所有权复查、挂起的后继 arm 触发包含类型化恢复失败的有界回退交付。小结模型不记忆插件来接管把整篇协议压缩成一句话OpenCode 模式下watcher 的再武装从模型记得做迁移为插件自动做。session.idle是触发器bin/fm-watch-arm.sh --restart是被跟踪的派生物client.session.promptAsync是唤醒交付点PreToolUse seatbelt 是手动路径的护栏WAKE_ACK_REQUIRED是持久化确认的关闸。理解这五者的关系就能在 OpenCode 主控部署中既享受免手动再武装的连续性又能在失败浮现时按协议第 7 条做一次短暂、受控、被 seatbelt 全程监督的手动恢复探针。如需深入排查监督空窗建议按以下路线阅读仓库证据watcher-continuity.md连续性契约总纲、arm-pretool-check.mdseatbelt 语义与稳定拒绝码、bin/fm-watch-arm.sharm 状态行与终局交付账本、tests/fm-opencode-primary-live-e2e.test.sh真实 TUI 端到端回归、tests/fm-arm-pretool-check.test.sh对抗性 seatbelt 验收。赞分享【免费下载链接】firstmateTalk to one agent. Ship with a crew.项目地址https://gitcode.com/gh_mirrors/fi/firstmate点击查看免费下载相关推荐Firstmate Pi 扩展后台唤醒与监督分支协议从接管舰队锁到事件驱动的零 Token 监督Firstmate Pi 扩展后台唤醒与监督分支协议从接管舰队锁到事件驱动的零 Token 监督 本文基于 docs/supervision protocolFirstmate 的 Claude Stop-hook 监督协议让 watcher 连续性与“不盲停”真正自动化Firstmate 的 Claude Stop hook 监督协议让 watcher 连续性与“不盲停”真正自动化 导读 本文讲解 Firstmate 在 CFirstmate 的 Codex 前台监督协议基于有界检查点Bounded Foreground Checkpoint的 Watcher 监督机制Firstmate 的 Codex 前台监督协议基于有界检查点Bounded Foreground Checkpoint的 Watcher 监督机制 Co上一篇Codex 技能安装指南用 skill-installer 三步装好第一个技能下一篇3分钟打破音乐壁垒163MusicLyrics的智能歌词革命创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考