【免费下载链接】firstmate
Talk to one agent. Ship with a crew.
本指南以 docs/verification/agy.md 这份验证记录为骨架,围绕 firstmate 项目中 agy(Antigravity CLI)crewmate/scout 适配器的检测、启动、信任对话框处理、忙碌状态判定、中断与退出、后端存活探活以及监督式任务全流程展开。读完本文,你将掌握 agy 为何"只有进程名可检测"、
--prompt-interactive启动形态的完整命令构成、trustedWorkspaces预注册的安全语义与原子写入方式,以及agy_wait_for_going就绪闸门如何把"对话框已应答 + 忙碌签名"作为 spawn 成功的双重证据——这些知识可以直接迁移到任何需要在无人值守 TUI 后端上托管外部 CLI 的编排系统设计中。
1. 文档定位:一份"经验事实"而非"操作手册"
docs/verification/agy.md在 firstmate 仓库中扮演特殊角色:它记录的不是该适配器的操作事实本体(那由.agents/skills/harness-adapters/SKILL.md及其 references/harness/agy.md 知识树持有),而是这些事实是如何被建立、以及哪些仍未得到证明的验证档案。因此本文同样以"验证了什么、怎么验证的、边界在哪"为叙事主线,而不是一份安装教程。
验证对象的基本盘如下表:
| 字段 | 值 |
|---|---|
| 版本 | agy 1.2.0;发送确认时序在agy 1.2.1(2026-09-12)上重测 |
| 验证时间 | 2026-09-10 |
| 二进制 | /home/andpod/.local/bin/agy,ELF 64 位 Go 编译的单一可执行文件 |
| 平台 | Linux x64(Arch,内核 7.2.3) |
| 后端 | Herdr,在隔离的非default实验室会话中(fm-lab-firstmate-agy-ad-*,经 bin/fm-herdr-lab.sh 创建);全程未触碰default会话与 captain fleet 状态 |
所有命令都在可丢弃的 firstmate 任务工作树或命名 Herdr 实验室会话内运行,不涉及任何 fleet 状态。
2. 检测:仅靠祖先进程名,无身份标记
agy 与 claude、codex 等"有环境变量标记"的适配器不同,它不发布任何身份标记。实测证据链如下:
agy --version输出1.2.0。- 一个活跃 TUI 的
/proc/<pid>/environ中没有任何AGY_*或ANTIGRAVITY_*变量。 - 环境里确实有
AGENT=1与CLAUDECODE=1,但两者都继承自启动环境——AGENT不是 agy 身份,而CLAUDECODE会让检测器误判成 claude,所以都不能被提升为标记。 - Herdr 的
pane process-info报告该 pane 的前台进程为name=agy、argv=["agy", ...];ps -o comm=同样输出agy。
因此 bin/fm-harness.sh 采用锚定进程名agy单独匹配(代码注释明确:"Anchored, never*agy*, so unrelated commands cannot be misread as this harness"),并在启动边界清掉CLAUDECODE、PI_CODING_AGENT、GROK_AGENT、FM_PI_HARNESS四个外来标记——理由与 cursor 适配器相同:agy 不清理继承的CLAUDECODE,若不主动清除,bin/fm-harness.sh会把 agy worker 误读成其启动者(claude)。锚定的必要性同样体现在 bin/fm-agent-process-lib.sh:agy与 muse、omp 一样是裸词进程名,通配agy*会误吞无关命令。
tests/fm-agy-harness.test.sh 用三组用例钉死这三件事:
test_agy_ancestry_detects_the_native_command_name——锚定匹配生效;test_agy_ancestry_rejects_unrelated_mentions——含agy片段的无关名字被拒绝;test_agy_claims_no_inherited_launcher_marker——被 spawn 清除后,继承的CLAUDECODE永远无法压过一个真实的agy祖先。
3. 启动形态:位置参数 +--prompt-interactive自动提交
验证中使用的完整启动命令:
$ agy --prompt-interactive "Reply with exactly AGY_LIVE_PROBE_OK and nothing else" --model gemini-3.8-flash-low --effort low --dangerously-skip-permissions观察到的行为:brief 自动提交(无需额外回车),回合运行,回复渲染到 pane 中;同一目录第二次启动以同样方式应答新 prompt,证明该形态可重复而非首次运行巧合。页脚渲染Gemini 3.8 Flash · low,证明--model与--effort两个旗标被同时接受。
bin/fm-spawn.sh 的launch_template将其固化为可展开模板(agy 分支):
env -u CLAUDECODE -u PI_CODING_AGENT -u GROK_AGENT -u FM_PI_HARNESS \ __AGYBIN__ --prompt-interactive "$(__OPINPUT__ encode launch-brief < __BRIEF__)" \ __MODELFLAG____EFFORTFLAG__--dangerously-skip-permissions几个细节值得展开:
- brief 随启动命令携带:
--prompt-interactive "<brief>"启动监督式交互会话并自动提交,因此 agy不需要像 claude 那样额外的投递闸门(bin/fm-spawn.sh 第 4276 行注释明言:"agy carries its brief on the launch command, so it needs no delivery gate")。 --dangerously-skip-permissions自动批准所有工具调用,是无人值守 crewmate 的必要条件。- 占位符展开:
__AGYBIN__解析为经过校验的 agy 可执行文件绝对路径(resolve_pi_executable agy,找不到时直接报错"install Antigravity CLI or select a different verified harness");__MODELFLAG__/__EFFORTFLAG__按模型与力度生成旗标。 - 任务种类限制:agy 与 muse、gemini、devin 一样仅验证为 crewmate/scout 适配器,
--secondmate直接被拒(bin/fm-spawn.sh 第 2357 行);docs/supervision-protocols/下也没有 agy 的 wake 协议。
测试 tests/fm-agy-harness.test.sh 的test_agy_launch_carries_the_brief_with_model_effort_and_autonomy逐项断言:启动命令钉死解析后的绝对二进制路径、携带--prompt-interactive、--model 'gemini-3.8-flash-low'、--effort 'low'、--dangerously-skip-permissions,且清理了继承的CLAUDECODE,所有占位符都被替换。test_agy_effort_xhigh_is_recorded_but_omitted则验证:请求xhigh时元数据仍记录该意图,但启动命令中不出现--effort(agy 1.2.0 只接受low|medium|high)。
4. 模型与力度:agy models远程目录校验
agy models的输出形态:
$ agy models Fetching available models... gemini-3.8-flash-high Gemini 3.8 Flash (High) gemini-3.8-flash-medium Gemini 3.8 Flash (Medium) gemini-3.8-flash-low Gemini 3.8 Flash (Low) ...要点:
agy --help将--effort文档化为low|medium|high,--model为会话模型。- 模型 id 是裸 id(
gemini-3.8-flash-high),绝无 provider 前缀;此前配置中无后缀的gemini-3.8-flash不在列表中,只有带-high/-medium/-low后缀的变体。 - 该列表是远程拉取(输出首行
Fetching available models...),依赖网络与已登录账号。
bin/fm-spawn.sh 的agy_model_validate据此实现三层策略:
- 列表可达且请求 id 不在其中 → 拒绝 spawn:
error: agy model '<model>' is not listed by 'agy models'; choose a listed id or omit --model。这使过期的 id(如已下线的裸gemini-3.8-flash)在创建任何 pane 之前大声失败,而不是卡死一个 worker pane。 - 列表不可达(非 124 退出码)→ 放行但打 notice:
listing is unreachable (exit N); launching with --model '<model>' unvalidated——不可达的列表"什么也没证明",因此不阻塞。 - 列表超时(退出码 124)→ 同样放行并 notice:探测运行在 bin/fm-timeout-lib.sh 的共享硬时限下(默认 15 秒,环境变量
FM_AGY_MODELS_TIMEOUT可调;非正数或非数值会被钳回 15,因为"非正的时限不算时限"),stdin 分离运行——卡死的拉取或登录提示被切断后落到未校验启动,绝不让 spawn 在 pane 尚未存在时被阻塞。
print模式是另一条验证凭证路径的手段:agy -p "Reply with exactly: AGY_PRINT_PROBE_OK" --model gemini-3.8-flash-low在约 8 秒内以退出码 0 返回完全一致的回复,证明无 pane 情况下凭证链路可用。
5. 信任对话框:预先注册为主,忙碌回合闸门兜底
5.1 现象与根因
在全新工作树中的首次启动会弹出文件夹信任对话框:
Accessing workspace: /home/andpod/.treehouse/firstmate-7bab20/1/firstmate/agy-probe-tmp Do you trust the contents of this project? Antigravity CLI requires permission to read, edit, and execute files here. > Yes, I trust this folder No, exitagy --help(1.2.0)没有列出任何信任旗标或预注册命令,但 agy 会认领启动前写入~/.gemini/antigravity-cli/settings.json中trustedWorkspaces数组的条目。验证过程在一次性HOME(持有~/.gemini副本,真实设置文件从未被写入)下完成:
- 手工把文件夹追加进数组后,
--prompt-interactive启动直接进入回合并渲染回复,无对话框; - 同一方式启动未注册的兄弟文件夹,则停在对话框上。
两个关键语义:
- agy 比较的是 pane 的逻辑工作目录而非解析路径:只注册真实路径而 cwd 是符号链接时,仍会停在对话框上。因此 bin/fm-agy-trust.sh 在两者不同时同时记录逻辑路径与其解析形式。
- 注册失败只是 stderr 警告而非拒绝:因为 agy 的对话框预选了安全答案("Yes, I trust this folder"),且下方闸门可以代答它。这与 claude 的对话框(未预选、阻塞一切)形成鲜明对照,后者注册失败会直接拒绝 spawn。
5.2 安全语义:结构性作用域测试
bin/fm-agy-trust.sh 的注释开宗明义:"THE SCOPE TEST IS THE SAFETY PROPERTY"。它复刻了 bin/fm-claude-trust.sh 的形状,对<worktree>施加严格的结构约束:
- 必须是链接的 git worktree——拥有自己的 git dir、与
<project>共享 common dir,且顶层恰好等于解析后的参数; - 主检出(primary checkout)、无关仓库的 worktree、worktree 的子目录、普通目录、主目录一律以非零退出拒绝,绝不警告后跳过;
- 只写启动用户自己的 store,store 必须是本 uid 拥有的常规文件;
- 保留 store 中所有无关键与条目,替换是原子的。
实现细节:refuse()统一打印error: refusing to pre-register agy trust: <原因>并以 1 退出;依次校验 worktree 可访问、非主目录、处于 git 仓库内、是 worktree 根、git dir 与 common dir 可解析且不同(不同才证明是隔离 worktree 而非主检出)、与项目共享 common dir;随后用内嵌 Node 脚本做读-改-写 + 指纹校验 + 回读:先 SHA-256 指纹原文件,写入临时文件(0600、wx独占创建),rename 前再次指纹对比(防止 agy 自己重写了文件),rename 后回读确认条目在列;若发现 store 被并发移动,最多重试一次后拒绝覆盖。整个注册过程最多 3 次尝试,全部失败则报错退出。
5.3 为什么不能只靠预注册:实测的边界行为
验证记录了若干令人警醒的实测观察:
- 两次受监督的 Herdr 运行在 treehouse worktree 中完成了文件写入回合,而观测时对话框仍未应答(worker 文件与
done:状态行都在向 pane 发送 Enter 之前就已落盘)。 - 在不受信任的
/tmp目录中的隔离运行从未在 Enter 之前到达工作区:回合改在 agy 自己的 scratch 目录里做探索性工具调用,只有排队的 prompt 在应答后才运行。 - 有一次运行搁置数分钟未应答,最终应答后把文件写进了 agy 的 scratch 目录而不是工作区。
- 差异背后的机制未被建立:路径、后端、延迟在多次运行中都有变化,但未能隔离出单一原因。
正是这些观察决定了 spawn不依赖预注册单独生效,而是再加一道闸门。
5.4 就绪闸门:agy_wait_for_working
bin/fm-spawn.sh 在预注册之后运行后启动就绪闸门(rovo/kimi 的"先启动后确认"形态),核心逻辑(约第 4290–4324 行):
- 常量
AGY_TRUST_DIALOG='Do you trust the contents of this project?'精确匹配对话框文本; - 轮询 pane 捕获(默认
FM_AGY_READY_POLLS=60次、间隔FM_AGY_POLL_INTERVAL=0.5秒):- 若看到对话框且尚未应答 → 发送单个 Enter(利用预选的"Yes, I trust this folder"),标记
AGY_TRUST_ANSWERED=1; - 否则若路径已预注册或对话框已应答 → 用
fm_busy_classify判定忙碌(Herdr 原生working或钉住的esc to cancel状态行),忙碌即视为就绪并返回 0;
- 若看到对话框且尚未应答 → 发送单个 Enter(利用预选的"Yes, I trust this folder"),标记
- 顺序严格:由于 Herdr 的原生
working判定已知可与未应答对话框共存,忙碌只有在"worktree 已预注册"或"对话框已看到并应答"时才计为就绪;未注册路径上持续轮询对话框,而非接受过早的忙碌判定。 - 若窗口内无法确认 brief 已运行(应答过的对话框始终不转忙碌、预信任 pane 始终不转忙碌、未注册 pane 始终不显示对话框),则 spawn 失败:向任务状态写入
failed:,并关闭 endpoint(rovo_endpoint_cleanup),确保没有孤儿 worker 存活在任务控制之外。
tests/fm-agy-harness.test.sh 用一个"读 spawn 刚写好的 store 来做对话框决策"的假 pane 覆盖了全部四条路径:预信任启动无对话框、对话框照常渲染且恰好应答一次、未注册路径上的过早忙碌判定继续等对话框、以及两条失败并关闭路径。
6. 忙碌状态:钉住的状态行是唯一信号,缺失即 unknown
回合中途,pane 同时渲染状态行与 spinner 行:
⣯ Generating... └ Tip: When reviewing a file edit, press f to see the full diff. ... esc to cancel Gemini 3.8 Flash · low回合完成后的空闲 composer:
> ────────────────────────────────────────────────────────────────────────────── ? for shortcuts Gemini 3.8 Flash · lowbin/fm-busy-lib.sh 的fm_busy_agy_tail_busy与投递守卫只匹配esc to cancel这个 token:
- TUI 在整个回合期间把该状态行钉在 pane 底部;空闲行则替换为
? for shortcuts。 Generating...这个 spinner 词刻意不作为信号:它是自由浮动的输出行,普通 worker 输出(如Generating report...)若被当作信号,会把空闲 worker 误判为忙碌、或"确认"一个根本没落地的提交。- 现场观察中没有任何忙碌阶段缺少状态行:每个捕获到的回合中帧都带有它。
- token 缺失时
fm_busy_classify报告unknown agy-regex——长回合可能把标记滚出捕获尾部。 - 签名硬编码、无环境变量覆盖,因此杂散变量永远无法改变 worker 状态分类。
- 旁证:Herdr 自己的注册表全程一致——
agent get在回合中报告agent_status=working、之后idle,因此在 Herdr 上原生判定即可携带忙碌,无需新代码。
测试 tests/fm-agy-harness.test.sh 中test_agy_busy_tail_needs_the_pinned_status_row、test_agy_busy_signatures_are_harness_scoped、test_agy_classify_reports_unknown_when_the_marker_scrolls_out分别钉死:只有钉住的状态行才算忙碌、签名按 harness 隔离、滚出捕获尾时报告 unknown。
7. 中断与退出:单次 Escape 取消,/quit退出
- 回合中经
herdr pane send-keys发送单个Escape即可取消回合,打印如下行,composer 回到空闲、无文本再污染:
⎿ Interrupted · What should Antigravity CLI do instead?- 发送
/quit加 Enter 退出进程;pane 在exec启动方式下关闭,Herdr 报告 pane 消失。
bin/fm-control-lib.sh 对 agy 记录:中断键Escape(一次,无清除键,无 ack 来源)、退出命令/quit(与 codex、pi、omp、gemini、devin 相同)。test_agy_control_mechanics_are_the_verified_ones钉死该控制机制。
8. 后端存活:Herdr 原生识别,tmux 靠进程名
$ herdr agent get w2:p1 --session fm-lab-firstmate-agy-ad-1599574-8823 {"result":{"agent":{"agent":"agy","agent_status":"idle",...,"agent_session":{"agent":"agy","kind":"id","source":"herdr:antigravity_cli",...}}}}- Herdr原生跟踪 agy(
antigravity-cli集成,检测为agent=agy),因此fm_backend_herdr_pane_agent_state对 agy 的每个已注册状态都返回live,无需任何退出检测加固。 - tmux 适配器通过 bin/fm-agent-process-lib.sh 的共享名称词汇表,把锚定进程名
agy分类为agent——这是 muse/omp 开创的"短裸词名"先例。 - agy 不在 bin/fm-session-lock-lib.sh 的会话锁名称词汇表中——其他纯 crewmate 适配器同样缺席。
9. Composer:按设计判为 unknown,投递靠忙碌转换
对空闲 pane 的字节级捕获显示:一个无样式的裸>位于两条全宽─规则之间,状态行中是未样式化的? for shortcutscell 与一个暗色(SGR 2)模型 cell。共享分类器在死壳规则下把裸>判为unknown,永远不会是empty。
但投递确认依然成立,因为:
- Herdr 提交核心以原生
idle→working转换为先导,而 agy 会执行这个转换; - tmux 路径由投递页脚正则覆盖。
实测时序(agy 1.2.1,2026-09-12 重测)暴露了 agy 的确认循环特性:忙碌页脚渲染较晚——短 steer 约在 Enter 后 1.5 秒,较长真实 brief 约 4–5 秒,而共享预算只有 3 × 0.4 秒。因此 bin/fm-send.sh 给 agy 的键入目标更长的默认提交确认预算:FM_SEND_RETRIES缺省 20 次重试(默认节奏下约 8 秒);显式FM_SEND_RETRIES仍然优先,其余每个 harness 保持共享的 3 次重试缺省。测试钉死:tests/fm-send-agy-confirm.test.sh 锁定提高后的默认值,tests/fm-agy-harness.test.sh 锁定 Herdr 转换路径。这是 cursor 的先例,而非需要在共享代码里打补丁的缺口。
10. 监督式任务全流程:spawn、steer、relaunch、exit
一个简单 scout 通过bin/fm-spawn.sh --harness agy在同一个隔离实验室会话中端到端跑通:
- spawn:
spawned agy-e2e1 harness=agy kind=scout,treehouse 供应的 worktree、--model gemini-3.8-flash-low、--effort low全部记入任务元数据。worker 写入其 worktree 文件,并向其位于 worktree 之外的状态文件追加done: agy e2e turn complete——证明 prompt 处理、工具执行、工作区外文件访问、以及新完成事件四件事同时成立。 - steer(持久定向):
bin/fm-send.sh消息落入任务收件箱,worker 把 steered 行追加到两个文件,收件箱记录移到handled/。 - relaunch(同副本重启):
bin/fm-control.sh relaunch --note在相同的 worktree、模型、力度上原地替换 worker;替换者核验先前两行内容完好并追加relaunched: done。 - exit:
bin/fm-control.sh exit停止 worker,注册表返回agent_not_found,pane 保留为 worktree 中的孤立 shell,所有工作完好。
值得强调的边界声明:没有自动配额故障转移被测试或被声称——上述每次交接都是显式的受监督 relaunch。
11. 仍未证明的事项
验证记录诚实列出了知识边界,本文照录:
- 未认证失败模式从未被观测到:此宿主上的 agy 以登录态运行,因此任何认证提示都是"大声失败的凭证阻塞器",而不是可处理的对话框。
- 无斜杠技能调用形式被验证:技能调用保持自然语言形态。
--continue与--conversation恢复从未被演练:恢复走的是"从磁盘上的 brief 确定性 relaunch"路线。- 没有任何 primary 或 secondmate 行为被构建或测试,也不声称存在。
12. 刷新这份记录:升级后必跑的验证套件
进程名、标记集合、信任对话框文本、忙碌/中断渲染文本全部是厂商控制的表面,spawn 闸门与忙碌回退逐字匹配它们。因此任何 agy 升级后都应运行可移植套件与现场守卫:
bin/fm-test-run.sh tests/fm-agy-harness.test.sh FM_AGY_SIGNALS_LIVE=1 bin/fm-test-run.sh tests/fm-agy-signals-live-e2e.test.sh第一条是可移植的单元/集成套件(无现场依赖),第二条是开启FM_AGY_SIGNALS_LIVE=1的现场端到端守卫,专门验证真实 agy 二进制下的信号链路(对应 tests/fm-agy-signals-live-e2e.test.sh)。
13. 小结:一份可复用的"无标记 TUI 后端"托管范式
agy 适配器验证记录的价值远超 agy 本身:它示范了一套在"无身份标记、无 hook 表面、有文件夹信任对话框、忙碌页脚渲染延迟"的多重不利条件下托管外部 CLI 的完整方法论——用锚定进程名做检测,用启动前预注册消解交互对话框,用"先启动后确认"的轮询闸门把对话框应答与忙碌签名绑定为就绪证据,用渲染尾部钉住的状态行做忙碌信号且对缺失显式报告 unknown。配合 docs/architecture.md 与 docs/agent-control.md 阅读,可以看清它在 firstmate 整体 agent 编排架构中的位置:agy 是纯 crewmate/scout 适配器之一,与 muse、rovo、devin 同属"按需雇佣、无人值守、可监督可回收"的那一类工人。
【免费下载链接】firstmate
Talk to one agent. Ship with a crew.
相关推荐
firstmate 集成 Antigravity CLI(agy)适配器完全指南:信任预注册、忙态判定与 Crewmate 调度
firstmate 集成 Antigravity CLI(agy)适配器完全指南:信任预注册、忙态判定与 Crewmate 调度 本文以 firstmate 仓
Warp 支持 Antigravity CLI Agent(agy):CLI Agent 检测、命令分类与品牌注册的完整实现解析
Warp 支持 Antigravity CLI Agent(agy):CLI Agent 检测、命令分类与品牌注册的完整实现解析 本篇技术指南以 specs/G
桌面应用开发者工具人工智能AI 应用AI Agent代码智能体Firstmate 的 Cursor Agent CLI 适配器:验证事实、进程身份、忙碌状态与 Primary 监督集成指南
Firstmate 的 Cursor Agent CLI 适配器:验证事实、进程身份、忙碌状态与 Primary 监督集成指南 导读 :本文是 Firstmat
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考