@thoth-agents/pi-antigravity-bridge

Gemini provider for Pi on the Antigravity ACP server (official Google ACP) or the stream-json agy CLI. Use antigravity/* models in Pi. Full /model picker support. Models runs Pi's tools. ToS safe to use.

Packages

Package details

extension

Install @thoth-agents/pi-antigravity-bridge from npm and Pi will load the resources declared by the package manifest.

$ pi install npm:@thoth-agents/pi-antigravity-bridge
Package
@thoth-agents/pi-antigravity-bridge
Version
0.4.1
Published
Oct 21, 2026
Downloads
836/mo · 240/wk
Author
eremesng
License
MIT
Types
extension
Size
1.1 MB
Dependencies
0 dependencies · 1 peer
Pi manifest JSON
{
  "extensions": [
    "./dist/index.ts"
  ]
}

Security note

Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.

README

@thoth-agents/pi-antigravity-bridge

A Gemini model provider and the AskAntigravity delegation tool for pi, built on Google's official Antigravity binaries: the agy CLI by default, or Google's official ACP server (opt-in). It registers antigravity/gemini-* models in pi's /model picker (streaming), and can provide the opt-in AskAntigravity tool for one-shot delegation (askTool, off by default) - the same combined shape as @thoth-agents/pi-claude-bridge.

If you also have @estebanforge/pi-ask-antigravity installed, this bridge takes over: pi-ask-antigravity detects the bridge and registers nothing, so the AskAntigravity tool is never duplicated.

For per-call reasoning, set thinking (minimal|low|medium|high|xhigh|max), clamped to agy's low|medium|high tiers. It overrides tiers in friendly Gemini aliases (such as flash high) and the configured default; exact catalog slugs and fixed-thinking families keep their resolved tier. effort is agy's CLI term, not a tool parameter.

What it does

You pick a Gemini model in pi's /model picker. pi routes each turn through this provider. A single persistent agy process runs in your workspace; pi feeds it each turn, parses its stream-json events, and streams the agent text back into pi token by token. Token usage is live.

Multi-turn works. The provider binds a pi session to an agy conversation id (persisted under ~/.pi/agent/antigravity-bridge/sessions.json) and resumes it on the next turn via --conversation <id>. agy keeps its own history, so only the latest user message is sent each turn.

Two engines

Turns run through one of two engines behind the same provider surface (config.engine, default stream-json):

  • stream-json (default): the persistent agy CLI process. The tested default; live token usage; conversation resume via --conversation.
  • acp (beta): Google's official ACP server (agy_acp_server.par), JSON-RPC 2.0 over stdio. Beta: parity-verified live against the current build (RC01) - text streaming, multi-turn resume via session/load, bridge tools, effort switching, serialization, abort recovery (see scripts/parity-live.mjs). Two known RC01 gaps remain: no usage fields (token display runs on live client-side estimates via acp.usageEstimate, default estimate, streamed per delta and superseded automatically the day the server starts sending real per-turn usage) and no cancel (abort tears the server down and reloads it next turn).

ACP supports Pi image attachments as typed content blocks; stream-json input is text-only. ACP has no plan mode: provider plan turns require stream-json. AskAntigravity delegations use the agy CLI regardless of the provider engine.

The choice of engine is left to the user, with the trade-offs explained in the tool: a first-run picker modal asks once on a fresh install (stream-json preselected; esc defers, and the modal reappears next start), and /agy engine with no arguments reopens it anytime. An acp pick downloads the ~1.5 GB server binary and starts the Google sign-in immediately; a restart applies the engine. With stream-json active and the agy binary missing, pi warns once per extension instance, when that session first uses an Antigravity model (lazy bridge start), until the binary is found.

Full capability comparison, switching, and setup/auth details: docs/ENGINES.md.

Switch and setup details live in docs/ENGINES.md: switching to acp self-installs Google's official server binary from the antigravity-acp registry entry and prepares the login (your Antigravity subscription, same account as the agy CLI; the extension never sees your credentials). /agy auth signs in explicitly, /agy doctor diagnoses, and first Antigravity use self-heals silently when everything is ready. Sessions are engine-scoped, so switching engines never crosses conversations.

What it cannot do

agy runs its own closed tool loop (read_file, write_file, edit_file, run_command) against --add-dir. Its read-only steps (view_file, list_dir, grep_search, find_by_name) re-run as real pi builtins (read, ls, grep, find) so their cards render natively; mutating steps never execute in pi - they replay through a display-only antigravity wrapper tool. What used to be a hard wall for pi's other tools is bridgeable; see MCP tool bridge below.

Residual limits (with or without the bridge):

  • agy's own edits still land directly on disk; pi's inline diff review does not engage for them.
  • agy commands run without per-action approval by default, same as every other tool in pi. The Approval gate can put pi-side review in front of agy's mutating native tools (off by default; auto enables it only when a pi permission extension is installed). See also Permissions below.
  • API-equivalent cost estimate: messages, session totals, and subagent costs use pi-ai catalog prices, not Antigravity subscription billing. Both engines price input/output/cache-read/cache-write tokens before emitting usage; ACP's client-side token estimates remain estimates and real per-turn usage replaces them with recomputed cost. Unmapped models stay at $0 and log usage-unpriced once per model (visible in the debug log with AGY_DEBUG=1).

The explicit price mapping uses normalized Pi model ids (not the CLI's dotted model slugs):

Antigravity Pi model id pi-ai catalog entry
gemini-3-6-flash google/gemini-3.6-flash
gemini-3-7-flash google/gemini-3.7-flash
gemini-3-1-pro google/gemini-3.1-pro-preview
claude-sonnet-4-6 anthropic/claude-sonnet-4-6
gpt-oss-120b, gpt-oss-120b-low, gpt-oss-120b-medium, gpt-oss-120b-high groq/openai/gpt-oss-120b

New model versions require an explicit mapping and tests; no price is guessed from the model name.

MCP tool bridge (agy uses pi's tools)

While agy is the active model it normally cannot see pi's universe of extensions: agentmemory, codegraph, web search, slack/asana, the Ask* delegations, and any other installed pi tool. This extension optionally bridges that gap.

The bridge starts a localhost MCP server inside pi's process. The exposed catalog is computed live from pi's active tools on every tools/list and re-checked immediately before every tools/call: the bridgeTools mode, the session's /agy tools hidden set, and the bridge's own internal tools (AskAntigravity, the display-only antigravity wrapper, activate_skill, bridge_poll_result, the agy_web_search/agy_read_url wrappers) are filtered each time, and a call for anything outside the fresh set is rejected - a cached MCP catalog is not authorization. A call that passes routes into pi's own tool loop via the round-trip described below. Discovery is instance-private by default (bridgeDiscovery: "private"): each extension factory acquires a short pi-agy-<8 hex> server name, collision-checked against live PID-owned private configs and process-wide reservations (including separately loaded package copies), and writes only its own .agents/mcp_config.json under ~/.pi/agent/antigravity-bridge/agy-mcp-<pid>-<instance>/. The stream driver passes this directory through --add-dir; ACP supplies the same owned name through its per-session mcpServers. Private mode never registers or suppresses global bridge entries. It still removes dead-process pi-bridge-* entries while preserving live and foreign servers. A live legacy-global bridge triggers one warning: mixed discovery modes are not supported for isolation.

Lazy lifecycle and catalog. Every instance, including root, starts the MCP server/private config/approval hooks only when using an antigravity model: at session start, on model selection, or immediately before its first provider stream. Startup is single-flight and awaited before either engine launches; shutdown invalidates pending startup. Sessions using other providers do not start the bridge or a persistent agy process. Loading uses a fresh models-cache.json; a missing/stale catalog triggers bounded agy models discovery awaited before registration. Success populates the current session; failure retains the stale cache or uses the built-in fallback. The stream-json CLI version check is also deferred to first use. Existing root/UI onboarding guards are unchanged.

Owned cleanup. Session shutdown terminates the drivers, removes the private config and approval hook, and removes only descriptor-cache keys the instance acquired under ~/.gemini/antigravity-cli/mcp/: its exact acquired private pi-agy-<8 hex> name, or the unique pi-bridge-<pid>-<instance> key if it successfully registered in legacy-global mode. Shared names (pi-antigravity-bridge and ACP's pi-bridge), other instances' keys, and old caches are never removed. An instance that never started the bridge removes no descriptor cache. /new and resume can start the same extension instance again. See bridge lifecycle.

Tool schemas. On both engines and discovery modes, object-root schemas without unions are advertised unchanged. Every present root anyOf/oneOf must be a non-empty object-only union, even when the root already declares type: "object"; eligible roots are advertised with type: "object", preserving variants and root keywords (including $defs/definitions). Variants can also be allOf of objects or local references resolving to objects. Other non-object schemas and roots with any ineligible union (including mixed variants, empty unions and dangling/cyclic references) are omitted with one warning per tool per session (TUI toast, stderr in headless children). Pi still validates arguments against the original schema.

Tool-name limit. agy qualifies names as mcp_<server>_<tool> and accepts at most 64 characters. Before advertising, the bridge enforces 4 + serverName.length + 1 + toolName.length <= 64 using the actual discovery name: private pi-agy-<8 hex>, legacy stream-json pi-bridge-<pid>-<UUID>, or legacy ACP pi-bridge. Overlong tools are omitted through the same once-per-tool-per-session warning channel as unsupported schemas, rather than disappearing silently. The short private name fits both agent_browser_electron and agent_browser_network_source; instance directories and approval hooks retain their full UUIDs. Legacy stream-json's long name leaves much less room and can omit even bridge-local tools; private discovery is recommended.

Upstream pi APIs only. Bridge calls park in the provider's round-trip store; the provider ends the pi assistant message with a toolUse stop reason for the real pi tool, pi executes it in its own loop (native cards, permissions, hooks), and the toolResult completes the parked MCP response on the next stream call.

Long calls don't die. agy's MCP client abandons a tools/call request at a flat ~180s, which used to kill any pi tool that ran longer (a long peer review, a build, a commit preview waiting for you). A call still running after ~20 seconds now settles its HTTP request with a STILL RUNNING answer carrying a callId while pi keeps executing; agy fetches the result through the bridge-local bridge_poll_result tool and polls until it lands. Escalated calls get their own 30-minute budget, so human-gated tools can take as long as the human takes. Fast calls stay fully synchronous and never see any of this. If a park does fail (abort, timeout, recycle), the late result is re-routed to agy as a follow-up prompt in the same conversation instead of being lost.

Recursion safety. Only the provider's agy receives its private --add-dir; AskAntigravity is filtered from the exposed tool list. In private mode delegated agy never receives the private bridge config, and no global suppression or suppression healing runs. bridgeDiscovery: "legacy-global" restores the upstream shared registration/suppression behavior: stream-json also registers pi-bridge-<pid>-<instance> globally, and AskAntigravity hides global bridge entries for its entire run, with marker-aware release/healing. Foreign global servers remain untouched. Discovery changes require a restart; do not mix private and legacy-global sessions.

Cost / fan-out. Every registered pi tool except builtins and the bridge's own internal tools is exposed (respecting the bridgeTools mode and any /agy tools hides), including other delegation tools like AskClaude/AskCodex. agy can therefore chain into other models via the bridge, which is a new cost/time fan-out vector that did not exist before this feature.

Security. The MCP server binds to 127.0.0.1 only and requires a per-session shared-secret header (x-bridge-token) that agy sends from the bridge config; browsers cannot set custom headers on a simple cross-origin POST, so this blocks web CSRF against the loopback server. Request bodies are size-capped. This is intended for single-user developer machines: any local process running as the same user can read the token from the per-pid config and call the exposed tools, so do not run it on a shared host where you do not trust other same-user processes.

Native cards, wrapper replay, and skills

Read-only agy steps (view_file, list_dir, grep_search, find_by_name) re-run as real pi builtins (read, ls, grep, find) when those builtins are active, so their cards render with pi's own renderers. Mutating and agy-specialty steps render through a display-only antigravity wrapper tool: its execute() replays the output agy already recorded, so the transcript gets proper toolCall/toolResult pairs without any double execution. Neither path re-runs anything with side effects.

When the bridge is on, agy also gets one activate_skill tool whose enum is your pi Agent Skills catalog; calling it returns the SKILL.md body. The bridge answers it directly, no pi round-trip. /agy doctor prints driver counters, bridge port, and the last lifecycle events without spending tokens.

On the ACP engine there is no re-exec: agy's own native tool steps render as display-only cards in pi instead - a status icon plus the file path with colored diff lines, the command line, or the captured output - streamed as the steps start and complete. The stream-json engine keeps its native re-exec cards for read-only steps.

AskAntigravity calls/results and the agy-native-event display-only messages render through the theme's Render KIT when present, discovered through @thoth-agents/pi-core at render time. Without the kit, they keep native Pi rendering; there is no dependency on @thoth-agents/pi-thoth-theme.

Approval gate (agy native tools)

agy runs its own agent loop with native tools (run_command, create_file, edit_file, ...), which pi's permission extensions never saw. The optional approval gate routes those calls through a pi-side approval: a staged PreToolUse hook parks the call, the provider surfaces it as a shadow bash/write/edit toolUse, and your permission extension (or the built-in ask/allow/deny fallback) decides before agy executes it. Off by default (approvals.gateMode: auto enables it only when a pi permission extension is detected); denials fail closed; read-only agy tools stay ungated. On ACP turns the server has its own per-tool permission ask: when one fires (skipPermissions off), the request parks on a real pi dialog instead of a silent deny, and allow-always choices are remembered per connection.

Full mechanics, configuration, and a sample gate extension: docs/APPROVAL-GATE.md.

Install

The bridge runs on pi's public APIs; the extension never edits your pi install.

Install manually with pi's package manager; the Thoth installer does not manage this bridge:

pi install npm:@thoth-agents/pi-antigravity-bridge

Requires Pi >=0.99.0 and Node >=22.19.0. ACP-only installations are supported; the agy CLI must be installed and authenticated for stream-json turns, AskAntigravity delegations, web delegates, and /agy quota. If you need the CLI, follow Google's official install guide for your platform, then run agy once to complete Google OAuth. The extension resolves agy on $PATH, or via the AGY_BIN environment variable. While the stream-json engine is active and the binary cannot be found, pi warns once per instance on first Antigravity use (toast in the TUI, stderr headless) pointing at the install guide; sessions that never use Antigravity do not run this check.

Usage

Pick a model and talk to pi as usual:

/model

Look for the models namespaced as: antigravity

Or specify a model directly:

/model antigravity/gemini-3-6-flash-medium

Model ids are slugified from the agy models output (Gemini 3.6 Flash (Medium) becomes gemini-3-6-flash-medium). Extension load uses models-cache.json while fresh (five-minute TTL). Missing/stale caches trigger bounded agy models discovery (eight-second timeout) before registering provider and AskAntigravity models in the current session. Discovery failure retains the stale cache, then uses the built-in fallback (including Gemini 4 Argon). After an agy update, reload once the cache is stale to discover new models.

If discovery fails and no usable cached catalog exists, the built-in fallback populates the picker. Bridge startup and the stream-json version check are deferred until an Antigravity model is used, so binary/auth/network failures surface at first use.

Bridge surface

config.json selects the bridge surface. Boolean keys use JSON true/false; the matching slash commands accept on/off:

Key Values Default
askTool true (register the AskAntigravity delegation tool), false (no delegation tool; provider and models only) false
webTools false (no web tools), true (register agy_web_search + agy_read_url as Pi tools, usable by ANY provider's model). Each call spawns a one-shot search-only agy agent (plan mode, bridge MCP inheritance off), gates the answer on an observed native search_web/read_url_content step, and spends Antigravity quota. Off by default: Antigravity sessions already have native web tools on both engines; these serve other providers false
bridgeDiscovery private (per-instance discovery, no global registration/suppression), legacy-global (upstream shared behavior). Env AGY_BRIDGE_DISCOVERY overrides the file; restart required private
bridgeTools none (bridge off), all (every non-builtin tool, incl. other Ask* delegations), mcp (pi-mcp-adapter tools + skills bridge only) all
digest false (stable prompts; agy's prompt cache hits) or true (inject a delta of pi-side context - compaction summaries, other-provider turns - into each agy prompt; the delta changes every turn, so agy re-bills the full context). Enable for mixed-provider sessions where agy must see pi-side context false
systemPrompt true (send pi's system prompt - operating instructions plus the global agent-dir AGENTS.md and ancestor AGENTS.md/CLAUDE.md - to the first prompt of each new agy conversation, plus a tool-priority note: Pi Bridge tools win over agy's native interactive ones, which never reach the user. Delivery: stream-json stages it as an agy agent file via --agent, off the prompt line - the CLI silently drops single prompts past a ~25KB cap and the dropped turn kills the conversation; ACP prepends it to the first prompt) or false (agy-native behavior) true
agent Custom agy agent name (--agent); stream-json provider turns only, ignored by ACP. AGY_AGENT overrides the file Unset (agy default)
turnTimeoutMin Overall cap on ONE agy turn, minutes, both engines. When it fires, the bridge kills the agy process mid-task ("ACP turn exceeded the 10m deadline" / "agy exceeded the 10m turn timeout") - it is a bridge cap, not a Google server limit. Default is TTY-aware: 0 (no cap) on an interactive pi - you are the backstop with Esc; 20 headless, where nobody can abort and one runaway turn blocks the serialized turn queue. Opt into a gate with 1-1440 (free type via config.json or `/agy timeout <1-1440 off>, or the /agypicker's preset list);0` disables explicitly; anything else falls back to the TTY-aware default. The default 3m inactivity stall guard still bounds a hung server unless explicitly disabled
inactivityTimeoutMin Progress-inactivity cap, minutes: no recognized stream-json frame / no ACP session/update for this long fails the activity wait. Checkpoints count as progress; unrecognized stdout does not. 0 disables 3 (180000 ms)
startupTimeoutMs Absolute deadline per startup-type wait (provider beforeStart, shared lazy startFlight, exclusive startup/termination/recycling, ACP setup). 0 disables 120000
queueTimeoutMs Requester-side serialized run-queue deadline. Expiry fails only that request, never the predecessor or its parks; the expired request cannot launch later. 0 disables 120000

Env overrides: AGY_AGENT, AGY_BRIDGE_TOOLS, AGY_ASK_TOOL, AGY_WEB_TOOLS, AGY_DIGEST, AGY_SYSTEM_PROMPT, AGY_TURN_TIMEOUT_MIN, AGY_INACTIVITY_TIMEOUT_MIN, AGY_STARTUP_TIMEOUT_MS, AGY_QUEUE_TIMEOUT_MS. Env wins over the file, so while AGY_DIGEST or AGY_SYSTEM_PROMPT is set, the matching /agy digest or /agy system-prompt toggle persists a value that never takes effect.

Wait expiry ends the provider stream with an explicit error naming the wait. Activity waits are inactivity-based, not a new absolute turn deadline: recognized frames (including checkpoint-only progress) refresh them, and parked bridge calls suspend inactivity as before. Existing overall-turn caps and all zero/disabled caps remain unchanged. Configure the parent subagent stall budget above bridge inactivity (default bridge 180000 ms < parent 240000 ms); the bridge cannot read the parent's budget. Checkpoints produce no Pi events, so checkpoint-only work can still trigger the parent's separate watchdog.

If agy settles while a native/wrapper replay is outstanding, its original handle, unread activities and final outcome remain available to the matching tool-result continuation for 10 minutes (bounded to 64 retained turns). The continuation drains that turn without another prompt; unrelated fresh prompts are not blocked. Session shutdown clears these replay tombstones. The antigravity({tool,key}) display/replay contract is unchanged.

The activate_skill catalog mirrors pi's directory-based skill discovery: the two global dirs plus project dirs, the latter only when pi has trusted the project (same gate pi itself applies). Pi's other skill sources - the skills settings array, package.json entries, and --skill CLI paths - are not mirrored and won't appear in the catalog.

The /agy command

/agy configures the provider at runtime. Settings persist to ~/.pi/agent/antigravity-bridge/config.json and take effect on the next turn.

/agy                      status summary, or open the full settings picker (TUI)
/agy doctor               single status surface: bridge state, driver counters, versions, acp state, lifecycle, settings, log dir
/agy tasks                browse background tasks for the bound Antigravity conversation
/agy artifacts [open <name|index>]   browse conversation artifacts, or open one by name/index
/agy subagents            show Antigravity subagents tracked this session
/agy agent [<name>|off]   list/select a custom agy agent, or clear it (stream-json only)
/agy auth                 run the antigravity-acp sign-in now (engine acp): opens the Google login in your browser, shows the URL when no browser opens
/agy mode plan            request agy's plan mode (stream-json only; see Permissions)
/agy mode accept-edits    agy applies edits directly (default)
/agy permissions on|off   auto-approve / prompt for tool calls (see warning)
/agy ask on|off           register the AskAntigravity delegation tool (default off: only the provider and models, even with pi-ask-antigravity installed)
/agy model flash|pro|argon|gemini   fallback model for the AskAntigravity tool; callers may override per call
/agy thinking low|medium|high fallback thinking tier for the AskAntigravity tool; callers may override per call
/agy digest on|off        inject pi-side context into agy prompts (default off; see table above)
/agy system-prompt on|off send pi's system prompt + AGENTS.md + the Pi Bridge tool-priority note to new agy conversations (default on)
/agy bridge all|mcp|none  which pi tools the MCP bridge exposes to agy (default all; none = bridge off; a running server picks up the new catalog immediately, a stopped one on the next start)
/agy tools [hide|show <name>|reset]   session-only bridge-catalog hides (multi-word names OK; reset restores the full set; bare lists exposed + hidden; never touches saved config)
/agy web on|off            register the agy_web_search + agy_read_url pi tools for ANY provider's model (default off; applies on the next pi start or /reload; every call spawns agy and spends Antigravity quota)
/agy acp-bin <path|auto>  point the ACP engine at a specific server binary (auto = setup installs, or AGY_ACP_BIN; applies on the next ACP turn)
/agy engine acp|stream-json   switch the turn engine (restart to apply; default stream-json; acp is beta and runs self-service setup: binary install + auth bootstrap). No arguments opens the engine picker modal (TUI)
/agy auth-manual             manual ACP credential setup (fallback; auto-setup normally covers this; default login = your Antigravity subscription, same account as the agy CLI)
/agy clear                drop all session bindings (force fresh conversations)

AskAntigravity parameters

Enable askTool to delegate a self-contained task:

Parameter Default Description
prompt Required Task and all required context.
cwd Current Pi working directory Workspace directory agy runs in.
model Configured default Alias (flash, pro, argon, gemini, or a catalogued family) or exact id; aliases support tiers (flash high) and versions (3.5 flash).
thinking Model tier/configured default Per-call reasoning as described above; exact slugs and fixed-thinking families retain their resolved tier.
mode accept-edits plan for restricted review or accept-edits for workspace edits; see Permissions.
digest true for plan, otherwise false Request compact digests instead of full files.
conversationId Unset (new conversation) Previous call's details.conversationId to continue that conversation.
timeoutMinutes 10 Hard deadline in minutes.
includeContext false Opt-in export of the Pi conversation as temporary markdown for agy to read; enable only on explicit user request (extra tokens).

Permissions

pi itself has no built-in approval gate. Unlike codex, claude, or agy running interactively, pi does not prompt you to confirm each tool action before it runs. That is the host environment this extension lives in.

Because agy runs non-interactively under this provider (nothing can answer a y/n prompt), this extension passes --dangerously-skip-permissions by default on accept-edits runs. It is technically necessary there: accept-edits auto-approves file edits but not shell commands, so a run_command would otherwise hang forever waiting for a prompt nothing can answer (upstream google-antigravity/antigravity-cli#318). The net effect is that agy executes commands the same way pi already executes your other tools: without per-action review.

Stream-json provider plan turns (/agy mode plan) never receive the flag: the flag auto-approves every permission request, including plan mode's own approval gate, which would silently turn review-only into full write access inside the --add-dir grant (probed 2026-09-25: with the flag a plan run wrote files; without it, file and command attempts end the run quickly with a "confirm plan" message).

AskAntigravity with mode: "plan" instead stages a restricted reviewer agent without native file-editing tools and passes skip-permissions when enabled. Analysis shell commands remain available: read-only behavior relies on a prompt guard, not a hard sandbox, so commands can still have side effects. If reviewer-agent staging fails, the delegation falls back to no skip flag and a stricter prompt forbidding commands. Do not combine --sandbox with skip-permissions (#36).

For per-action review of agy's mutating native tools (run_command, create_file, edit_file, ...), see the Approval gate: with it on, the call must pass a pi-side approval (your permission extension, or the built-in ask/allow/deny fallback) before agy executes it.

Windows process containment

The stream-json driver, AskAntigravity, web delegates and ACP server each run inside a kill-on-close Windows Job Object. On any end, including agy exiting on its own, the job ends all descendants too. Anything agy starts that should outlive it (for example a cold browser) may therefore end with it. Processes created through brokers, COM or WMI can escape the job.

Short --version and models probes use plain spawn and end only their own leader. If the job launcher is unavailable, agent launches fall back to plain spawn with a warning and leader-only termination; there is no PID-tree fallback. Console windows stay hidden through CREATE_NO_WINDOW, the same mechanism as before. POSIX launches retain process-group termination.

Windows quota console diagnosis

AskAntigravity also uses shell: false and windowsHide: true. Windows launches are not detached, so agy's MCP descendants inherit the hidden console rather than allocating new visible consoles. POSIX launches remain detached for process-group termination; Windows agent termination uses the owned job described above.

/agy quota calls the CLI directly with --print /usage --output-format json --print-timeout 30s, piped output, shell: false, windowsHide: true, and detached: false on Windows. It does not run the configured ACP server. Prefer a real agy.exe in AGY_BIN: .cmd/.bat shims need a shell on Windows and are not supported by this direct-spawn path.

A Windows reproduction using the actual fetchAgyQuota helper resolved AGY_BIN and PATH to a real agy.exe (not a shim). Two calls returned quota successfully in approximately 2.4–3.1 seconds. Get-CimInstance Win32_Process sampling observed an agy-associated conhost.exe and traced several cmd.exe /c launchers for configured MCP servers (npx and codegraph) with agy as their parent, even for this quota-only request. The MCP launches are inside agy, not the bridge's spawn helper; a conhost.exe alone is not evidence of a visible console. A second trace also sampled EnumWindows/IsWindowVisible but captured no visible windows; the reported flash was not reproduced, so a specific visible-window cause is still unconfirmed. windowsHide on the bridge spawn does not establish that descendants launched by agy are hidden. No speculative spawn change was made. A live desktop reproduction/trace is still needed before attributing the flash to a particular upstream child; the quota spawn-options regression protects the existing direct, hidden Windows launch.

A follow-up probe on agy 1.3.2 reused the bridge's temporary reviewer agent with --agent, inheritMcp: false, inheritCustomizations: false, excludeDefaultComponents: true, and mcpServers: []. Get-CimInstance Win32_Process polling still observed four global MCP cmd.exe launchers directly parented by agy, both with and without the custom agent: three npx commands and codegraph serve --mcp. Including their descendants, the baseline captured 5 cmd.exe / 6 node.exe processes, versus 7 / 8 with the agent (sampling can miss short-lived children). Both quota calls parsed two groups with two buckets each, in 2237 ms and 2671 ms respectively. The temporary agent was removed and no traced descendants remained. Thus the agent's MCP exclusions do not prevent global MCP process startup for /usage in this version; the ineffective change was reverted, preserving the current quota invocation. agy --help exposes no per-print invocation flag to disable MCP (agy mcp disable changes global configuration instead).

Live desktop capture (agy 1.3.2). While the user ran /agy quota repeatedly, a 125-second capture polled top-level windows every ~25 ms and process creations. Two agy launches were confirmed, each starting its four global MCP cmd.exe launchers; no window from that process ancestry was ever visible, and the user saw no flash. All short-lived windows in the interval (an msrdc helper, a conhost IME window and a 280 ms cmd console) stayed invisible. The earlier flash was therefore not reproduced and is most likely unrelated to /agy quota (another process on the desktop, such as the terminal host); /agy quota itself shows no visible window.

If you do see console flashes: inspect your own ~/.gemini/config/mcp_config.json. On Windows, MCP commands resolving to .cmd shims (such as npx or an npm-installed codegraph) can create console windows. Where the server supports it, use the actual node.exe executable with the installed server's JavaScript entry point in args, or a native .exe, rather than the shim. This was not needed in the capture above. The bridge does not edit or disable your global MCP configuration.

Run pi inside a sandbox

For isolation when running any agent that executes commands without a confirmation gate, run pi inside construct-cli - EstebanForge's sandbox for AI agents. Isolated container, no path escape, ephemeral filesystem, strict / offline network modes, secret redaction. The blast radius of a bad command stays in the container, not your host. Install and usage instructions are in that repo.

Environment variables

Variable Purpose
AGY_BIN Path to the agy binary. Defaults to agy on PATH.
AGY_ENGINE Engine: stream-json (default) or acp. Wins over the config file.
AGY_ACP_BIN Path to the ACP server binary (agy_acp_server.par). Defaults to agy_acp_server.par on PATH. Wins over config.acp.bin. When neither points at a binary, auto-setup installs one.
AGY_EXTRA_ARGS Extra args for AskAntigravity CLI delegations only. Whitespace-split; not used by provider turns, web delegates, or quota calls.
AGY_CONVERSATIONS_DIR Override the conversations DB directory.
AGY_MODE Override provider execution mode: plan (stream-json only) or accept-edits (default). Wins over the config file.
AGY_SKIP_PERMISSIONS 1/true (default) to pass --dangerously-skip-permissions so commands don't hang on an unanswerable prompt in -p mode. 0/false to prompt (may hang non-interactive commands). See Permissions for plan-mode exceptions. Wins over the config file.
AGY_USAGE_ESTIMATE ACP token display: estimate (default; live client-side per-delta text estimates), direct (one output token per streamed text/thought delta; input remains regex/text-estimated), off (no estimated usage display). Real server usage supersedes estimates. Anything else falls back to estimate. Wins over the config file.
AGY_AGENT Custom agy agent name for stream-json provider turns only; overrides config agent. ACP ignores it.
AGY_DEFAULT_MODEL Default model alias for the AskAntigravity tool (flash/pro/argon/gemini, or a tier/version qualifier). Wins over the config file.
AGY_DEFAULT_THINKING Default thinking tier for the AskAntigravity tool: low/medium/high. Anything else falls back to medium. Wins over the config file.
AGY_DEBUG 1/true/on writes the full trail to the daily log (driver lifecycle, raw bridge traffic). Default off: only error records land on disk - routine disk writes are zero for regular users, and warnings surface as UI toasts instead.
AGY_APPROVALS Approval gate mode: auto (default; gate on only when a pi permission extension is detected), shadow (force the shadow-tool gate on), dedicated, off. Unknown values fall back to auto, so a typo can never force the gate on. Wins over config.approvals.gateMode.
AGY_APPROVALS_MODE Fallback decision when no permission extension answers a gated call: ask (interactive prompt), allow, deny (headless default). Wins over config.approvals.mode.

Debug logs

The extension keeps a daily log on your machine, sorted by day:

~/.pi/extensions-data/estebanforge/pi-antigravity-bridge/logs/<YYYY-MM-DD>.ndjson

One JSON record per line. Two verbosity tiers keep the disk cost at zero for regular users: by default only error records land on disk - everything routine (turn starts, tool calls, escalations, commands, driver failures) is withheld. Warnings are not lost: the extension toasts each one in the pi UI (bridge tool failures, stalls, timeouts, process exits), so users see them and can report them; deliberate aborts and failures pi already renders as the turn's own error block stay silent. Set AGY_DEBUG=1 before reproducing a problem for the full trail: per-event driver lifecycle (spawn, exit, session load/new, unparks), turn starts and outcomes, bridge tool calls, escalations and poll traffic, late deliveries, list-tools traffic, recycle causes, and the raw bridge chatter. /agy doctor prints the log directory.

Notes:

  • Retention: 14 days. Older files are pruned automatically.
  • Privacy: prompt text, tool arguments, and tool output never land in the log. Secret-shaped values (tokens, API keys, credentials, header blocks) are redacted, and long strings are truncated. The auth-url record strips the login URL's query string.
  • Logging never throws: an unwritable directory is skipped silently and retried on the next record.
  • SSD wear: default volume is effectively zero until something actually errors. Verbose mode (AGY_DEBUG=1) writes more; turn it off after reproducing.

When you report an issue, attach the last day or two of files from that directory. For anything that needs reproduction, run with AGY_DEBUG=1 once and attach that day's file. They usually contain the exact failure sequence (engine, session, bridge call, error) with no need to guess.

Development

Build, test, and debug instructions live in docs/DEVELOPMENT.md. For the internal architecture (engines, bridge round-trips, conversation discovery) see docs/ARCHITECTURE.md.

Terms of Service notice

Google's Antigravity ToS (Section 6) prohibits accessing the service "in connection with products not provided by us", and names as its example using tools like Hermes/OpenClaw with Antigravity OAuth. That targets reusing your credentials in a non-Google harness that calls Google's backend directly.

This extension does not do that. It spawns official, unmodified Google binaries as subprocesses - the agy CLI, or the official ACP server when enabled - which perform their own OAuth and make their own calls to Google. This code never sees, extracts, or reuses your token, and never contacts Antigravity's backend. It only reads what the binary itself produces locally: its stream-json output, or its ACP JSON-RPC messages. From Google's server-side view there is no signal that distinguishes "agy launched by pi" from "agy launched by a terminal, an IDE task runner, or cron": same signed binaries, same authenticated calls.

Google's reported enforcement to date (the February 2026 suspensions) targeted token-reuse tools, not spawning the official CLI.

@thoth-agents/pi-antigravity-bridge practical risk is low, near zero. But not zero: the "in connection with" wording is broad, and Google can suspend accounts at its discretion regardless of whether a breach is provable. Grey area. Safe for now. You should read "news" about this online from time to time.

This is engineering analysis, not legal advice. Use against your own Antigravity account at your own risk; I am not responsible for any consequence to your account.

License

MIT.