Skip to content

feat(desktop): add Antigravity CLI (agy) as a first-class agent - #5772

Open
thebrownproject wants to merge 3 commits into
ParadevAI:mainfrom
thebrownproject:feat/antigravity-cli-hook
Open

thebrownproject wants to merge 3 commits into
ParadevAI:mainfrom
thebrownproject:feat/antigravity-cli-hook

Conversation

@thebrownproject

@thebrownproject thebrownproject commented Jul 19, 2026 •

Copy link
Copy Markdown
Contributor

Why

Google has deprecated the Gemini CLI and is pointing users at the Antigravity CLI. The individual-account client is already rejected at sign-in:

This client is no longer supported for Gemini Code Assist for individuals. To continue using Gemini, please migrate to the Antigravity suite of products.

Homebrew's gemini-cli formula is marked deprecated with brew install --cask antigravity-cli as the replacement, and disables on 2026-12-18.

This adds Antigravity as its own builtin terminal agent so Superset's lifecycle notifications work with it.

The existing gemini entry is left untouched. Enterprise Code Assist users can still run the Gemini CLI until Google pulls it, so this is purely additive — no preset migration, nothing breaks for existing users.

Two things that differ from the other agent integrations

1. The agent id is agy, not antigravity. SUPERSET_MANAGED_BINARIES derives the shell shim name directly from the agent id (shell-wrappers.ts), so the id has to match the binary Antigravity actually installs. Registering it as antigravity would generate a shim named antigravity while the wrapper file was written as agy, and the two would never line up — the agent would launch unwrapped and no hook would ever fire.

The alternative is adding a binaryName field to DesktopAgentSetupTarget and mapping it in both prelude builders. Happy to switch to that if you'd rather keep ids human-readable — it's a small change, but it touches plumbing shared by all 11 agents, so I went with the id that needs no core changes.

2. The hook takes its event from argv. Antigravity's hook payload carries no event-name field — the common fields are conversationId / workspacePaths / transcriptPath / artifactDirectoryPath / modelName only (camelCase, protojson). Every other agent's hook derives the event from stdin; this one can't, so hooks.json passes the Superset event as $1.

Config location

Hook config goes to ~/.gemini/config/hooks.json — Antigravity's global customization root, shared with Antigravity 2.0 and the IDE — not the ~/.gemini/settings.json the Gemini CLI used. Antigravity namespaces hooks by name and merges every named block for an event, so Superset owns a single "superset" key and leaves user- and plugin-defined hooks untouched. That makes the merge considerably simpler than the Gemini per-event reconciliation.

Event mapping

Antigravity event Superset event Why
PreInvocation Start Fires before each model call
PostToolUse Start Keeps the terminal marked busy across long tool loops
Stop Stop Fires when the execution loop terminates

PreToolUse is deliberately not registered. Its contract requires a decision field (allow / deny / ask / force_ask), and emitting an empty object there risks gating the user's own tool calls. There's a test asserting we never register it.

Antigravity runs hooks synchronously and blocks the agent loop on them, so the hook prints its JSON result before doing any network work, and every event we register treats {} as a safe no-op (PreInvocation treats injectSteps as optional, PostToolUse expects exactly {}, and Stop only blocks termination when decision is "continue").

Testing

  • bun run typecheck — 35/35 tasks
  • bun test apps/desktop/src/main/lib/agent-setup/ — 79 pass
  • bun test packages/shared/src — 704 pass
  • bun run lint — exit 0

New tests cover the wrapper's agent-id stamping, the ~/.gemini/config path, the argv event contract for all three registered events, the PreToolUse exclusion, idempotency, foreign-hook preservation, and recovery from an unparseable existing file. The Antigravity template is also added to the shared "dispatches to v2 first, falls back to v1" contract test.

Not included

  • Marketing compatibility surfaces and apps/mobile/store.config.json — happy to add if you want them in this PR.
  • Not added to DEFAULT_V2_TERMINAL_PRESET_IDS, matching how gemini is treated. Seeding a preset for a CLI the user hasn't installed shows a broken-looking entry.
  • No AGENT_MODEL_SUPPORT entry. Antigravity exposes --model, but the model names are display strings (e.g. "Gemini 3.5 Flash (Low)") resolved per-account via agy models, so a static catalog would go stale. Worth a follow-up if you want model selection in the picker.

The icon is the official Antigravity mark.


Open in Stage

Summary by cubic

Add Antigravity CLI (agy) as a first-class terminal agent so Superset can track lifecycle events for Google’s replacement to the deprecated Gemini CLI. The existing gemini agent remains unchanged.

  • New Features

    • Added agy agent with a managed wrapper, preset, and icon.
    • Hook config at ~/.gemini/config/hooks.json under a dedicated key; preserves other user/plugin hooks.
    • Events passed via argv; maps PreInvocation/PostInvocation → Start, Stop → Stop; skips PreToolUse and PostToolUse (the latter can fire after Stop).
    • Wrapper id matches the binary name (agy); docs updated to list the Antigravity preset and note gemini is deprecated upstream.
  • Bug Fixes

    • Use PostInvocation (not PostToolUse) to prevent panes from getting stuck in a “working” state.
    • Skip writing hooks.json when the existing file is unparseable or not an object, avoiding clobbering other hooks.

Written for commit 2929c5b. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features
    • Added Antigravity (agy) as a built-in terminal agent with default presets, settings support, and a dedicated preset icon.
    • Introduced Antigravity setup for generating the wrapper, lifecycle hook script, and hooks configuration.
    • Added Antigravity to the terminal “quick-add” preset list and agent icon picker.
  • Bug Fixes
    • Preserves existing hook configuration and avoids clobbering hooks.json when it can’t be parsed.
  • Tests
    • Expanded coverage for wrapper behavior, hook event dispatching, hooks merging/idempotency, and template fallback.
  • Documentation
    • Updated terminal preset docs to include Antigravity and note Gemini CLI status.

Google deprecated the Gemini CLI (Homebrew disables the formula on
2026-12-18, and the individual-account client is already rejected at
sign-in) and points users at the Antigravity CLI. This registers
Antigravity as its own builtin terminal agent so Superset's lifecycle
notifications work with it. The existing gemini entry is left untouched:
enterprise Code Assist users can still run it until Google pulls it.

Two things differ from the other agent integrations:

- The agent id is `agy`, not `antigravity`. SUPERSET_MANAGED_BINARIES
  derives the shell shim name directly from the agent id, so the id has
  to match the binary that Antigravity actually installs.

- Antigravity's hook payload carries no event-name field (the common
  fields are conversationId/workspacePaths/transcriptPath/modelName), so
  hooks.json passes the Superset event as argv rather than the hook
  deriving it from stdin.

Hook config lives at ~/.gemini/config/hooks.json -- Antigravity's global
customization root -- not the ~/.gemini/settings.json the Gemini CLI
used. Hooks are namespaced by name, so we own a single "superset" key
and leave user- and plugin-defined hooks alone.

PreInvocation and PostToolUse map to Start, Stop maps to Stop.
PreToolUse is deliberately not registered: its contract requires a
`decision` field, and emitting an empty object risks gating the user's
own tool calls.
Also flag the gemini preset as deprecated upstream so users know why a
second Google agent is listed.
@ghost

ghost commented Jul 19, 2026 •

Copy link
Copy Markdown

Ready to review this PR? Stage has broken it down into 6 individual chapters for you:

Title
1 Define Antigravity agent and documentation
2 Add Antigravity icons and UI options
3 Implement Antigravity hook template
4 Implement agent wrapper and hook logic
5 Wire Antigravity into desktop setup lifecycle
6 Other changes
Open in Stage

Chapters generated by Stage for commit 2929c5b on Jul 19, 2026 8:30am UTC.

@coderabbitai

coderabbitai Bot commented Jul 19, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds the agy Antigravity terminal agent, including its builtin definition, icon, documentation, executable wrapper, lifecycle hook script, hooks.json integration, desktop setup wiring, and tests for generated artifacts and notification behavior.

Changes

Antigravity agent integration

Layer / File(s) Summary
Define the agy agent and presentation
packages/shared/src/builtin-terminal-agents.ts, packages/ui/src/assets/icons/preset-icons/index.ts, apps/desktop/.../agent-icon-options.ts, apps/docs/content/docs/terminal-presets.mdx
Adds the agy builtin agent, default preset inclusion, Antigravity icon mappings, settings icon option, and terminal preset documentation.
Implement Antigravity hook behavior
apps/desktop/src/main/lib/agent-setup/agent-wrappers-antigravity.ts, apps/desktop/src/main/lib/agent-setup/templates/antigravity-hook.template.sh
Generates the hook script and Superset hook configuration for supported Antigravity lifecycle events, including payload handling, host dispatch, and completion requests.
Manage wrapper and hooks.json artifacts
apps/desktop/src/main/lib/agent-setup/agent-wrappers-antigravity.ts, apps/desktop/src/main/lib/agent-setup/agent-wrappers.ts
Creates the executable agy wrapper and hook script, preserves unrelated hooks.json entries, and replaces the managed hook block with formatted JSON.
Wire setup actions and validate output
apps/desktop/src/main/lib/agent-setup/desktop-agent-capabilities.ts, apps/desktop/src/main/lib/agent-setup/desktop-agent-setup.ts, apps/desktop/src/main/lib/agent-setup/*test.ts
Registers Antigravity setup actions and target dispatch, and tests wrapper generation, hook configuration behavior, idempotence, invalid JSON handling, and notification fallback.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant AntigravityCLI
  participant HookScript
  participant Superset
  AntigravityCLI->>HookScript: Send event argv and JSON stdin
  HookScript->>Superset: POST lifecycle notification
  Superset-->>HookScript: Return hook response
  HookScript->>Superset: GET /hook/complete
Loading

Possibly related issues

  • superset-sh/superset#4986 — Directly covers the Antigravity built-in agent, wrapper, hooks, preset, and icon integration implemented here.

Possibly related PRs

  • superset-sh/superset#5552 — Wires another terminal agent through the same wrapper, hook, and desktop setup machinery.
  • superset-sh/superset#4703 — Updates the shared hook completion and notification fallback expectations exercised by the Antigravity template.
  • superset-sh/superset#5758 — Changes the notify-hook behavior and payload expectations used by the new Antigravity hook test coverage.

Suggested reviewers: kitenite

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
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.
Title check ✅ Passed The title is conventional, concise, and accurately summarizes the main change: adding Antigravity CLI as a first-class agent.
Description check ✅ Passed The description covers the why, implementation details, and testing, but it does not follow the template headings exactly and omits the checklist section.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@greptile-apps

greptile-apps Bot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds Antigravity CLI (agy) as a first-class builtin terminal agent, mirroring the existing Gemini integration while adapting for two key behavioral differences: the agent id must match the binary name (agy), and hook events are passed via argv rather than derived from the stdin payload.

  • Adds agent-wrappers-antigravity.ts with hook script, hooks.json merge (preserving foreign blocks under a namespaced \"superset\" key at ~/.gemini/config/hooks.json), and shell wrapper; the PreToolUse event is intentionally excluded since its contract requires a decision field.
  • Registers agy in DESKTOP_AGENT_SETUP_TARGETS with managedBinary: true and includeInDefaultTerminalPresets: true (consistent with gemini; neither appears in the separate DEFAULT_V2_TERMINAL_PRESET_IDS list).
  • Ships a comprehensive test suite covering event-argv contract, path targeting, idempotency, foreign-hook preservation, and corrupt-file recovery.

Confidence Score: 4/5

Safe to merge; the change is purely additive and follows the established agent-integration pattern throughout the codebase.

The integration is well-structured and the test coverage is thorough. The one open question is whether agy -p works correctly without --mode accept-edits in headless contexts — if the mode flag is required for unattended non-interactive runs this could silently stall, but it's easy to confirm and fix. Everything else — the hook merge logic, the argv event contract, the icon wiring, and the capability registration — is clean.

Pay extra attention to packages/shared/src/builtin-terminal-agents.ts (the nonInteractiveCommand flag question) and agent-wrappers-antigravity.ts (the TOCTOU note on the hooks.json merge path).

Important Files Changed

Filename Overview
apps/desktop/src/main/lib/agent-setup/agent-wrappers-antigravity.ts New integration module: writes the hook script, hooks.json block, and shell wrapper for the Antigravity CLI. Merge logic preserves foreign hook keys and handles corrupt JSON.
apps/desktop/src/main/lib/agent-setup/templates/antigravity-hook.template.sh Shell hook template that reads the Superset event from argv instead of stdin. Emits {} before network dispatch; follows the same v2-then-v1 fallback pattern as gemini/cursor/copilot hooks.
packages/shared/src/builtin-terminal-agents.ts Adds agy builtin agent with includeInDefaultTerminalPresets: true. nonInteractiveCommand omits --mode accept-edits, which may affect headless invocations.
apps/desktop/src/main/lib/agent-setup/desktop-agent-capabilities.ts Adds three new setup actions and an agy target with managedBinary: true. Wiring is correct and consistent with other managed-binary agents.
apps/desktop/src/main/lib/agent-setup/agent-wrappers.test.ts Adds comprehensive test suite covering agent-id stamping, config path, argv event contract, PreToolUse exclusion, idempotency, foreign-hook preservation, and corrupted-file recovery.
apps/desktop/src/main/lib/agent-setup/desktop-agent-setup.ts Registers the three Antigravity setup runners in the action dispatch table. Purely additive.
packages/ui/src/assets/icons/preset-icons/index.ts Adds antigravity.svg and maps it under the agy key in PRESET_ICONS.
apps/desktop/src/main/lib/agent-setup/notify-hook.test.ts Adds antigravity-hook.template.sh to the shared v2-first, v1-fallback contract test.
apps/desktop/src/renderer/routes/_authenticated/settings/agents/components/V2AgentsSettings/components/AgentIconPicker/agent-icon-options.ts Adds {id: 'agy', label: 'Antigravity'} to the icon picker options list.
apps/docs/content/docs/terminal-presets.mdx Documents agy preset and marks gemini as deprecated upstream.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant A as Antigravity CLI (agy)
    participant H as antigravity-hook.sh
    participant S as Superset (v2 host-service)
    participant S1 as Superset (v1 local)

    A->>H: "PreInvocation payload (stdin), argv=$1=Start"
    H->>H: "INPUT=$(cat) - read stdin"
    H-->>A: "printf '{}' (hook response, no-op)"
    H->>S: "POST SUPERSET_HOST_AGENT_HOOK_URL {Start}"
    alt v2 success (2xx)
        S-->>H: 200 OK
    else v2 fail / missing
        H->>S1: "GET /hook/complete?eventType=Start"
    end
    A->>H: "PostToolUse payload (stdin), argv=$1=Start"
    H->>H: "INPUT=$(cat)"
    H-->>A: "printf '{}' (expected exactly {})"
    H->>S: "POST {Start}"
    A->>H: "Stop payload (stdin), argv=$1=Stop"
    H->>H: "INPUT=$(cat)"
    H-->>A: "printf '{}' (decision omitted = no block)"
    H->>S: "POST {Stop}"
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant A as Antigravity CLI (agy)
    participant H as antigravity-hook.sh
    participant S as Superset (v2 host-service)
    participant S1 as Superset (v1 local)

    A->>H: "PreInvocation payload (stdin), argv=$1=Start"
    H->>H: "INPUT=$(cat) - read stdin"
    H-->>A: "printf '{}' (hook response, no-op)"
    H->>S: "POST SUPERSET_HOST_AGENT_HOOK_URL {Start}"
    alt v2 success (2xx)
        S-->>H: 200 OK
    else v2 fail / missing
        H->>S1: "GET /hook/complete?eventType=Start"
    end
    A->>H: "PostToolUse payload (stdin), argv=$1=Start"
    H->>H: "INPUT=$(cat)"
    H-->>A: "printf '{}' (expected exactly {})"
    H->>S: "POST {Start}"
    A->>H: "Stop payload (stdin), argv=$1=Stop"
    H->>H: "INPUT=$(cat)"
    H-->>A: "printf '{}' (decision omitted = no block)"
    H->>S: "POST {Stop}"
Loading
Prompt To Fix All With AI
Fix the following 3 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 3
packages/shared/src/builtin-terminal-agents.ts:109
The `nonInteractiveCommand` for `agy` omits `--mode accept-edits`, while both `command` and `promptCommand` include it. If Antigravity requires the mode flag to operate without a TTY (i.e., to suppress interactive prompts during headless runs), the current `agy -p` invocation may stall or error in non-interactive task mode. Gemini's equivalent is `gemini --skip-trust -p`, which also drops the approval flag — but it's worth confirming that `--mode accept-edits` is not required for `agy`'s `-p` path before shipping.

```suggestion
		nonInteractiveCommand: "agy --mode accept-edits -p",
```

### Issue 2 of 3
apps/desktop/src/main/lib/agent-setup/templates/antigravity-hook.template.sh:21-31
**`{}` is emitted after stdin is fully consumed, not before**

`INPUT=$(cat)` at line 21 blocks until Antigravity closes the hook's stdin writer. `printf '{}\n'` (line 31) only fires after that. The comment on line 27 — "Emit before dispatching" — refers to dispatching to Superset, not to providing the Antigravity response early. This ordering is intentional and matches the Gemini hook pattern exactly, so it's fine as long as Antigravity closes stdin before reading stdout. Worth clarifying the comment so future reviewers don't mistake it for an early-response guarantee.

### Issue 3 of 3
apps/desktop/src/main/lib/agent-setup/agent-wrappers-antigravity.ts:110-130
**`fs.readFileSync` inside the `try` block can throw independently of `JSON.parse`**

If `fs.existsSync` returns `true` but the file becomes unreadable between the check and `readFileSync` (e.g., a permission change or race with another writer), the `catch` block silently swallows the I/O error and proceeds with an empty `existing` object — wiping every foreign hook block previously written. This is a pre-existing pattern in the codebase, but it's more consequential here since `hooks.json` is shared with IDE and user-defined hooks.

Reviews (1): Last reviewed commit: "docs(terminal-presets): list the Antigra..." | Re-trigger Greptile

"Google's terminal agent harness for reasoning, editing, and running code from the terminal.",
command: "agy --mode accept-edits",
promptCommand: "agy --mode accept-edits",
nonInteractiveCommand: "agy -p",

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.

P2 The nonInteractiveCommand for agy omits --mode accept-edits, while both command and promptCommand include it. If Antigravity requires the mode flag to operate without a TTY (i.e., to suppress interactive prompts during headless runs), the current agy -p invocation may stall or error in non-interactive task mode. Gemini's equivalent is gemini --skip-trust -p, which also drops the approval flag — but it's worth confirming that --mode accept-edits is not required for agy's -p path before shipping.

Suggested change
nonInteractiveCommand: "agy -p",
nonInteractiveCommand: "agy --mode accept-edits -p",

Does agy -p behave correctly in headless/non-TTY mode without --mode accept-edits, or does the mode flag need to be present for non-interactive prompts to run unattended?

Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/shared/src/builtin-terminal-agents.ts
Line: 109

Comment:
The `nonInteractiveCommand` for `agy` omits `--mode accept-edits`, while both `command` and `promptCommand` include it. If Antigravity requires the mode flag to operate without a TTY (i.e., to suppress interactive prompts during headless runs), the current `agy -p` invocation may stall or error in non-interactive task mode. Gemini's equivalent is `gemini --skip-trust -p`, which also drops the approval flag — but it's worth confirming that `--mode accept-edits` is not required for `agy`'s `-p` path before shipping.

```suggestion
		nonInteractiveCommand: "agy --mode accept-edits -p",
```

 Does `agy -p` behave correctly in headless/non-TTY mode without `--mode accept-edits`, or does the mode flag need to be present for non-interactive prompts to run unattended?

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +21 to +31
INPUT=$(cat)

# Payload keys are camelCase (protojson). conversationId is Antigravity's
# session identifier.
HOOK_SESSION_ID=$(printf '%s' "$INPUT" | grep -oE '"conversationId"[[:space:]]*:[[:space:]]*"[^"]*"' | grep -oE '"[^"]*"$' | tr -d '"')

# Emit before dispatching. An empty object is the no-op result for every event
# we register: PreInvocation/PostInvocation treat injectSteps as optional,
# PostToolUse expects exactly {}, and Stop only blocks termination when
# decision is "continue".
printf '{}\n'

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.

P2 {} is emitted after stdin is fully consumed, not before

INPUT=$(cat) at line 21 blocks until Antigravity closes the hook's stdin writer. printf '{}\n' (line 31) only fires after that. The comment on line 27 — "Emit before dispatching" — refers to dispatching to Superset, not to providing the Antigravity response early. This ordering is intentional and matches the Gemini hook pattern exactly, so it's fine as long as Antigravity closes stdin before reading stdout. Worth clarifying the comment so future reviewers don't mistake it for an early-response guarantee.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src/main/lib/agent-setup/templates/antigravity-hook.template.sh
Line: 21-31

Comment:
**`{}` is emitted after stdin is fully consumed, not before**

`INPUT=$(cat)` at line 21 blocks until Antigravity closes the hook's stdin writer. `printf '{}\n'` (line 31) only fires after that. The comment on line 27 — "Emit before dispatching" — refers to dispatching to Superset, not to providing the Antigravity response early. This ordering is intentional and matches the Gemini hook pattern exactly, so it's fine as long as Antigravity closes stdin before reading stdout. Worth clarifying the comment so future reviewers don't mistake it for an early-response guarantee.

How can I resolve this? If you propose a fix, please make it concise.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment on lines +110 to +130
export function getAntigravityHooksJsonContent(hookScriptPath: string): string {
const globalPath = getAntigravityHooksJsonPath();

let existing: AntigravityHooksJson = {};
try {
if (fs.existsSync(globalPath)) {
const parsed: unknown = JSON.parse(fs.readFileSync(globalPath, "utf-8"));
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
existing = parsed as AntigravityHooksJson;
}
}
} catch {
console.warn(
"[agent-setup] Could not parse existing ~/.gemini/config/hooks.json, rewriting Superset block only",
);
}

existing[ANTIGRAVITY_HOOK_NAME] = buildSupersetHookBlock(hookScriptPath);

return JSON.stringify(existing, null, 2);
}

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.

P2 fs.readFileSync inside the try block can throw independently of JSON.parse

If fs.existsSync returns true but the file becomes unreadable between the check and readFileSync (e.g., a permission change or race with another writer), the catch block silently swallows the I/O error and proceeds with an empty existing object — wiping every foreign hook block previously written. This is a pre-existing pattern in the codebase, but it's more consequential here since hooks.json is shared with IDE and user-defined hooks.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src/main/lib/agent-setup/agent-wrappers-antigravity.ts
Line: 110-130

Comment:
**`fs.readFileSync` inside the `try` block can throw independently of `JSON.parse`**

If `fs.existsSync` returns `true` but the file becomes unreadable between the check and `readFileSync` (e.g., a permission change or race with another writer), the `catch` block silently swallows the I/O error and proceeds with an empty `existing` object — wiping every foreign hook block previously written. This is a pre-existing pattern in the codebase, but it's more consequential here since `hooks.json` is shared with IDE and user-defined hooks.

How can I resolve this? If you propose a fix, please make it concise.

…ites

Two defects found reviewing the preceding commit.

1. Register PostInvocation, not PostToolUse.

Antigravity dispatches a trailing PostToolUse for the final step roughly
a second AFTER the Stop hook on any turn that ends without a tool call.
Since PostToolUse mapped to Start, the last event Superset received for
such a turn was Start, and terminal status is last-write-wins with no
staleness gate on the Start branch -- so the pane stayed pinned to
"working" indefinitely after the agent had finished replying, with only
the manual clear-status escape hatch to recover.

Reproduced against agy 1.1.4 with a probe hook logging argv and epoch.
A no-tool turn emits:

  307.589 PreInvocation
  307.630 PostToolUse   stepIdx:1  toolCall:null
  309.117 PostInvocation
  309.157 Stop          terminationReason:NO_TOOL_CALL
  310.026 PostToolUse   stepIdx:3  toolCall:null   <- 0.87s after Stop

PostInvocation fires once per loop iteration and always precedes Stop, so
it serves the same "stay busy across long tool loops" purpose without the
trailing Start.

Two incidental corrections to the previous reasoning: matcher "*" matches
every step type rather than only tool calls (tool names are derived from
the step type with the CORTEX_STEP_TYPE_ prefix stripped), and those
trailing steps carry toolCall:null -- so PostToolUse was never really a
tool-loop keepalive to begin with.

2. Never rewrite a hooks.json we could not read.

getAntigravityHooksJsonContent seeded an empty object and fell through on
parse failure, so an unreadable or non-object hooks.json was replaced
wholesale by our block alone, discarding the user's and any plugin's
hooks. ~/.gemini/config/ is shared by the CLI, Antigravity 2.0 and the
IDE, so that took out every surface at once. It now returns null and the
writer skips, matching the readExistingClaudeSettings /
readExistingCodexHooks / readExistingDroidSettings contract the newer
sibling integrations already use.

The unparseable-file test asserted only that our own key existed, so it
passed either way; it now covers unparseable, top-level-array and null
files and asserts the file is left byte-identical.
@thebrownproject

Copy link
Copy Markdown
Contributor Author

Ran an adversarial review over this branch (5 reviewers by dimension, every finding handed to an independent agent tasked with refuting it). Two defects survived, both now fixed in 08d0772.

1. PostToolUse fires after Stop — this was a real bug in the original push, and it broke the entire point of the integration.

A verifier installed the exact hooks.json this PR generates and ran the real agy 1.1.4 with a probe logging argv + epoch. On any turn ending without a tool call:

307.589 PreInvocation
307.630 PostToolUse    stepIdx:1  toolCall:null
309.117 PostInvocation
309.157 Stop           terminationReason:NO_TOOL_CALL  fullyIdle:true
310.026 PostToolUse    stepIdx:3  toolCall:null   <-- 0.87s AFTER Stop

Since PostToolUse maps to Start, the last event Superset saw was Start. recordEvent is last-write-wins on lastEventType and deriveTerminalAgentStatus has no staleness gate on the Start branch, so the pane stayed pinned to "working" indefinitely after the agent finished replying — recoverable only via clearWorkspaceStatuses. Reproduced 4+ times, under an interactive pty as well as --print.

Two of my original assumptions were also just wrong: matcher: "*" matches every step type, not only tool calls (tool names are the step type minus the CORTEX_STEP_TYPE_ prefix, and the enum includes PLANNER_RESPONSE/FINISH), and those trailing steps carry toolCall: null. So PostToolUse was never the tool-loop keepalive I described it as.

Now registers PostInvocation, which the same traces show always precedes Stop and fires once per loop iteration — same intent, no trailing Start. There's a regression test asserting PostToolUse is never registered, with the reason.

Worth flagging for the other integrations: PostToolUse -> Start is shared with Claude/codex/opencode/droid/mastra via map-event-type.ts. Those agents don't emit a tool event after their Stop hook, so they're fine today — but the Start branch having no staleness gate means any agent that ever does will latch the same way.

2. Unreadable hooks.json was rewritten wholesale. The merge seeded {} and fell through on parse failure, so a truncated or hand-broken file got replaced by the Superset block alone, discarding user and plugin hooks. Since ~/.gemini/config/ is shared by the CLI, Antigravity 2.0 and the IDE, that hit every surface at once. Now returns null and the writer skips — matching the readExistingClaudeSettings / readExistingCodexHooks / readExistingDroidSettings contract the newer integrations already use; I'd picked up the older Cursor/Gemini/Mastra pattern by copying the wrong sibling.

The test for that path was also theatre — it asserted only that our own key existed, so it passed whether or not user hooks survived. It now covers unparseable, top-level-array and null files and asserts the file is left byte-identical.

Everything else checked out against the binary's embedded docs: the agy agent id, argv-passed events, the ~/.gemini/config/hooks.json path, and omitting PreToolUse.

typecheck 35/35, agent-setup tests 82 pass, lint exit 0.

@thebrownproject
thebrownproject force-pushed the feat/antigravity-cli-hook branch from 08d0772 to 2929c5b Compare July 19, 2026 08:30

@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: 1

🤖 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 `@packages/shared/src/builtin-terminal-agents.ts`:
- Around line 99-111: Remove includeInDefaultTerminalPresets from the
createBuiltinTerminalAgent registration for the agy Antigravity agent. Keep the
agent available without adding it to DEFAULT_TERMINAL_PRESET_AGENT_TYPES or
newly initialized users’ default terminal presets.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: cea7cd95-f36a-42f4-a1c2-1259e0be920d

📥 Commits

Reviewing files that changed from the base of the PR and between 08d0772 and 2929c5b.

⛔ Files ignored due to path filters (1)
  • packages/ui/src/assets/icons/preset-icons/antigravity.svg is excluded by !**/*.svg
📒 Files selected for processing (11)
  • apps/desktop/src/main/lib/agent-setup/agent-wrappers-antigravity.ts
  • apps/desktop/src/main/lib/agent-setup/agent-wrappers.test.ts
  • apps/desktop/src/main/lib/agent-setup/agent-wrappers.ts
  • apps/desktop/src/main/lib/agent-setup/desktop-agent-capabilities.ts
  • apps/desktop/src/main/lib/agent-setup/desktop-agent-setup.ts
  • apps/desktop/src/main/lib/agent-setup/notify-hook.test.ts
  • apps/desktop/src/main/lib/agent-setup/templates/antigravity-hook.template.sh
  • apps/desktop/src/renderer/routes/_authenticated/settings/agents/components/V2AgentsSettings/components/AgentIconPicker/agent-icon-options.ts
  • apps/docs/content/docs/terminal-presets.mdx
  • packages/shared/src/builtin-terminal-agents.ts
  • packages/ui/src/assets/icons/preset-icons/index.ts
🚧 Files skipped from review as they are similar to previous changes (8)
  • apps/desktop/src/renderer/routes/_authenticated/settings/agents/components/V2AgentsSettings/components/AgentIconPicker/agent-icon-options.ts
  • apps/desktop/src/main/lib/agent-setup/notify-hook.test.ts
  • apps/desktop/src/main/lib/agent-setup/desktop-agent-capabilities.ts
  • packages/ui/src/assets/icons/preset-icons/index.ts
  • apps/desktop/src/main/lib/agent-setup/agent-wrappers.ts
  • apps/desktop/src/main/lib/agent-setup/desktop-agent-setup.ts
  • apps/docs/content/docs/terminal-presets.mdx
  • apps/desktop/src/main/lib/agent-setup/agent-wrappers.test.ts

Comment on lines +99 to +111
createBuiltinTerminalAgent({
// Google's replacement for the deprecated Gemini CLI. The id matches the
// binary name (`agy`) because SUPERSET_MANAGED_BINARIES derives the shell
// shim name from the agent id.
id: "agy",
label: "Antigravity",
description:
"Google's terminal agent harness for reasoning, editing, and running code from the terminal.",
command: "agy --mode accept-edits",
promptCommand: "agy --mode accept-edits",
nonInteractiveCommand: "agy -p",
includeInDefaultTerminalPresets: true,
}),

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 | 🟠 Major | ⚡ Quick win

Do not add Antigravity to default terminal presets.

includeInDefaultTerminalPresets: true causes agy to flow into DEFAULT_TERMINAL_PRESET_AGENT_TYPES and be seeded into new users’ terminal presets, contradicting the PR objective that Antigravity should not be included by default.

Proposed fix
 		nonInteractiveCommand: "agy -p",
-		includeInDefaultTerminalPresets: true,
 	}),

Based on the PR objective and the downstream preset initialization contract, this flag must remain unset for agy.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
createBuiltinTerminalAgent({
// Google's replacement for the deprecated Gemini CLI. The id matches the
// binary name (`agy`) because SUPERSET_MANAGED_BINARIES derives the shell
// shim name from the agent id.
id: "agy",
label: "Antigravity",
description:
"Google's terminal agent harness for reasoning, editing, and running code from the terminal.",
command: "agy --mode accept-edits",
promptCommand: "agy --mode accept-edits",
nonInteractiveCommand: "agy -p",
includeInDefaultTerminalPresets: true,
}),
createBuiltinTerminalAgent({
// Google's replacement for the deprecated Gemini CLI. The id matches the
// binary name (`agy`) because SUPERSET_MANAGED_BINARIES derives the shell
// shim name from the agent id.
id: "agy",
label: "Antigravity",
description:
"Google's terminal agent harness for reasoning, editing, and running code from the terminal.",
command: "agy --mode accept-edits",
promptCommand: "agy --mode accept-edits",
nonInteractiveCommand: "agy -p",
}),
🤖 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 `@packages/shared/src/builtin-terminal-agents.ts` around lines 99 - 111, Remove
includeInDefaultTerminalPresets from the createBuiltinTerminalAgent registration
for the agy Antigravity agent. Keep the agent available without adding it to
DEFAULT_TERMINAL_PRESET_AGENT_TYPES or newly initialized users’ default terminal
presets.

Kitenite added a commit that referenced this pull request Aug 24, 2026
Adds Google's Antigravity CLI (`agy`) to BUILTIN_TERMINAL_AGENTS, with
the official mark as its preset icon, README row, docs bullet, and
marketing demo entry.

Rebased by hand from #5772 onto the current manifest shape. The agent id
is `agy` to match the binary. Prompt launches seed the interactive
session positionally, resume uses `--conversation <id>`, and `agy -p` is
the headless form.

The lifecycle-hook wrapper from #5772 (hooks.json under ~/.gemini/config)
targets the old desktop agent-setup location and is left for a follow-up
now that agent setup lives in packages/agent-setup; agy ships here as a
plain terminal agent like Pi / Cursor Agent.

Co-authored-by: Fraser Brown <173673575+thebrownproject@users.noreply.github.com>

Claude-Session: https://claude.ai/code/session_01DuAhw6Ao5Cru3acdkrzx9f
Kitenite added a commit that referenced this pull request Aug 24, 2026
Adds Google's Antigravity CLI (`agy`) to BUILTIN_TERMINAL_AGENTS, with
the official mark as its preset icon, README row, docs bullet, and
marketing demo entry.

Rebased by hand from #5772 onto the current manifest shape. The agent id
is `agy` to match the binary. Prompt launches seed the interactive
session positionally, resume uses `--conversation <id>`, and `agy -p` is
the headless form.

The lifecycle-hook wrapper from #5772 (hooks.json under ~/.gemini/config)
targets the old desktop agent-setup location and is left for a follow-up
now that agent setup lives in packages/agent-setup; agy ships here as a
plain terminal agent like Pi / Cursor Agent.

Co-authored-by: Fraser Brown <173673575+thebrownproject@users.noreply.github.com>

Claude-Session: https://claude.ai/code/session_01DuAhw6Ao5Cru3acdkrzx9f
Kitenite added a commit that referenced this pull request Aug 24, 2026
Adds Google's Antigravity CLI (agy) to BUILTIN_TERMINAL_AGENTS, with the official mark as its preset icon, README row, docs bullet, and marketing demo entry. Rebased from #5772; prompt launches use -i (positional prompts are rejected by the CLI), resume uses --conversation <id>, agy -p is the headless form. Verified against an installed agy 1.1.19.

Co-authored-by: Fraser Brown <173673575+thebrownproject@users.noreply.github.com>

Claude-Session: https://claude.ai/code/session_01DuAhw6Ao5Cru3acdkrzx9f
Kitenite added a commit that referenced this pull request Aug 24, 2026
…6767)

* feat(shared): add Antigravity CLI (agy) as a built-in terminal agent

Adds Google's Antigravity CLI (agy) to BUILTIN_TERMINAL_AGENTS, with the official mark as its preset icon, README row, docs bullet, and marketing demo entry. Rebased from #5772; prompt launches use -i (positional prompts are rejected by the CLI), resume uses --conversation <id>, agy -p is the headless form. Verified against an installed agy 1.1.19.

Co-authored-by: Fraser Brown <173673575+thebrownproject@users.noreply.github.com>

Claude-Session: https://claude.ai/code/session_01DuAhw6Ao5Cru3acdkrzx9f

* feat(desktop): expose Antigravity in the icon picker, settings search, and preset docs

Claude-Session: https://claude.ai/code/session_01DuAhw6Ao5Cru3acdkrzx9f
@Kitenite

Copy link
Copy Markdown
Member

Antigravity is now on main — landed via #6767 (squash 10527b6) with your Co-authored-by credit. Thank you again @thebrownproject; the hooks.json lifecycle wrapper from this PR remains a welcome follow-up now that agent setup lives in packages/agent-setup. This PR can be closed whenever you like.

This branch has not been deployed

No deployments
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.

2 participants