---
title: antigravity()
description: >-
  The Antigravity harness, its options and id, its Gemini API key, plugins,
  prompt size limit and telemetry.
---
> ## Documentation Index
> Fetch the complete documentation index at: https://docs.reeval.ai/llms.txt
> Use this file to discover all available pages before exploring further.

`antigravity()` runs Google's Antigravity CLI (`agy`) in the Docker sandbox, with a Gemini API key. `model` is required.

```ts title="reeval.config.ts"
import { defineConfig } from '{{ pkg }}'
import { antigravity } from '{{ pkg }}/harness'

export default defineConfig({
  harness: antigravity({ model: 'gemini-3.8-flash-medium' }),
})
```

## Options

<Property name="model" type="string">
  A model slug that `agy models` lists for a Gemini API key, such as `gemini-3.8-flash-medium`. Required, since the CLI's default changes under you.
</Property>

<Property name="effort" type="string" optional>
  Reasoning effort passed as `agy --effort`: `low`, `medium`, `high` or `max`. The slug's `-low` / `-medium` / `-high` suffix is the same knob baked into `model`. It isn't the measured [effort](/concepts/lift#effort-next-to-lift).
</Property>

<Property name="id" type="string" optional>
  The harness's id in cell keys, filters and the record. Default `antigravity:<model>`, or `antigravity:<model>[effort=<value>]` when `effort` is set.
</Property>

<Property name="gateway" type="'direct' | Gateway" optional>
  The gateway this harness's model calls go through, by name or helper, such as `direct()`. It skips the config's `gateway` fallback: the plan refuses a gateway that isn't listed or can't serve this harness. See [Gateways](/reference/gateway#pinning-a-harness).
</Property>

<Property name="maxConcurrent" type="number" optional>
  The most Antigravity attempts at once across the run, for example for your key's rate limits.
</Property>

<Property name="startTimeout" type="Duration" optional>
  How long its session may take to become ready (bootstrap and session start) before the attempt is an infra error, such as `'3m'`. Default `'90s'`. A start that times out is aborted and started once more; a second timeout fails the attempt with `antigravity: session did not become ready within 90s (tried twice)`, and the record's `startRetries` notes a retried start.
</Property>

## At a glance

| | |
|---|---|
| Import | `'{{ pkg }}/harness'` |
| Credential | `GEMINI_API_KEY` (a Gemini API key) |
| Adapter | `@reeval/harness-antigravity` 0.1.12, bundled with reeval |
| Sandbox | `docker()` only |
| Image | `reeval-sandbox:antigravity-0.1.12` |
| Rules file | `AGENTS.md` |
| Skills (default placement) | `~/.gemini/config/skills` |
| Skills (`placement: 'workspace'`) | `.agents/skills` in the workspace |
| Egress hosts added | `generativelanguage.googleapis.com` |
| Tokens | Reported per turn |

Build its image once with `reeval image build` in a project whose config uses `antigravity()`.

## The key

The harness uses a Gemini API key only, never the CLI's Google sign-in, which Google's terms don't allow automating. reeval passes `GEMINI_API_KEY` to the adapter explicitly, and it never enters the container. The gateway swaps it in on one kind of request (what CLI 1.4.7 sends it on: its model, and a lite one for titles):

| Host | Endpoint |
|---|---|
| `generativelanguage.googleapis.com` | `POST /v1beta/models/<model>:streamGenerateContent` |

The adapter refuses to run in a sandbox that can't broker the key, so it can't leak through a plain environment variable.

## Settings

| Setting | Why |
|---|---|
| `enableTelemetry: false` in the CLI's settings | No telemetry it can turn off (below) |
| `modelProvider: 'gemini'` in the CLI's settings | The Gemini API key's provider |
| `AGY_CLI_DISABLE_AUTO_UPDATE=true` | No updates; `1` doesn't turn them off |
| MCP servers in `~/.gemini/config/mcp_config.json` | Where the CLI reads them; remote servers take `serverUrl` |
| The adapter's instructions appended to `~/.gemini/GEMINI.md` | How the adapter talks to the agent |
| Home skills in `~/.gemini/config/skills` | Where the CLI reads them, not the `~/.gemini/antigravity-cli/skills` its docs give |
| Plugins installed with `agy plugin install` | Every part (below) |

## Plugins

```text
agy plugin install /home/reeval/.reeval/plugins/review
```

reeval copies each plugin to `~/.reeval/plugins/<name>/`, and the adapter installs that copy as the session starts. The CLI copies it to `~/.gemini/config/plugins/<name>/`, which `context` lists, and loads every part: its commands become skills named `<plugin>-cmd-<command>`, and its MCP tools are named `mcp__<plugin>_<server>__<tool>`.

The adapter then fixes what CLI 1.4.2 would get wrong in the installed copy:

| What | Why |
|---|---|
| `hooks.json` rewritten in the CLI's shape, `${CLAUDE_PLUGIN_ROOT}` filled in | It copies Claude Code's file unchanged, where a `SessionStart` hook never runs, and doesn't set the variable |
| `trigger: always_on` on a rule with no frontmatter, or `alwaysApply: true` | It leaves out a rule without a trigger |
| `name:` on a skill without one | It lists a command it converted as `SKILL` |

The CLI starts a plugin's MCP servers itself, from the plugin's `.mcp.json`. As for [Claude Code](/reference/harness/claude-code#plugins), reeval rewrites that file to run each through its MCP timer before the install, and a host variable can't go in it:

```text
reeval: evals/review.eval.ts: evaluate("reviews the diff") on antigravity:gemini-3.8-flash-medium: Antigravity loads the review plugin's MCP server "docs" itself, so reeval can't give it DOCS_TOKEN from the host: use only: ['skills'] and declare the server in mcp, where reeval fills it in
```

The CLI runs `SessionStart`, `PreToolUse`, `PostToolUse` and `Stop` hooks, so the plan refuses a plugin with any other event, or with a hook that isn't a `command`. agy installs a plugin that also has its own manifest (a root `plugin.json`, `.antigravity-plugin/plugin.json`, `.gemini-plugin/plugin.json` or `gemini-extension.json`) from that manifest instead, so the plan refuses it. Each turn is a new process, so a `SessionStart` hook runs on every turn. An install the CLI refuses fails the attempt with `agy plugin install <dir> exited <code>: …`.

## Telemetry it sends anyway

| Host | What |
|---|---|
| `play.googleapis.com` | Telemetry |
| `antigravity-unleash.goog` | Feature flags |

CLI 1.4.7 opens both in every session. No setting stops them, and neither gets the key.

Under a restricted egress policy the gateway refuses them and records them under the record's `egress.expectedBlocked`, not `blocked`. `-v` prints one `gateway` line for them at teardown, `expected blocks, not logged per request:` with each `host:port` and its connection count, instead of one line per request.

## Tokens

| The CLI reports | The turn records |
|---|---|
| `input_tokens`, without cache reads | `input` |
| `cache_read_tokens` | `cacheRead` |
| `output_tokens`, thinking included | `output` |
| `thinking_tokens` | `reasoning` |

Each turn also records the model that served it. A turn served mostly from the cache records more `cacheRead` than `input`: the prompt was `input + cacheRead`. See [Transcripts](/reference/transcript#tokens-and-the-served-model).

## Prompt size

```text
Argument list too long
```

The CLI takes the prompt as a command-line argument, so it must stay under 128 KiB. A longer one fails the turn with the shell's error.

## Errors

| Situation | Message |
|---|---|
| No `model` | `antigravity() needs a model, e.g. antigravity({ model: 'gemini-3.8-flash-medium' })` |
| No key when the attempt starts | `GEMINI_API_KEY isn't set, so the Antigravity harness can't authenticate. Set it in the environment or .env.local.` |
| A non-Docker sandbox | `The Antigravity harness needs the Docker sandbox: set sandbox: docker() …` |
| The CLI doesn't start | `Antigravity harness failed to start: …` |

## Related

- [Harnesses guide](/guide/harnesses)
- [Egress](/reference/egress)
- [Credential brokering](/concepts/credential-brokering)
- [docker()](/reference/sandbox/docker)
