Add Antigravity (agy) provider via an ACP compatibility bridge#4497
Add Antigravity (agy) provider via an ACP compatibility bridge#4497agentool wants to merge 9 commits into
Conversation
Antigravity ships no native agent protocol: `agy agent stdio` is not a
thing, and the bundled `language_server` speaks Codeium gRPC rather than
ACP. So this adds a bridge that presents the ACP surface
`AcpSessionRuntime` needs and runs each turn through the documented
non-interactive `agy --print`.
The bridge ships as hidden subcommands of the server binary (`t3 agy-acp`,
`t3 agy-hook`) so it always versions with the server and needs no separate
artifact.
A live event stream is reconstructed from two documented Antigravity
sources that correlate on step index (a hook's `stepIdx` is the transcript
record's `step_index`):
- Hooks (PreToolUse/PostToolUse/Stop) supply tool name, arguments and
completion status. They are registered through a throwaway `--add-dir`
workspace, so nothing is written into the user's repository. Both the
session cwd and that hook workspace are passed, because `--add-dir`
replaces the workspace rather than extending cwd -- passing only the
hook dir hides the project from the agent.
- The trajectory transcript supplies assistant text and real tool output
as the turn runs. Its format is undocumented, so every parse path
degrades to emitting nothing rather than failing a turn.
File contents for an edit diff are captured inside the hook process. The
bridge cannot read them when it drains hook output: both hooks for a fast
edit land within a single poll interval, by which point "before" would
read back as "after".
Any `agy` subcommand spawned for a probe sets `stdin: "ignore"`. `agy`
starts a language server and emits nothing while stdin stays open, so the
default "pipe" hangs it and model discovery returns empty.
Known constraints, all inherent to print mode and documented in AGENTS.md:
tools auto-approve (`--dangerously-skip-permissions`) so no approval flow
is possible; no image attachments; no session modes; the model binds at
spawn, so `sessionModelSwitch` is "unsupported".
The three ProviderRegistry fixtures assert an exact provider list or that
only the subject provider probes, so they gain the new driver.
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
- session/load no longer treats a UUID-shaped session id as an Antigravity conversation id. Bridge session ids are random UUIDs themselves, so the fallback could not tell them apart and resumed a conversation that never existed whenever the session map was missing. The map is now the only authority; an unknown id starts fresh. - The transcript file is pinned for the turn. transcript.jsonl appearing after streaming began from transcript_full.jsonl used to switch files while keeping the old byte offset, misaligning reads or re-emitting records already streamed. - Tool call bookkeeping survives PostToolUse. Hooks are drained before the transcript, so for a fast tool both arrive in one poll; deleting the step on completion dropped the real output permanently, with no fallback since post hooks carry no tool body. Records are now marked completed and the exit sweep only fails the ones still open. - session/cancel only records a cancellation for the turn actually running. Cancels bypass the request queue, so one arriving after a turn finished stayed set and made the next successful turn report stopReason cancelled. - The adapter validates the prompt before emitting turn.started, so an attachment-only or whitespace-only prompt no longer leaves a turn that never completes in the UI.
| ).pipe( | ||
| Effect.catch((cause) => | ||
| Effect.logError("Failed to process Antigravity runtime notification.", { cause }), | ||
| ), | ||
| Effect.forkChild, | ||
| ); |
There was a problem hiding this comment.
🟠 High Layers/AntigravityAdapter.ts:448
The notification drain fiber is forked with Effect.forkChild, which attaches it to the Effect.scoped startSession workflow's scope. When startSession returns, that scope closes and immediately interrupts the notification fiber — even though sessionScope was created separately and transferred into ctx. As a result, the live session stops forwarding all subsequent ACP content, tool, and plan events. Fork the drain into sessionScope via Effect.forkIn(ctx.scope) instead of Effect.forkChild.
| ).pipe( | |
| Effect.catch((cause) => | |
| Effect.logError("Failed to process Antigravity runtime notification.", { cause }), | |
| ), | |
| Effect.forkChild, | |
| ); | |
| ).pipe( | |
| Effect.catch((cause) => | |
| Effect.logError("Failed to process Antigravity runtime notification.", { cause }), | |
| ), | |
| Effect.forkIn(ctx.scope), | |
| ); |
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/provider/Layers/AntigravityAdapter.ts around lines 448-453:
The notification drain fiber is forked with `Effect.forkChild`, which attaches it to the `Effect.scoped` `startSession` workflow's scope. When `startSession` returns, that scope closes and immediately interrupts the notification fiber — even though `sessionScope` was created separately and transferred into `ctx`. As a result, the live session stops forwarding all subsequent ACP content, tool, and plan events. Fork the drain into `sessionScope` via `Effect.forkIn(ctx.scope)` instead of `Effect.forkChild`.
There was a problem hiding this comment.
No change — this matches GrokAdapter, and live streaming is verified working end to end.
There was a problem hiding this comment.
Sorry, I'm unable to act on this request because you do not have permissions within this repository.
ApprovabilityVerdict: Needs human review 4 blocking correctness issues found. This PR adds a substantial new provider integration (~4700 lines) with complex session management, process coordination, and tool approval workflows. Multiple high-severity bugs have been identified in review comments affecting cancellation behavior, event forwarding, and resource cleanup that require resolution before merging. You can customize Macroscope's approvability policy. Learn more. |
|
Bro ... Read contributors md :/ |
Round-two fixes from automated review: - Attachments are staged into a per-turn temp directory instead of adding the attachment store to the workspace, which would have handed an auto-approving agent read access to every thread's uploads. - Resumed conversations no longer replay history. One conversation keeps a single append-only transcript and reading starts at byte 0, so the first batch is trimmed to what follows the last USER_INPUT record — verified against real two-turn transcripts. - The session map is written through a temp file and renamed. It is now the sole resume authority, and a torn write read back as empty JSON would silently start a fresh conversation. - Non-string values in that map are discarded rather than cast, and an unhandled handler failure now answers the request instead of leaving the client blocked forever. - Turn setup releases its claim and removes its temp directories if it throws, and a failed turn clears the public session's active turn id. - File URIs go through pathToFileURL, which escapes characters that would otherwise truncate the path on the way back. Two limitations removed after checking the CLI rather than assuming: - Model switching works. `--model` composes with `--conversation`: a resumed conversation answers on the new model with its history intact, so the bridge takes `session/set_model` and the capability is now "in-session". - Attachments work. `agy --print` has no attachment flag, so files travel as `resource_link` blocks and the bridge names the staged paths in the prompt.
Print mode cannot prompt, so `agy` has to run with permissions skipped.
That does not mean tools must be auto-approved: a PreToolUse hook returning
`{"decision":"deny"}` genuinely blocks the call and Antigravity reports the
reason back to the model. Verified against the CLI before building on it.
The hook process becomes the gate. It writes its event, then blocks polling
for a decision file. The bridge — which is the ACP agent — issues
`session/request_permission` to T3 Code, and writes the answer out when the
user replies. The adapter registers the matching callback and resolves it
from `respondToRequest`, the same path the other ACP providers use.
Fails closed everywhere it can: a cancelled prompt, an unknown option, a
malformed reply, a lost bridge, or a timeout all deny rather than allow.
Antigravity's own hook timeout is set above the bridge's wait so the deny
lands rather than the CLI abandoning the hook first.
Off by default via `requireToolApproval`, because every approval blocks the
turn until a human answers.
Verified end to end against the real CLI through the built bundle: asked to
overwrite a file, the bridge raised two permission requests (run_command,
then write_to_file), both were rejected, and the file was unchanged.
More findings from automated review: - Tool output no longer arrives after the call is completed. Hooks and the transcript are drained in one pass, so for a fast tool the completion and its output were emitted back to back; AcpSessionRuntime drops tool state on completion, so the output resurfaced as a second, never-completed item. Terminal updates are now held until that step's transcript record has been streamed, or until the final drain if none arrives. - Session-to-conversation mappings are one file per session. A shared map meant a read-modify-write, so two bridge processes finishing turns at once would each rebuild it from a stale snapshot and the later write would drop the other's entry, losing a thread's history. Atomic rename alone did not fix that; independent files do not contend at all. - Terminal turn events are published from exactly one place. The old success path tested `promptsInFlight === 1` and then yielded before publishing, so a steer arriving in that window could make two prompts each believe they owned the turn and emit a completion. Decrement and the last-prompt test are now a single synchronous step. - A model switch is applied before `turn.started`, so the announced model is the one the turn runs on rather than the previous one. - Non-`file:` resource links are rendered into the prompt for Antigravity's fetch tool instead of being dropped, and an attachment that cannot be staged now fails the turn — silently dropping it would run the turn against a prompt the user did not write.
Final review round, mostly against the approval gate added in the previous commit: - The gate no longer fails open. A hook that could not parse its payload or write its event file fell through to the observation-only response, which answers "allow" — so a full disk or an unwritable directory ran the tool with nobody having approved it. Every PreToolUse failure now denies; only a validated decision allows. - Cancelling stops prompts that have not started yet. Turns are serialized, so a steer queued behind a long turn used to begin executing tools after the user pressed Stop. Cancels are counted per session and each prompt records the count when it is accepted, which invalidates queued prompts without reviving the stale-cancel bug a plain flag caused. - Approval requests carry a deadline and are settled on interrupt, so a client that never answers cannot pin an entry for the life of the process, and a cancelled turn releases the hook waiting behind it. - No approval is opened during the final drain: the child has already exited, so nothing is waiting on the answer. - A tool whose transcript output arrived before its PostToolUse hook is completed immediately rather than at end of turn. The transcript is read once by byte offset, so that record never comes round again. - A failed model switch clears the active turn instead of leaving one advertised to listSessions and the reaper; staging cleans up copied uploads if a later copy fails; the approvals map is registered only after startup succeeds. Re-verified end to end through the built bundle: reject path blocks the tool and leaves the file untouched; approve path runs it and emits in_progress -> content -> completed.
…e bugs `requireToolApproval` now defaults to on. `agy` runs with permissions skipped either way, so the hook is the only thing between the model and a tool; a gate that has to be discovered protects nobody. Fixes from the latest review round: - "Allow for this session" no longer denies the tool. The bridge advertised only allow_once/reject_once, so the client mapped that choice to no option id, the reply read as cancelled, and the gate denied — the button did the opposite of what it said. An allow_always option is offered and honoured for the rest of the session. - `requireToolApproval` was missing from AntigravitySettingsPatch, so the setting was stripped on every settings update and could never be changed from its default. - `requiresNewThreadForModelChange` was still true, which kept the UI from offering the in-session model switch the adapter had just gained. - A resumed transcript whose current-turn USER_INPUT had not been written yet could replay the previous turn's trailing records as live output. Those lines are now retained and re-examined instead of emitted. - Transcript bytes are decoded through a streaming decoder. A write landing mid-multibyte-character used to be replaced with U+FFFD and skipped, corrupting non-ASCII assistant text and tool output. - Two concurrent sendTurns could both read promptsInFlight as zero and open rival turns; the id is now minted before the read so claiming is atomic. - Turn settlement catches defects, not only typed failures, and cancelling an already-settled approval no longer aborts teardown. Verified end to end through the built bundle: reject blocks the tool and leaves the file untouched; allow and allow-for-session both run it and emit in_progress -> content -> completed.
- A cancel now stops prompts already accepted but still queued upstream. The bridge's own generation check was too late: the ACP runtime serializes prompts behind a semaphore, so a steer could still be waiting there when Stop was pressed, reach the bridge after the cancel, capture the post-cancel state and run anyway. The adapter records a cancel epoch when it accepts a prompt and rechecks it immediately before submitting. - `turn.started` is claimed from shared per-turn state rather than from "am I a steer". A steer assumed the prompt it folded into had already announced the turn, which is false if that prompt failed during preflight — it would then emit content and a completion for a turn nobody started. - The adapter's approval handler races its own deadline and cleans up in an `ensuring`. The bridge forgetting a timed-out request only freed its side; this one stayed blocked on the deferred with its UI prompt open, and those accumulated across turns. An unanswered request resolves to cancel, which denies. - `approvalsByThread` is registered after the session, so an interrupted startup cannot leave an entry with no context to clean it up, and `createHookWorkspace` removes its directory if setup throws — the caller never receives the path and cannot do it. Re-verified end to end: reject blocks the tool, allow runs it with in_progress -> content -> completed.
- The approval gate answers on every gating path. A PreToolUse payload carrying no `toolCall` still fell through to the observation-only response, which allows — so a change in Antigravity's payload shape would have run tools unapproved. Missing or unidentifiable tool calls now deny. - Resumed conversations use a byte baseline taken before `agy` starts instead of inferring the turn boundary from the last USER_INPUT record. The transcript always holds earlier USER_INPUT records, so a poll landing before the new one was written treated a previous turn's output as live. The conversation's log directory is derivable from its id, so the boundary can be measured rather than guessed; the marker heuristic remains as a fallback when the file cannot be read. - The turn id is bound in the same synchronous step as the prompt claim. A concurrent call could otherwise observe promptsInFlight > 0 with no active id yet and open a rival turn. - Turn settlement reads shared per-turn state rather than the settling call's own flag, and a turn is marked started only after the event is actually published. Otherwise a steer that became the last outstanding prompt could drop the completion, or emit one for a turn nobody saw start. Known and unfixed, both structural: a steer can still pass the adapter's cancel check and then wait on the ACP runtime's prompt semaphore, reaching the bridge after a cancel; and an interrupted startup between scope transfer and the first published event leaves the session registered. Both live in shared runtime code this provider only borrows.
| try { | ||
| const stats = NodeFS.statSync(transcriptPath); | ||
| if (stats.size > input.transcriptOffset.value) { | ||
| const fd = NodeFS.openSync(transcriptPath, "r"); |
There was a problem hiding this comment.
🟡 Medium antigravity/agyBridge.ts:865
drain advances transcriptOffset.value to stats.size and decodes the entire buffer regardless of how many bytes NodeFS.readSync actually returned. On filesystems where readSync returns fewer than length bytes, the unread tail of the buffer is zero-filled and decoded as transcript content, while the real unread bytes are permanently skipped — corrupting or silently losing transcript records and tool output. Advance the offset and decode only the actual bytesRead, looping until the requested range is fully consumed.
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/provider/acp/antigravity/agyBridge.ts around line 865:
`drain` advances `transcriptOffset.value` to `stats.size` and decodes the entire buffer regardless of how many bytes `NodeFS.readSync` actually returned. On filesystems where `readSync` returns fewer than `length` bytes, the unread tail of the buffer is zero-filled and decoded as transcript content, while the real unread bytes are permanently skipped — corrupting or silently losing transcript records and tool output. Advance the offset and decode only the actual `bytesRead`, looping until the requested range is fully consumed.
| }).pipe(Effect.scoped), | ||
| ); | ||
|
|
||
| const sendTurn: AntigravityAdapterShape["sendTurn"] = (input) => |
There was a problem hiding this comment.
🟡 Medium Layers/AntigravityAdapter.ts:656
sendTurn calls requireSession up front but then yields during attachment resolution and model switching without holding the per-thread lock or rechecking ctx.stopped. A concurrent stopSession can delete the session and close ctx.scope during that window, yet sendTurn continues to publish turn.started and call ctx.acp.prompt on the closed runtime, emitting turn events after session.exited. Serialize sendTurn under withThreadLock so teardown cannot run concurrently, or recheck ctx.stopped before publishing and submitting.
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/provider/Layers/AntigravityAdapter.ts around line 656:
`sendTurn` calls `requireSession` up front but then yields during attachment resolution and model switching without holding the per-thread lock or rechecking `ctx.stopped`. A concurrent `stopSession` can delete the session and close `ctx.scope` during that window, yet `sendTurn` continues to publish `turn.started` and call `ctx.acp.prompt` on the closed runtime, emitting turn events after `session.exited`. Serialize `sendTurn` under `withThreadLock` so teardown cannot run concurrently, or recheck `ctx.stopped` before publishing and submitting.
| // stdin closed: no approval can still be answered, so unblock the hooks | ||
| // waiting on them (they fail closed) rather than letting them time out. | ||
| failPendingOutbound("T3 Code disconnected before approving this tool call"); | ||
| await queue; |
There was a problem hiding this comment.
🟠 High antigravity/agyBridge.ts:1333
On stdin disconnect, runAgyBridge calls await queue before killing activeChild, so the bridge blocks until the in-flight session/prompt resolves — which only happens when agy exits (default two-hour timeout). A disconnected client leaves the bridge and child process alive for hours. Kill activeChild before await queue so disconnect terminates the active turn.
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/provider/acp/antigravity/agyBridge.ts around line 1333:
On stdin disconnect, `runAgyBridge` calls `await queue` before killing `activeChild`, so the bridge blocks until the in-flight `session/prompt` resolves — which only happens when `agy` exits (default two-hour timeout). A disconnected client leaves the bridge and child process alive for hours. Kill `activeChild` before `await queue` so disconnect terminates the active turn.
| * output as live. Returns 0 when the file cannot be measured, which falls back | ||
| * to the marker heuristic rather than skipping the turn's own output. | ||
| */ | ||
| function transcriptBaseline(conversationId: string | undefined): number { |
There was a problem hiding this comment.
🟡 Medium antigravity/agyBridge.ts:110
transcriptBaseline measures whichever transcript file exists first — usually transcript_full.jsonl — but resolveTranscriptPath can later pin the turn to the condensed transcript.jsonl once it appears. The byte offset captured from one file is then used to seek into a different file. If that offset equals or exceeds the condensed file's size, drain reads zero bytes from the transcript and the resumed turn's tool-call output and assistant text are skipped entirely. Consider measuring the baseline against the same file path that resolveTranscriptPath will select, or deferring the baseline read until the pinned path is known.
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/provider/acp/antigravity/agyBridge.ts around line 110:
`transcriptBaseline` measures whichever transcript file exists first — usually `transcript_full.jsonl` — but `resolveTranscriptPath` can later pin the turn to the condensed `transcript.jsonl` once it appears. The byte offset captured from one file is then used to seek into a different file. If that offset equals or exceeds the condensed file's size, `drain` reads zero bytes from the transcript and the resumed turn's tool-call output and assistant text are skipped entirely. Consider measuring the baseline against the same file path that `resolveTranscriptPath` will select, or deferring the baseline read until the pinned path is known.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit d87551f. Configure here.
| threadId: input.threadId, | ||
| turnId, | ||
| resumeCursor: ctx.session.resumeCursor, | ||
| }; |
There was a problem hiding this comment.
Cancel misses steers on semaphore
High Severity
cancelEpoch is rechecked only before calling acp.prompt, but prompt serialization waits on a semaphore inside that call. A steer that already passed the check and is queued there survives Stop: acp.cancel only interrupts the active fiber, and the bridge records cancel generation at enqueue time—after the cancel—so the steer still spawns agy.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit d87551f. Configure here.


Adds
antigravityas a provider driver alongside Codex, Claude, Cursor, Grok and OpenCode.Up front, re: CONTRIBUTING: this is large (+3442) and unsolicited, and I did not open an issue first. Opening it anyway as a working reference rather than a request for your time — if the answer is no, close it and it costs you nothing. Notes on scope and on splitting it are at the bottom.
Why this needs a bridge rather than another ACP driver
Antigravity ships no native agent protocol. Verified against
agy1.1.7:agy agent stdio→unexpected arguments: [stdio](Grok's entrypoint isgrok agent stdio)--acpflag; the binary carriesjsonrpc2and MCP, but no ACP methodsAntigravity.app/Contents/Resources/bin/language_serverspeaks Codeium gRPC (exa.language_server_pb), not ACPSo
provider/acp/antigravity/agyBridge.tspresents the ACP surfaceAcpSessionRuntimealready expects, and runs each turn through the documented non-interactiveagy --print. It ships as hidden subcommands of the server binary (t3 agy-acp,t3 agy-hook) so it versions with the server and adds no build artifact.How the event stream is reconstructed
Two documented Antigravity sources correlate on step index — a hook's
stepIdxis the transcript record'sstep_index:toolSummary)PreToolUsehookstep_indexPostToolUsehookPLANNER_RESPONSErecords as they landconversationIdfor resumeNeither source alone is sufficient: hooks never carry tool output, the transcript never carries tool arguments.
Three things that cost real debugging time
--add-dirreplaces the workspace, it does not extend cwd. Hooks are registered via a throwaway--add-dirworkspace so nothing is written into the user's repo — but passing only that dir makes the project invisible to the agent. Both the session cwd and the hook workspace are passed.Edit diffs must be captured inside the hook process. Both hooks for a fast edit land within one 50ms poll, so reading the file while draining hook output makes "before" read back as "after". The hook brackets the tool call and is the only place that sees true pre-edit state.
Probes must set
stdin: "ignore".agystarts a language server and emits nothing while stdin stays open;ChildProcessdefaultsstdinto"pipe", which hangs it. Presented asinstalled: true, models: 0whileagy modelsworked by hand.Known constraints
All inherent to print mode, documented in
AGENTS.md:--dangerously-skip-permissions); no approval flow is possiblesessionModelSwitchis"unsupported"The trajectory JSONL format is undocumented. Every parse path degrades to emitting nothing rather than failing a turn, so an
agyrelease that changes it costs observability, not correctness.UI surface
No new components. The provider renders through the existing rows:
PROVIDER_OPTIONS,PROVIDER_ICON_BY_PROVIDER, andPROVIDER_CLIENT_DEFINITIONS, reusing theAntigravityIconalready inIcons.tsxfor the editor integration, with anExperimentalbadge in the same slot Cursor and Grok use forEarly Access. CONTRIBUTING asks for before/after images on UI changes — I don't have a clean way to attach them here; the visible delta is one additional provider row.Verification
agyEvents,agyTranscript,AntigravityAcpSupportpnpm buildclean; bridge bundles intodist/bin.mjsand all three entrypoints work off the built binarystatus: ready | version: 1.1.7 | models: 11agy: tool calls, real tool output, a file edit with diff,stopReason: end_turn, file on disk actually changedThree
ProviderRegistryfixtures assert an exact provider list or that only the subject provider probes, so they gain the new driver.On size
Most of the diff is
AntigravityAdapter.ts(~690 lines), which follows the existing convention of one standalone adapter per provider (Cursor 1.2k, Grok 1.5k, Claude 3.9k) over the shared ACP helpers. I deliberately did not refactor a shared adapter core out ofGrokAdapter, since that would mean touching a working provider to land a new one.Happy to split this into (1) contracts + bridge + tests and (2) driver + UI wiring, or to drop the text-generation backend, if either would make it reviewable. Equally happy for you to take the bridge approach and reimplement it your way — the
--add-dir, hook-timing andstdinfindings above are the parts that were expensive to discover.Note
High Risk
Large new provider surface (~3.4k LOC) spanning tool approval gating, external CLI execution with
--dangerously-skip-permissions, and complex cancel/steer concurrency; mistakes could allow unapproved tools or strand turns in the UI.Overview
Introduces
antigravityas a built-in provider because the Antigravity CLI has no native agent protocol. Sessions talk to a bundled ACP bridge (t3 agy-acpover stdio) that runs each turn withagy --print, whilet3 agy-hookobserves tool lifecycle via Antigravity hooks registered from a throwaway workspace (session cwd plus hook dir —--add-dirreplaces rather than extends).Live streaming is rebuilt by correlating hook
stepIdxwith transcriptstep_index: hooks announce tools and completion;transcript.jsonlsupplies assistant text and real tool output. The adapter wires permissions throughPreToolUsewhenrequireToolApprovalis on (fail-closed), sends attachments asresource_link+ staged paths, supports in-session model switches on the next spawn, and rejects rollback when the trajectory cannot be truncated server-side.Contracts and UI add
AntigravitySettings, model defaults/aliases, registry/tests updates, settings/picker icons,attachmentFileUrl, andAntigravityTextGenerationfor git/thread helpers.AGENTS.mddocuments bridge constraints (stdinignoreon probes, print-mode limits).Reviewed by Cursor Bugbot for commit d87551f. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Add Antigravity (agy) provider via an ACP compatibility bridge
antigravityprovider driver that integrates with theagyCLI via an ACP (Agent Communication Protocol) compatibility bridge, runningagyin print mode as a subprocessAntigravityAdapter.tswith full session lifecycle: start/stop, per-turn prompt sending with attachments, tool approval mediation with an 11-minute timeout, interruption, per-turn model switching, and event streaming via PubSubAntigravityAcpSupport.tswhich spawns the ACP bridge as a server sub-process, passing configuration and per-turn parameters (model, effort, timeout, approval gating) via environment variablesagy-acpandagy-hookhidden CLI subcommands to the server binary to handle ACP bridge and hook lifecycle eventsagy's transcript JSONL file and processing hook callbacks, translating them into ACP-shaped updatesagyCLI being installed and accessible; missing binary degrades to a warning status with no models availableMacroscope summarized d87551f.