Skip to content

feat(bin): add verified Antigravity worker adapter - #3008

Closed
brybrydataguy wants to merge 28 commits into
kunchenguid:mainfrom
brybrydataguy:fm/firstmate-agy-adapter-verification-v1-isolated-recovery
Closed

brybrydataguy wants to merge 28 commits into
kunchenguid:mainfrom
brybrydataguy:fm/firstmate-agy-adapter-verification-v1-isolated-recovery

Conversation

@brybrydataguy

Copy link
Copy Markdown

Intent

Add verified Antigravity CLI (agy) worker adapter support to Firstmate with Gemini 3.7 Flash High default

What Changed

  • Add verified agy crewmate and scout launches with harness detection, isolated busy-state hooks, a gemini-3.7-flash-high default, and model/effort validation while rejecting unsupported secondmate use.
  • Introduce generation-bound worker process scopes with PID-namespace or process-group containment so lifecycle operations can prove identity, quiesce descendants, preserve endpoints, and refuse unsafe agy transitions.
  • Document the adapter lifecycle and add regression coverage for launch, backend integration, relaunch, teardown, stale-lock recovery, and endpoint identity.

Risk Assessment

✅ Low: Captain, the latest fix preserves and validates the endpoint identity across the active-to-empty transition, covers both scope states without allowing foreign holders, and satisfies the agy adapter and Gemini 3.7 Flash High default intent.

Testing

The focused adapter regression passed, Firstmate spawned agy with Gemini 3.7 Flash High as its persisted default, and the real authenticated agy 1.1.19 CLI successfully completed a request using that exact model.

Evidence: Firstmate agy spawn transcript

Firstmate reported a successful agy worker spawn, persisted model=gemini-3.7-flash-high, and generated the autonomous interactive launch command.

warning: /var/folders/13/t392f7894bjb4vdz0l4s8ydm0000gn/T//fm-agy-harness.XT6Exg/default-model/home/data/agy-default-model-x1/brief.md records no delivery contract line (scaffolded before ship briefs recorded one); launching on the explicit --mode no-mistakes - confirm its definition of done matches
spawned agy-default-model-x1 harness=agy kind=ship mode=no-mistakes yolo=off window=firstmate:fm-agy-default-model-x1 worktree=/var/folders/13/t392f7894bjb4vdz0l4s8ydm0000gn/T//fm-agy-harness.XT6Exg/default-model/wt
ok - fm-spawn: agy defaults to gemini-3.7-flash-high and uses --prompt-interactive

Task metadata:
harness=agy
kind=ship
model=gemini-3.7-flash-high
process_scope_token=s1787626252.87732.30692

Captured worker launch:
'/Users/bryansmith/.no-mistakes/worktrees/19a7e0a5ff0c/01M0V72W1H48V8GWNSDZ39TF2Z/bin/fm-task-process-launch.sh' '/private/var/folders/13/t392f7894bjb4vdz0l4s8ydm0000gn/T/fm-agy-harness.XT6Exg/default-model/home/state/agy-default-model-x1.process-scope' 's1787626252.87732.30692' 's1787626252.87732.30692' 'env -u CURSOR_AGENT -u CURSOR_INVOKED_AS env -u CLAUDECODE -u PI_CODING_AGENT -u GROK_AGENT -u FM_PI_HARNESS '\''/var/folders/13/t392f7894bjb4vdz0l4s8ydm0000gn/T//fm-agy-harness.XT6Exg/default-model/fake/fakebin/agy'\'' --dangerously-skip-permissions --model '\''gemini-3.7-flash-high'\'' --prompt-interactive "$('\''/Users/bryansmith/.no-mistakes/worktrees/19a7e0a5ff0c/01M0V72W1H48V8GWNSDZ39TF2Z/bin/fm-operational-input.sh'\'' encode launch-brief < '\''/var/folders/13/t392f7894bjb4vdz0l4s8ydm0000gn/T//fm-agy-harness.XT6Exg/default-model/home/data/agy-default-model-x1/brief.md'\'')"' '/private/var/folders/13/t392f7894bjb4vdz0l4s8ydm0000gn/T/fm-agy-harness.XT6Exg/default-model/fake/fakebin/unshare'
Evidence: Real Antigravity model smoke

The real agy 1.1.19 catalog listed Gemini 3.7 Flash High, then the model returned the expected smoke response.

$ agy --version
1.1.19

$ agy models | select gemini-3.7-flash-high
gemini-3.7-flash-high	Gemini 3.7 Flash (High)

$ agy --dangerously-skip-permissions --model gemini-3.7-flash-high --effort high --print <smoke prompt>
AGY_GEMINI_3_7_FLASH_HIGH_OK

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

🔧 **Review** - 2 issues found → auto-fixed (5) ✅
  • 🚨 bin/fm-task-process-launch.sh:47 - scope_agent relies solely on BASHPID, but Bash 3.2, explicitly supported by the macOS CI lane, does not define it. Under stock /usr/bin/env bash, the background function exits before executing agy, so every scoped ship or scout launch fails after task metadata may already be published. Launch the child through a mechanism that obtains its real PID without BASHPID.
  • 🚨 bin/fm-teardown.sh:2860 - Required contract: verified agy worker support. This closes the agy endpoint before the strict lsof proof and non-force worktree safety check at lines 2865 and 2888. A dirty or unlanded task, or a host without lsof, therefore loses its agent and terminal before teardown refuses; relaunch then rejects the missing endpoint. The test at tests/fm-teardown.test.sh:1560 deliberately forbids an earlier git safety read, so changing this challenges deliberate behavior. Recommend a read-only preliminary safety and lsof availability pass before quiescence, while retaining the post-quiescence checks. This adds duplicate preflight work but keeps refused tasks operable; declining can strand them.

🔧 Fix: Preserve agy workers across launches and teardown refusals
1 warning still open:

  • ⚠️ bin/fm-teardown.sh:2868 - The established teardown path proves and removes stale Git locks, but this new agy preflight exits on TEARDOWN_WORKTREE_SAFETY_LOCK_BLOCKED before reaching that recovery. If git status needs an index refresh while an old, unheld index.lock remains, every retry refuses at this branch. Choose between safe automatic stale-lock recovery before quiescence or explicit manual containment instead of promising that retry will work.

🔧 Fix: Recover stale agy teardown locks before worker quiescence
1 warning still open:

  • ⚠️ bin/fm-teardown.sh:1461 - The durable stale-lock fix still fails with an actual live agy worker. This pre-quiescence cleanup passes $WT to fm_lock_is_provably_stale, which treats any process holding the worktree directory open as a live lock holder; the agy scope anchor is launched from $WT and remains there until quiescence at line 2878. Consequently, a stale index.lock plus a live worker refuses on every retry. The new regression test uses mark_agy_scope_empty, so it misses this path. I recommend an identity-bound pre-quiescence proof that excludes the known scope's expected cwd while still rejecting a true lock holder; otherwise document the preserved-worker refusal as manual containment.

🔧 Fix: Recover stale locks around verified live agy scopes
1 warning still open:

  • ⚠️ bin/fm-teardown.sh:1290 - The durable recovery still fails on the normal terminal-backed path. The endpoint shell enters $WT before launching agy and remains there waiting as the process-scope anchor's parent, but it is outside the recorded scope. Therefore lsof -Fp &#34;$WT&#34; returns that shell PID and this scope-only check rejects it on every retry. The regression starts the sleeper directly and fakes lsof to return only its PID, omitting the real endpoint shell. Another fix round must either identity-bind the verified endpoint shell as an allowed holder or adopt a lock-file-specific proof; the smaller alternative is explicit manual containment. I recommend resolving this at the endpoint or shared lock-ownership boundary, not adding another test-only exemption.

🔧 Fix: Bind agy lock recovery to verified endpoints
1 warning still open:

  • ⚠️ bin/fm-task-process-launch.sh:137 - The durable recovery still misses an already-exited agy worker: this transition replaces the active record without retaining its verified endpoint PID and identity. The treehouse endpoint shell remains in $WT, so a stale index.lock makes safety preflight see that shell via lsof, while worktree_lock_has_only_expected_scope_holders rejects the now-empty scope on every retry. Decide whether empty scopes should retain and validate the endpoint binding at this shared state transition, which I recommend, or explicitly require manual lock removal or --force after worker exit.

🔧 Fix: Preserve endpoint identity across empty process scopes
✅ Re-checked - no issues remain.

✅ **Test** - passed

✅ No issues found.

  • tests/fm-agy-harness.test.sh
  • Focused re-run of test_agy_default_model_and_launch_template with spawn output, task metadata, and generated launch command captured
  • agy --version
  • agy models
  • agy --dangerously-skip-permissions --model gemini-3.7-flash-high --effort high --print 'Do not call tools or inspect files. Reply with exactly: AGY_GEMINI_3_7_FLASH_HIGH_OK'
⚠️ **Document** - 4 errors
  • 🚨 tests/fm-harness-liveness-drift-live-e2e.test.sh:103 - The opt-in real-harness drift guard says every verified adapter belongs in its loop, but it omits agy. The documented Antigravity liveness claim therefore cannot be refreshed, leaving only stubbed coverage for this vendor-controlled surface. Add agy while retaining absent-harness and version reporting.

🔧 Fix: Align agy adapter documentation
4 errors still open:

  • 🚨 tests/fm-harness-liveness-drift-live-e2e.test.sh:103 - The real-harness liveness guard promises to check every installed verified adapter but still omits agy, so Antigravity process-identity drift cannot refresh its documented liveness evidence. Add agy while retaining absent-harness, version, and non-vacuity reporting.
  • 🚨 tests/fm-composer-matrix-live-e2e.test.sh:120 - The live composer guard promises coverage for every installed verified harness but omits agy. Add it so Antigravity's vendor-rendered empty composer is checked after upgrades.
  • 🚨 tests/fm-send-inbox-doorbell-live-e2e.test.sh:189 - The live steering guard promises coverage for every installed verified harness, but agy has neither a launch recipe nor default-loop entry. Add both so real Antigravity workers must receive, act on, and acknowledge durable inbox steers.
  • 🚨 docs/verification/supervision.md:184 - The verification record claims real Antigravity PreInvocation, Stop, and rendered delivery-footer observations, but its linked test only exercises fixtures and no opt-in real-agy refresh command exists. Add a live guard with version, absence, and non-vacuity reporting, then record its command and bounded output here.

🔧 Fix: Consolidate agy documentation ownership
4 errors still open:

  • 🚨 tests/fm-harness-liveness-drift-live-e2e.test.sh:103 - The real-harness liveness guard still omits agy, so Antigravity process-identity drift cannot refresh its documented evidence. Add agy while retaining absence, version, and non-vacuity reporting.
  • 🚨 tests/fm-composer-matrix-live-e2e.test.sh:120 - The live composer guard still omits agy. Add it so Antigravity's vendor-rendered empty composer is checked after upgrades.
  • 🚨 tests/fm-send-inbox-doorbell-live-e2e.test.sh:189 - The live steering guard still lacks an agy launch recipe and default-loop entry. Add both so real Antigravity workers must receive, act on, and acknowledge inbox steers.
  • 🚨 docs/verification/supervision.md:184 - The verification record claims real Antigravity lifecycle observations, but only fixture coverage exists. Add an opt-in real-agy guard with version, absence, and non-vacuity reporting, then record its command and bounded output.

🔧 Fix: Correct Antigravity verification evidence
4 errors still open:

  • 🚨 tests/fm-harness-liveness-drift-live-e2e.test.sh:103 - The real-harness liveness guard still omits agy, so real Antigravity process-identity evidence cannot be refreshed. Add agy while retaining absence, version, and non-vacuity reporting.
  • 🚨 tests/fm-composer-matrix-live-e2e.test.sh:120 - The live composer guard still omits agy. Add it so Antigravity's vendor-rendered empty composer is checked after upgrades.
  • 🚨 tests/fm-send-inbox-doorbell-live-e2e.test.sh:189 - The live doorbell guard still lacks an agy launch recipe and default-loop entry. Add both so real Antigravity workers must receive, act on, and acknowledge inbox steers.
  • 🚨 docs/verification/supervision.md:201 - Only synthetic fixture coverage exists for agy's lifecycle hooks and delivery footer. Add an opt-in real-agy guard with version, absence, and non-vacuity reporting, then record its bounded output.

🔧 Fix: Document Antigravity verification limits
4 errors still open:

  • 🚨 tests/fm-harness-liveness-drift-live-e2e.test.sh:103 - The real-harness liveness guard still omits agy, so Antigravity process-identity evidence cannot be refreshed. Add agy while retaining absence, version, and non-vacuity reporting.
  • 🚨 tests/fm-composer-matrix-live-e2e.test.sh:120 - The live composer guard still omits agy. Add it so Antigravity's vendor-rendered empty composer is checked after upgrades.
  • 🚨 tests/fm-send-inbox-doorbell-live-e2e.test.sh:189 - The live doorbell guard still lacks an agy launch recipe and default-loop entry. Add both so real Antigravity workers must receive, act on, and acknowledge inbox steers.
  • 🚨 docs/verification/supervision.md:201 - Only synthetic fixture coverage exists for agy's lifecycle hooks and delivery footer. Add an opt-in real-agy guard with version, absence, and non-vacuity reporting, then record its bounded output.
⚠️ **Lint** - 1 warning
  • ⚠️ linter found issues (exit code 1)
✅ **Push** - passed

✅ No issues found.

@greptile-apps

greptile-apps Bot commented Aug 25, 2026 •

Copy link
Copy Markdown

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Reviews (4): Last reviewed commit: "no-mistakes: apply CI fixes" | Re-trigger Greptile

Comment thread bin/fm-harness.sh
Comment thread bin/fm-control-lib.sh Outdated
Comment thread bin/fm-harness.sh Outdated
@devin-ai-integration

Copy link
Copy Markdown

Closed as superseded — this work already landed on main via #4200.

— Kun's Firstmate

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant