Skip to content

feat: add built-in Antigravity CLI (agy) agent plugin - #405

Open
djbclark wants to merge 1 commit into
subsy:mainfrom
djbclark:feat-antigravity-plugin
Open

feat: add built-in Antigravity CLI (agy) agent plugin#405
djbclark wants to merge 1 commit into
subsy:mainfrom
djbclark:feat-antigravity-plugin

Conversation

@djbclark

@djbclark djbclark commented Aug 2, 2026

Copy link
Copy Markdown

Summary

Adds a built-in agent plugin for Google's Antigravity CLI (agy) — the multi-model (Gemini/Claude/GPT-OSS) CLI under a Google AI Pro subscription.

Not a fix to the existing gemini plugin — that one wraps Google's separate standalone gemini-cli, which as of 2026-08-02 returns IneligibleTierError for individual-account OAuth ("migrate to the Antigravity suite of products"). Antigravity is the actual working path to these models now.

  • src/plugins/agents/builtin/antigravity.ts — modeled on pi.ts/gemini.ts, stdin prompt input, --output-format stream-json event parsing, --dangerously-skip-permissions
  • Registered in builtin/index.ts, AGENT_ID_MAP in setup/skill-installer.ts
  • Docs (website/content/docs/plugins/agents/antigravity.mdx) + nav entry
  • 44 unit tests

Built as a proper built-in (relative imports within the package) rather than an external user plugin — an earlier attempt at the latter hit a real bug where importing the published ralph-tui package from outside triggers a duplicate @opentui/core environment-variable registration crash.

Test plan

  • bun run typecheck — clean
  • bun run build — clean
  • bun test src/plugins/agents/builtin/antigravity.test.ts — 44 pass
  • bun run dist/cli.js doctor --agent antigravity — HEALTHY (real preflight round-trip, not mocked)

Summary by CodeRabbit

  • New Features

    • Added support for the Antigravity (agy) CLI agent.
    • Added model selection, sandbox configuration, setup validation, streaming output, tool events, and error handling.
    • Registered Antigravity for built-in use and skill installation.
  • Documentation

    • Added setup, usage, configuration, troubleshooting, and model selection guidance.
    • Added Antigravity to the agent documentation navigation.
  • Tests

    • Added comprehensive coverage for configuration, validation, output parsing, arguments, and error scenarios.

Google's standalone gemini-cli is ineligible for individual OAuth; agy is
the working path to Gemini/Claude/GPT-OSS. Register as a proper built-in
(relative imports) to avoid OTUI env-var double-registration from
external ralph-tui package imports.

Co-authored-by: Cursor <cursoragent@cursor.com>
@vercel

vercel Bot commented Aug 2, 2026

Copy link
Copy Markdown

@djbclark is attempting to deploy a commit to the plgeek Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a complete Antigravity (agy) CLI agent plugin with JSONL event parsing, configuration, execution, registration, tests, skill mapping, and documentation.

Changes

Antigravity agent

Layer / File(s) Summary
Stream-JSON event parsing
src/plugins/agents/builtin/antigravity.ts, src/plugins/agents/builtin/antigravity.test.ts
Parses Antigravity JSONL messages into text, tool, and error events. Tests cover invalid, ignored, incomplete, and multi-line output.
Plugin configuration and CLI detection
src/plugins/agents/builtin/antigravity.ts, src/plugins/agents/builtin/antigravity.test.ts
Adds metadata, model setup, sandbox requirements, validation, CLI detection, version probing, timeout handling, and preflight guidance.
Command execution and streaming
src/plugins/agents/builtin/antigravity.ts, src/plugins/agents/builtin/antigravity.test.ts
Builds command arguments, sends prompts through stdin, buffers JSONL chunks, and forwards parsed events through callbacks.
Registration and documentation
src/plugins/agents/builtin/index.ts, src/setup/skill-installer.ts, website/content/docs/plugins/agents/antigravity.mdx, website/lib/navigation.ts
Registers and exports the plugin, adds the skill mapping, and adds documentation and navigation.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant AntigravityAgentPlugin
  participant agy CLI
  participant JSONL parser
  participant Execution callbacks
  AntigravityAgentPlugin->>agy CLI: Send arguments and prompt through stdin
  agy CLI-->>AntigravityAgentPlugin: Stream JSONL output
  AntigravityAgentPlugin->>JSONL parser: Parse complete lines
  JSONL parser-->>Execution callbacks: Emit text, tool, and error events
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: adding a built-in Antigravity CLI (agy) agent plugin.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install failed. For unrecoverable errors, disable the tool in CodeRabbit configuration.


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (6)
src/plugins/agents/builtin/antigravity.test.ts (2)

160-168: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Call the protected members directly; the unknown casts are unnecessary.

TestableAntigravityPlugin extends AntigravityAgentPlugin, so it can access the protected buildArgs and getStdinInput members without a cast. Removing the casts keeps the tests type-checked against the real signatures.

♻️ Proposed refactor
   class TestableAntigravityPlugin extends AntigravityAgentPlugin {
     testBuildArgs(prompt: string): string[] {
-      return (this as unknown as { buildArgs: (p: string) => string[] }).buildArgs(prompt);
+      return this.buildArgs(prompt);
     }
 
     testGetStdinInput(prompt: string): string | undefined {
-      return (this as unknown as { getStdinInput: (p: string) => string | undefined }).getStdinInput(prompt);
+      return this.getStdinInput(prompt);
     }
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/plugins/agents/builtin/antigravity.test.ts` around lines 160 - 168,
Update TestableAntigravityPlugin.testBuildArgs and testGetStdinInput to call the
inherited protected buildArgs and getStdinInput members directly, removing the
unknown casts and duplicate method type annotations while preserving their
existing return behavior.

373-405: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add coverage for the chunked stdout buffering in execute.

The tests cover the parser but not the buffering in antigravity.ts Lines 349-433. That code holds a partial JSONL line across onStdout chunks and flushes it in onEnd. It is the most defect-prone logic in this PR. Add a test that feeds one JSON object split across two chunks and asserts that exactly one text event reaches onStdout.

Do you want me to generate this test?

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/plugins/agents/builtin/antigravity.test.ts` around lines 373 - 405, Add a
test covering execute’s stdout buffering in antigravity.ts: feed one JSONL
object split across two onStdout chunks, then trigger onEnd and assert exactly
one text event is delivered to onStdout. Keep the existing parser tests
unchanged and verify the reconstructed event content.
src/plugins/agents/builtin/antigravity.ts (4)

447-457: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Simplify validateModel; all three branches return null.

The checks at Line 448 and Lines 453-455 are dead code. The model === undefined comparison is also unreachable because the parameter type is string. Keep the explanatory comment and return null directly.

♻️ Proposed refactor
   override validateModel(model: string): string | null {
-    if (model === '' || model === undefined) {
-      return null;
-    }
     // Accept any non-empty model string — `agy models` list drifts over time.
     // Known IDs are offered in setup; custom/newer IDs should still work.
-    if (model.trim().length === 0) {
-      return null;
-    }
+    void model;
     return null;
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/plugins/agents/builtin/antigravity.ts` around lines 447 - 457, In
Antigravity’s validateModel method, remove the redundant empty/undefined and
whitespace checks, preserve the explanatory comment about accepting any
non-empty or custom model string, and return null directly.

349-433: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract the shared JSONL emit logic from flushBuffer and the onStdout wrapper.

Lines 354-377 and Lines 398-426 implement the same two steps: forward raw JSON objects to onJsonlMessage, then parse the text into display events and forward them to onStdoutSegments and onStdout. The buffering logic is correct, so this is a maintainability change only. A single helper keeps the two paths from drifting.

♻️ Proposed refactor
+    const emitJsonlMessages = (lines: string[]) => {
+      if (!options?.onJsonlMessage) return;
+      for (const line of lines) {
+        const trimmed = line.trim();
+        if (!trimmed.startsWith('{')) continue;
+        try {
+          options.onJsonlMessage(JSON.parse(trimmed));
+        } catch {
+          // Not valid JSON, skip
+        }
+      }
+    };
+
+    const emitDisplayEvents = (text: string) => {
+      const events = parseAntigravityOutputToEvents(text);
+      if (events.length === 0) return;
+      if (options?.onStdoutSegments) {
+        const segments = processAgentEventsToSegments(events);
+        if (segments.length > 0) options.onStdoutSegments(segments);
+      }
+      if (options?.onStdout) {
+        const formatted = processAgentEvents(events);
+        if (formatted.length > 0) options.onStdout(formatted);
+      }
+    };
+
     const flushBuffer = () => {
       if (!jsonlBuffer) return;
       const trimmed = jsonlBuffer.trim();
+      jsonlBuffer = '';
       if (!trimmed) return;
-      ...
+      emitJsonlMessages([trimmed]);
+      emitDisplayEvents(trimmed);
     };

Then call emitJsonlMessages(lines) and emitDisplayEvents(completeData) inside the onStdout wrapper.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/plugins/agents/builtin/antigravity.ts` around lines 349 - 433, Extract
the duplicated JSONL forwarding and display-event forwarding from flushBuffer
and the parsedOptions.onStdout wrapper into shared local helpers, such as
emitJsonlMessages and emitDisplayEvents. Replace both inline implementations
with calls to those helpers, while preserving the existing buffering behavior
and callback ordering.

224-262: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Declare timer before safeResolve to remove the temporal-dead-zone dependency.

safeResolve reads timer at Line 227, but timer is declared at Line 259. The current code is safe because every call site runs asynchronously. A future synchronous call would throw a ReferenceError. Declare the handle first with let timer: ReturnType<typeof setTimeout> | undefined; and assign it later.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/plugins/agents/builtin/antigravity.ts` around lines 224 - 262, Declare
the timer handle before the safeResolve callback in the version-check flow,
using an optional ReturnType<typeof setTimeout> variable, then assign it when
creating the timeout. Update safeResolve to safely clear the possibly undefined
timer while preserving the existing settlement behavior.

71-94: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Extract tool_info once to remove the duplicated type guard.

The same tool_info object check runs twice, at Lines 75-79 and Lines 82-86. A single narrowed local makes the branch easier to read. Behavior stays the same.

♻️ Proposed refactor
       } else if (stepType === 'tool') {
         if (state === 'ACTIVE') {
-          const toolName =
-            (typeof step.tool_name === 'string' && step.tool_name) ||
-            (step.tool_info != null &&
-            typeof step.tool_info === 'object' &&
-            !Array.isArray(step.tool_info) &&
-            typeof (step.tool_info as Record<string, unknown>).name === 'string'
-              ? ((step.tool_info as Record<string, unknown>).name as string)
-              : 'unknown');
-          let toolInput: Record<string, unknown> | undefined;
-          if (
-            step.tool_info != null &&
-            typeof step.tool_info === 'object' &&
-            !Array.isArray(step.tool_info)
-          ) {
-            const info = step.tool_info as Record<string, unknown>;
-            if (info.parameters != null && typeof info.parameters === 'object' && !Array.isArray(info.parameters)) {
-              toolInput = info.parameters as Record<string, unknown>;
-            } else {
-              toolInput = info;
-            }
-          }
+          const info =
+            step.tool_info != null &&
+            typeof step.tool_info === 'object' &&
+            !Array.isArray(step.tool_info)
+              ? (step.tool_info as Record<string, unknown>)
+              : undefined;
+          const toolName =
+            (typeof step.tool_name === 'string' && step.tool_name) ||
+            (typeof info?.name === 'string' ? info.name : 'unknown');
+          let toolInput: Record<string, unknown> | undefined;
+          if (info) {
+            toolInput =
+              info.parameters != null &&
+              typeof info.parameters === 'object' &&
+              !Array.isArray(info.parameters)
+                ? (info.parameters as Record<string, unknown>)
+                : info;
+          }
           events.push({ type: 'tool_use', name: toolName, input: toolInput });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/plugins/agents/builtin/antigravity.ts` around lines 71 - 94, Refactor the
ACTIVE tool handling in the step-processing branch to narrow and store
step.tool_info once in a local variable, then reuse that narrowed object for
both toolName extraction and toolInput construction. Remove the duplicated
object/array type guards while preserving the existing fallback names and
parameter-selection behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@website/content/docs/plugins/agents/antigravity.mdx`:
- Line 122: Update website/content/docs/plugins/agents/antigravity.mdx at lines
122-122 and 138-138: remove the claim that --print requires a prompt argument,
and replace the prohibition with the actual Ralph TUI plugin behavior, including
its specific reason for omitting --print if intentional.
- Line 23: Update the authentication guidance at
website/content/docs/plugins/agents/antigravity.mdx lines 23-23 to instruct
users to run agy interactively and complete browser-based Google Sign-In,
removing the oauth_creds.json requirement. Update the troubleshooting step at
website/content/docs/plugins/agents/antigravity.mdx lines 154-154 to remove
credential-directory checks; retain ~/.gemini references only for plugin
configuration or skill paths.

---

Nitpick comments:
In `@src/plugins/agents/builtin/antigravity.test.ts`:
- Around line 160-168: Update TestableAntigravityPlugin.testBuildArgs and
testGetStdinInput to call the inherited protected buildArgs and getStdinInput
members directly, removing the unknown casts and duplicate method type
annotations while preserving their existing return behavior.
- Around line 373-405: Add a test covering execute’s stdout buffering in
antigravity.ts: feed one JSONL object split across two onStdout chunks, then
trigger onEnd and assert exactly one text event is delivered to onStdout. Keep
the existing parser tests unchanged and verify the reconstructed event content.

In `@src/plugins/agents/builtin/antigravity.ts`:
- Around line 447-457: In Antigravity’s validateModel method, remove the
redundant empty/undefined and whitespace checks, preserve the explanatory
comment about accepting any non-empty or custom model string, and return null
directly.
- Around line 349-433: Extract the duplicated JSONL forwarding and display-event
forwarding from flushBuffer and the parsedOptions.onStdout wrapper into shared
local helpers, such as emitJsonlMessages and emitDisplayEvents. Replace both
inline implementations with calls to those helpers, while preserving the
existing buffering behavior and callback ordering.
- Around line 224-262: Declare the timer handle before the safeResolve callback
in the version-check flow, using an optional ReturnType<typeof setTimeout>
variable, then assign it when creating the timeout. Update safeResolve to safely
clear the possibly undefined timer while preserving the existing settlement
behavior.
- Around line 71-94: Refactor the ACTIVE tool handling in the step-processing
branch to narrow and store step.tool_info once in a local variable, then reuse
that narrowed object for both toolName extraction and toolInput construction.
Remove the duplicated object/array type guards while preserving the existing
fallback names and parameter-selection behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 0cdba8c8-9081-4e62-94c5-9d7a0e052c95

📥 Commits

Reviewing files that changed from the base of the PR and between 8191b80 and 716df24.

📒 Files selected for processing (6)
  • src/plugins/agents/builtin/antigravity.test.ts
  • src/plugins/agents/builtin/antigravity.ts
  • src/plugins/agents/builtin/index.ts
  • src/setup/skill-installer.ts
  • website/content/docs/plugins/agents/antigravity.mdx
  • website/lib/navigation.ts

agy models
```

Authenticate with your Google account so credentials exist under `~/.gemini` (for example `oauth_creds.json`).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Correct the authentication guidance.

agy uses the operating-system keyring and falls back to browser-based Google Sign-In. It does not require an oauth_creds.json file under ~/.gemini. Tell users to run agy interactively and complete sign-in. Keep ~/.gemini references only for plugin configuration or skill paths. (antigravity.google)

  • website/content/docs/plugins/agents/antigravity.mdx#L23-L23: replace the credential-file requirement.
  • website/content/docs/plugins/agents/antigravity.mdx#L154-L154: replace the credential-directory troubleshooting step.
📍 Affects 1 file
  • website/content/docs/plugins/agents/antigravity.mdx#L23-L23 (this comment)
  • website/content/docs/plugins/agents/antigravity.mdx#L154-L154
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@website/content/docs/plugins/agents/antigravity.mdx` at line 23, Update the
authentication guidance at website/content/docs/plugins/agents/antigravity.mdx
lines 23-23 to instruct users to run agy interactively and complete
browser-based Google Sign-In, removing the oauth_creds.json requirement. Update
the troubleshooting step at website/content/docs/plugins/agents/antigravity.mdx
lines 154-154 to remove credential-directory checks; retain ~/.gemini references
only for plugin configuration or skill paths.

When Ralph TUI executes a task with Antigravity:

1. **Build command**: `agy --output-format stream-json [--dangerously-skip-permissions] [--model …]`
2. **Pass prompt via stdin**: Avoids shell escaping; `--print` is omitted because that flag requires a prompt argument

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Remove the stale --print rationale.

Current AGY releases support headless --print / -p runs and explicitly handle authentication when stdin contains a piped prompt. Do not state that these flags cannot be used with stdin because they require a prompt argument. If Ralph TUI intentionally omits the flag, document the plugin-specific reason instead. (antigravity.google)

  • website/content/docs/plugins/agents/antigravity.mdx#L122-L122: remove the claim that --print requires a prompt argument.
  • website/content/docs/plugins/agents/antigravity.mdx#L138-L138: replace the prohibition with the actual plugin behavior.
📍 Affects 1 file
  • website/content/docs/plugins/agents/antigravity.mdx#L122-L122 (this comment)
  • website/content/docs/plugins/agents/antigravity.mdx#L138-L138
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@website/content/docs/plugins/agents/antigravity.mdx` at line 122, Update
website/content/docs/plugins/agents/antigravity.mdx at lines 122-122 and
138-138: remove the claim that --print requires a prompt argument, and replace
the prohibition with the actual Ralph TUI plugin behavior, including its
specific reason for omitting --print if intentional.

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