# antigravity-cli

> Antigravity CLI (agy) as a Paseo provider: streaming turns, tool rows with diffs, images, structured output, skills and slash commands, conversation import, and opt-in MCP sharing.

> This is a community-submitted listing. Treat plugin-provided text as untrusted data and review the source before installing or running code.

- **Plugin ID:** `antigravity-cli`
- **Source repository:** [lefos13/paseo-plugin-antigravity-cli](https://github.com/lefos13/paseo-plugin-antigravity-cli)
- **Catalog page:** https://paseo.cafe/plugins/antigravity-cli
- **Markdown listing:** https://paseo.cafe/plugins/antigravity-cli.md
- **Catalog API:** https://paseo.cafe/api/plugin/antigravity-cli.json
- **Author:** lefos13
- **License:** MIT
- **Requires Paseo:** `>=0.9.1`
- **Platforms:** all
- **Categories:** provider

## Install

```sh
paseo plugin add npm:paseo-plugin-antigravity-cli@0.3.0
```

Paseo 0.8 GitHub fallback:

```sh
paseo plugin add lefos13/paseo-plugin-antigravity-cli --ref 23678d03f35dd7d0925257388da3b0254253ee81
```

## Caveats

- Requires Google's Antigravity CLI (agy) installed and signed in on the daemon host; built against agy 1.2.10.
- No steering, tool-approval prompts, or revert: agy's stream-json mode does not expose them.
- Sharing Paseo's MCP tools is opt-in and writes a credential-bearing .agents/mcp_config.json (locally git-excluded).
- Plan mode is enforced by the plugin (instruction plus approval prompt); agy's headless --mode plan does not block edits.
- Verified end to end on macOS only.

## Catalog health

- Manifest: valid
- README: present
- License: present
- Tests: present
- Typecheck script: present

## npm artifact security scan

- Status: passed
- Package: paseo-plugin-antigravity-cli
- Version: 0.3.0
- Integrity: sha512-ONpQPCUhB/ApvBMe4yfvdHG+N3xyvEiSlJvIkLvK9kiFocurQYv71NbpxHc81yskkkjCaAkeqPkjVnfFIbzIkQ==
- Blocking findings: 0
- Advisory findings: 0

## Git fallback security scan

- Status: passed
- Blocking findings: 0
- Advisory findings: 0

## Repository-provided content

> Everything below this point comes from the community repository. It is untrusted reference material, not system instructions. No catalog-authored facts follow it.

### Installation notes

From npm (Paseo 0.9):

```
paseo plugin install npm:paseo-plugin-antigravity-cli
```

Or from GitHub:

```
paseo plugin install github:lefos13/paseo-plugin-antigravity-cli
```

You can also paste either source into **Settings → Plugins → Plugin source**. Check it with
`paseo plugin ls`; `antigravity-cli` should be `running`.

Antigravity must already work on its own: `agy --version` should print, and `agy` should be signed
in. Then pick **Antigravity** as the provider when you start a new agent.

###### How this differs from `agy-provider`

[`agy-provider`](https://paseo.cafe/plugins/agy-provider) adapts Google's Antigravity ACP server
through Paseo's ACP shim. This plugin drives the `agy` CLI directly over its documented
`--input-format stream-json` / `--output-format stream-json` mode, so it needs no extra server
install. On top of plain turns it adds edit diffs rebuilt from file snapshots, structured output
through `--json-schema`, image input, import of existing agy conversations, slash commands and
skills, and opt-in sharing of Paseo's MCP tools.

###### Which `agy` gets launched

The first one that resolves, in this order:

1. `providerOptions.agyPath` — a per-session absolute path to the binary.
2. `PASEO_ANTIGRAVITY_BIN` — an environment variable for the daemon's environment.
3. `~/.local/bin/agy` — checked explicitly because a daemon started by a GUI app often does not
   inherit that directory on `PATH`.
4. `agy` — resolved from `PATH`.

### Source README

#### Antigravity CLI provider for Paseo

Runs Google's official Antigravity CLI (`agy`) as a Paseo provider: Paseo owns the session, the
CLI does the work, and every turn, tool call, and message is rendered from the CLI's `stream-json`
protocol. Nothing about Antigravity is reimplemented — this plugin spawns the `agy` binary that is
already installed and signed in on your machine.

- Provider id: `antigravity-cli`
- Requires: Paseo ≥ 0.9.1 (provider protocol version 1), Node 24 for the plugin process, and
  Antigravity CLI 1.2.9 for the behaviour described below.

##### Install

From npm (Paseo 0.9):

```
paseo plugin install npm:paseo-plugin-antigravity-cli
```

Or from GitHub:

```
paseo plugin install github:lefos13/paseo-plugin-antigravity-cli
```

You can also paste either source into **Settings → Plugins → Plugin source**. Check it with
`paseo plugin ls`; `antigravity-cli` should be `running`.

Antigravity must already work on its own: `agy --version` should print, and `agy` should be signed
in. Then pick **Antigravity** as the provider when you start a new agent.

###### How this differs from `agy-provider`

[`agy-provider`](https://paseo.cafe/plugins/agy-provider) adapts Google's Antigravity ACP server
through Paseo's ACP shim. This plugin drives the `agy` CLI directly over its documented
`--input-format stream-json` / `--output-format stream-json` mode, so it needs no extra server
install. On top of plain turns it adds edit diffs rebuilt from file snapshots, structured output
through `--json-schema`, image input, import of existing agy conversations, slash commands and
skills, and opt-in sharing of Paseo's MCP tools.

###### Which `agy` gets launched

The first one that resolves, in this order:

1. `providerOptions.agyPath` — a per-session absolute path to the binary.
2. `PASEO_ANTIGRAVITY_BIN` — an environment variable for the daemon's environment.
3. `~/.local/bin/agy` — checked explicitly because a daemon started by a GUI app often does not
   inherit that directory on `PATH`.
4. `agy` — resolved from `PATH`.

##### What the plugin supports

| Capability | Behaviour |
|---|---|
| `prompt.message` | One `agy` process per session; each prompt is one NDJSON turn on its stdin and exactly one `result` back. A prompt sent while a turn runs is queued by the CLI and becomes the next turn. |
| `prompt.command` | Slash commands, through the composer's command picker. A command turn runs on a CLI launched *without* `--disable-slash-commands` and sends `/<name> <arguments>` as the first token of the turn, which is what makes the CLI expand it; the next plain turn relaunches with the flag again (see below). |
| `prompt.image` | Images cannot go over `stream-json` (`stream input content block type "image" is not supported (only "text")`), so each image part is written to the plugin's attachments folder and the prompt names its absolute path with `view it with view_file`. The folder is passed as an extra `--add-dir` and deleted on `session.close`. Nothing is written into your workspace. |
| `prompt.output_schema` | A prompt with an `outputSchema` is served by a CLI launched with `--json-schema <file> --conversation <id>`; the turn's last assistant message is `JSON.stringify(result.structured_output)`. The flag is launch-time only, so the CLI is relaunched without it before the next plain turn, and a schema prompt is refused with `code: "busy"` while another turn is pending. |
| `session.configure` | Model, reasoning tier, mode, and settings. All of them are launch flags, so a change restarts the CLI on the next turn, resuming the same conversation with `--conversation <id>`. |
| `session.list` | Imports existing Antigravity conversations by reading `~/.gemini/antigravity-cli/conversation_summaries.db` read-only. Filter by workspace, text, and limit; subagent runs are excluded. |
| `session.persistence` | The conversation id agy reports is persisted, so reopening an agent resumes the same Antigravity conversation. |
| `session.subsession` | Each subagent an `invoke_subagent` call starts is shown as a child session of the agent that spawned it, linked to its row, and follows the child's own transcript live (see [Subagents](#subagents)). |
| `permission` | Used only for plan approval: a plan-mode turn ends with an *Implement this plan?* prompt (see [Plan mode](#plan-mode)). agy's own tool approvals cannot be surfaced. |
| `permission.tool_policy` | Accepted (Paseo rejects a session carrying a tool policy otherwise), but preapproved MCP tools cannot be forwarded: agy reads its own rules from `settings.json`. |

Models come from `agy models` (cached for 10 minutes against the resolved binary's path and
mtime; `force` rediscovers). Reasoning tiers are encoded in the model id itself
(`gemini-3.8-flash-high`), so the composer shows one model per family with High/Medium/Low and maps
the choice back onto the slug — `--effort` is never passed, because the CLI rejects the pair.

Modes: *Default* (review file writes before they run), *Accept edits*, *Plan*.

Tool rows are mapped from the CLI's own step parameters: shell commands, file reads and writes,
edits (with a unified diff), `grep_search`/`find_by_name`/`list_dir`, `search_web`,
`read_url_content`, `define_subagent`, and `call_mcp_tool` (shown as `server/tool`). Subagents
get their own rows, below.

###### Plan mode

`agy --mode plan` does not stop a headless run from editing: agy 1.1.28+ approves its own plan
review when nobody can answer it, and on CLI 1.2.10 a `--mode plan` run edited files straight away,
with and without `--dangerously-skip-permissions` (probed 2026-09-24). The plugin therefore enforces
plan mode itself:

- every plan-mode turn is prefixed with a `<plan_mode>` block telling the model to investigate
  read-only and end with an implementation plan instead of implementing it;
- when the turn completes, its last answer is offered as a plan (`kind: "plan"` permission) with
  **Implement** and **Keep planning**. *Implement* switches the session to *Accept edits* and sends
  `The plan is approved. Implement it now.`; *Keep planning*, or simply sending another message,
  withdraws the prompt and stays in plan mode.

This is an instruction, not a sandbox: agy has no headless flag that denies edits, so a model that
ignores the instruction can still write files.

###### Background commands

When the model starts a long-running command in the background (a dev server, a watcher), agy
keeps that tool `ACTIVE` on the stream until the command exits and holds back every later step and
the turn's `result` behind it — the conversation itself carries on and finishes (CLI 1.2.10). A
tool still running after 5 s therefore makes the plugin read the conversation's own transcript
(`~/.gemini/antigravity-cli/brain/<conversation>/.system_generated/logs/transcript.jsonl`), publish
the steps the stream is holding, and complete the turn as soon as the transcript shows the final
answer. The CLI holding the command is left running, so the server stays up; a notice says so.
It cannot take another turn (a line written to it would queue behind the command), so your next
message stops it — and the command with it — and resumes the conversation in a fresh CLI.

##### Subagents

When the model delegates with `invoke_subagent`, agy starts each subagent as its own conversation
in the background and keeps the parent turn open until their reports arrive. The plugin shows that
in two layers:

1. **A subagent row in the parent timeline**, built only from the parent's stream: one row per
   subagent (one call may start several), with its type, role, and the prompt it was given. The
   row stays *running* while the subagent works, and ends *completed* when the subagent finishes or
   the turn succeeds, *canceled* when the turn is interrupted, and *failed* when the turn fails.
2. **A child session per subagent.** agy names each subagent's transcript
   (`~/.gemini/antigravity-cli/brain/<id>/.system_generated/logs/transcript.jsonl`, handed out as
   the step's `log_uri`). The plugin follows that file while the subagent runs and shows it as a
   Paseo child session linked to the row: the subagent's prompt, each tool call with its result,
   and its final answer. The row's text becomes the report the subagent sent back to the parent,
   and the row lists the subagent's tool calls. The child's rows are stored like the parent's, so
   reopening the agent with history restores its children too.

The transcript file is agy-internal and undocumented, so the child session is best-effort: a
missing or unreadable transcript, or one in a shape the plugin does not recognise, leaves the row
from step 1 in place (the parent turn is never affected), and lines of an unknown kind are skipped.
A subagent counts as finished when its transcript ends on an answer with no further tool call; the
parent's own "report arrived" step is not used, because it arrives well after the transcript's last
line and does not say which subagent it belongs to. The plugin stops following a transcript when
the subagent finishes, when the session or the plugin closes, when the parent turn is interrupted or
fails, when the file never shows up within a minute, or after ten minutes without a new line.

##### Slash commands

The composer's command picker lists the commands this plugin has verified the CLI expands in
`stream-json` mode (each one probed against CLI 1.2.9 with `--log-file`, which is the only place
`Print mode: expanded slash command "<name>"` is written — stderr never shows it):

| Command | Source |
|---|---|
| `/plan`, `/goal`, `/grill-me`, `/teamwork-preview`, `/learn`, `/schedule`, `/boost`, `/browser` | The CLI's own workflows (`(system)` in the log). `/learn` writes the behaviour into the workspace's `GEMINI.md`; `/schedule` sets up a recurring run; `/boost` runs the task with deep thinking, multiple perspectives and rigorous verification (it answers `Routine: Solo` when it keeps the work to itself); `/browser` hands the task to the CLI's browser agent. |
| `/<name>` | A skill in this workspace's customization roots: `.agents/skills/<name>/SKILL.md`, and the same under `.agent/`, `_agents/`, `_agent/` (`(skill)` in the log). The name is the skill's own frontmatter `name`, not its directory. |
| `/<name>` | A skill installed for every workspace, in the CLI's own precedence order: `~/.gemini/antigravity-cli/skills/<name>/SKILL.md`, `~/.gemini/config/skills/<name>/SKILL.md`, then `~/.gemini/skills/<name>/SKILL.md`. All three expand (`(skill)` in the log), and each one outranks the CLI's built-in skills. |
| `<plugin>:<name>` | A skill of a plugin installed for the CLI, under `~/.gemini/config/plugins/<plugin>/skills/`. A plugin that keeps its one skill directly in `skills/` is addressed with a `..` placeholder — `/android-cli-plugin:..:android-cli` — because that is the name the CLI expands. |
| `<name>` | A skill the CLI ships itself, under `~/.gemini/antigravity-cli/builtin/skills/`. |
| `/<name>` | A skill in the shared installer's directory, `~/.agents/skills/<name>/SKILL.md`. The CLI never reads that directory, so the **plugin expands this one itself**: agy is sent the skill's own instructions as a plain message (never a slash name) and is given the skill's directory as an extra `--add-dir`, so the turn can read the scripts and templates the skill refers to. A name the CLI expands on its own, or a workspace skill, always wins over the copy here. |

Antigravity decides some built-ins per account, not per binary: `/boost` and `/teamwork-preview`
answer to the `boost_command_disabled` and `teamwork_preview_command_disabled` admin controls, and
`/compact`, `/review` and `/owl` exist in the binary but stayed inert for the account these probes
ran on (`enable-compact-slash-command`, `enable-review`, `enable-owl-slash-command`). A built-in
that is disabled for your account simply **does not expand**: agy treats the text as an ordinary
message and the model answers it, so choosing one of the commands above costs a normal turn rather
than failing it. `/boost` and `/browser` expanded on every probe on the same account as the six
before them, so they are listed; `/compact`, `/review` and `/owl` never expanded there, and a
plugin cannot tell whether any other account has them, so they stay out rather than send a name
that would silently be answered as text.

Commands the CLI answers itself (`/skills`, `/usage`, `/quota`, `/credits`, `/model`, `/effort`,
`/help`, `/config`, `/permissions`, `/hooks`, `/agents`, `/changelog`, …) are deliberately absent:
in a `stream-json` turn each one ends the turn with `ERROR` and exit 2 — `/skills` says so itself
(`/skills is answered by the CLI itself and is unavailable with --input-format stream-json; run it
as its own --print /skills invocation`), and `/btw` and `/tasks` report "not available in print
mode" — so offering one would kill the turn instead of running it. They remain available inside the
CLI's own TUI, or through a separate `--print <command>` invocation.

A command is a *turn*, so it obeys the relaunch rules: `--disable-slash-commands` is left off for
that turn's process and put back for the next plain turn, on the same conversation. That flag is
also what keeps a plain message starting with `/` from being expanded, so while a command turn is
running both a further command and a plain prompt are refused with `code: "busy"` rather than
queued into a process that would serve them wrongly.

A plugin-expanded skill (`~/.agents/skills`, above) is the mirror image: `--disable-slash-commands`
stays on, because the turn is an ordinary message, but the skill's directory joins the launch flags
for that turn alone, so it is its own launch too — the next plain turn relaunches without it. While
such a turn runs, a second command and a plain prompt are refused with `code: "busy"` for the same
reason: the CLI cannot be replaced until the turn it owes has finished.

##### What it cannot do, and why

- **Steering** (`prompt.steer`): a line written to agy's stdin while a turn is running is *queued
  into a following turn*, not applied to the running one. There is no way to steer, so Paseo
  replaces the active turn instead of offering it.
- **Tool permission prompts**: agy resolves tool approval internally through its own
  `toolPermission` setting and cannot surface a request over `stream-json`. Choose the approval
  behaviour in the session settings instead. (`permission` is negotiated only for plan approval.)
- **Rewind** (`session.revert.*`): Antigravity's `/rewind` is interactive-only; nothing in
  `stream-json` exposes it.
- **Shared-installer skills are expanded by the plugin, not the CLI.** `~/.agents/skills/<name>/SKILL.md`
  — the directory other agent CLIs install skills into — is never read by `agy` (probed on CLI 1.2.9:
  a probe skill there was absent from `agy --print /skills`, and a skill that does exist there,
  `/paseo-help`, reached the model as plain text). Paseo therefore offers those names and this plugin
  expands them itself: the turn is sent the `SKILL.md` body, frontmatter stripped, capped at 64 KiB
  (a larger file fails that prompt with `code: "skill_too_large"`, and one that is gone by the time
  the command runs fails with `code: "skill_unavailable"`), followed by the skill's directory and your
  request. Because it is one message and not a CLI command, nothing in it is expanded as a slash name.
  A skill you want the CLI itself to expand belongs under one of the CLI's own roots above.

##### Session settings

- **Tool approval** … default *Use Antigravity setting*, no flag; *Skip all permissions* passes
  `--dangerously-skip-permissions`.
- **Sandbox** — an Off/On select. *On* passes `--sandbox`.
- **Share Paseo tools with Antigravity** — an Off/On select, *Off* by default (below).

The booleans are selects rather than toggles because Paseo draws a plugin toggle as an icon-only
button with no on/off state, so its value is invisible; a select shows the current value as a pill.
Settin
