OpenAI-compatible wrapper around the logged-in official Antigravity CLI.
- Calls
agy --print <prompt>throughsubprocess.run. - Reads the newest Antigravity conversation SQLite DB because
agystdout is empty in current builds. - Decodes protobuf
steps.step_payloadwith a small dependency-free wire decoder. - Exposes:
POST /v1/chat/completionsGET /v1/models
- Supports fake streaming by sending heartbeats while
agyruns, then chunking the completed answer into OpenAI SSE events.
This wrapper does not handle Google authentication. You must set up the official CLI yourself before running it:
- Install the Antigravity CLI (
agy) yourself. This project does not bundle, download, or redistribute it. - Log in yourself (
agyGoogle OAuth). The login lives entirely insideagy's own local state. - The wrapper only ever runs
agy --print <prompt>as a subprocess and reads the conversation SQLite file thatagywrites locally. It never reads, writes, stores, transmits, or validates your Google credentials or OAuth tokens.
- Two unrelated layers — don't confuse them:
- Google OAuth — owned 100% by
agy. This project has zero OAuth code. AGY2API_KEY— this wrapper's own Bearer password, only gating who may call your local HTTP endpoint. Unrelated to Google.
- Google OAuth — owned 100% by
- Quota is yours. Every request consumes your logged-in
agyquota. Anyone who can reach the endpoint with a valid Bearer key spends your quota. - Keep it local. The server binds
127.0.0.1by default. Do not setHOST=0.0.0.0/ expose it publicly unless you set a strongAGY2API_KEYand accept that callers run prompts under your Google account.
This is an unofficial personal-interop tool. It is not affiliated with, endorsed by, or supported by Google. You are responsible for using it within the Antigravity / Gemini Terms of Service. To stay on the safe side:
- Personal, local, single-user only. Do not share the endpoint, share the Bearer key, or run it as a public proxy. Doing so redistributes your personal Google quota to third parties — the clearest ToS violation.
- No commercial use or resale of the free-tier quota.
- Do not expose it to the network. The server refuses to bind a non-loopback
address unless you set
AGY2API_ALLOW_REMOTE=1(don't, unless you fully understand the consequences). - Human-paced volume. Concurrency is capped at 1 by default
(
AGY2API_MAX_CONCURRENCY). Don't drive high-volume or mass-parallel traffic. - Don't use outputs to train competing models, and don't strip safety filtering — pass prompts through as-is.
- The tool only reads your own local conversation database on your own machine; it does not break encryption or access anyone else's data. Keep it that way.
cd agy2api
python -m venv .venv
.\.venv\Scripts\pip install -r requirements.txtMake sure agy is installed and already logged in (see Prerequisites).
Windows (recommended): start.bat — a one-click launcher that checks agy
login, sets up the venv, then asks which mode to run:
| Choice | Mode | Best for |
|---|---|---|
1 (default — just press Enter) |
Stateful | ongoing chats / roleplay; only the new turn is sent each request, so long chats are much less likely to hit the upstream cutoff |
2 |
Stateless | simple / one-off requests; full history resent each time |
Set AGY2API_STATEFUL in the environment beforehand (1/0) to skip the
prompt. See Stateful mode for what stateful changes.
Manual / non-Windows:
$env:AGY2API_KEY="pwd"
python server.py # stateless by default; set AGY2API_STATEFUL=1 for statefulDefault URL: http://127.0.0.1:7862.
curl http://127.0.0.1:7862/v1/chat/completions \
-H "Authorization: Bearer pwd" \
-H "Content-Type: application/json" \
-d '{"model":"gemini-3.5-flash","messages":[{"role":"user","content":"reply with exactly PONG"}]}'AGY_PATH: CLI executable path, defaultagyAGY_WORKDIR: working directory foragy, default project parentAGY_CONVERSATIONS_DIR: Antigravity conversations directoryAGY_TIMEOUT: per-request budget seconds, default300(also passed to agy as--print-timeout; the subprocess is killed only 20s later as a hard backstop)AGY2API_KEY: bearer token, defaultpwd(empty disables auth)AGY_MODELS: comma-separated model listAGY_POLL_INTERVAL: DB-readiness poll seconds, default0.25AGY2API_CHUNK_SIZE: fake-stream chunk size in chars, default10AGY2API_STREAM_DELAY: inter-chunk delay seconds for typing effect, default0.03AGY2API_EXPOSE_REASONING: emitreasoning_content, defaulttrueAGY2API_MAX_CONCURRENCY: max concurrent agy runs, default3AGY2API_CLEANUP_DB: delete each run's conversation DB + brain dir after reading, defaulttrueAGY2API_SUPPRESS_AUTOUPDATE: keep agy'slast_check.timestampfresh so its background updater never spawns theagy --bg-updaterchild (a console window that flashes despiteCREATE_NO_WINDOW), and so agy doesn't silently auto-update and change the DB/protobuf layout the parser relies on, defaulttrueAGY2API_STATEFUL: experimental — keep a persistentagyconversation per chat and send only the new turn each request (instead of resenting the full history every time). Smaller per-turn payloads finish faster and are less likely to trip the upstream ~60s connection cutoff on long chats. Defaultfalse. See Stateful mode for the isolation model.AGY2API_MAX_SESSIONS: cap on live stateful conversations (LRU-evicted above this), default200. Only meaningful withAGY2API_STATEFUL=1.AGY2API_STATEFUL_HOME: isolatedagyhome directory used only in stateful mode, defaultstateful_home/inside the project (gitignored). See Stateful mode.AGY2API_ALLOW_REMOTE: allow binding a non-loopback host, defaultfalseHOST: bind address, default127.0.0.1(see Auth & Privacy / Compliance)PORT: server port, default7862
AGY2API_STATEFUL=1 keeps one persistent agy conversation per chat and
forwards only the new turn each request, instead of re-sending the full
history. This shrinks per-turn payloads and makes long chats far less likely
to hit the upstream connection cutoff. (start.bat selects this mode by
default.)
Because the OpenAI protocol is stateless, this is mapped heuristically: the
incoming message list is fingerprinted, and if its prefix matches a chat we've
already forwarded, only the trailing new turn is sent to the existing
conversation via agy --conversation <id>.
Stateful mode runs agy inside its own home directory (default
stateful_home/ inside this project, gitignored; override with
AGY2API_STATEFUL_HOME). It does this by setting USERPROFILE to that path for
every agy subprocess, so agy's entire data tree — conversations, brain,
cache — lives there and never touches your real ~/.gemini. Conversations
you open manually in the agy TUI are in a different directory and are not
affected.
The startup/exit disk wipes (below) therefore only ever delete agy2api's own sandbox files.
agy stores its OAuth token in the OS credential store (Windows Credential
Manager), not in the home directory. That store is system-scoped, so the
sandbox automatically inherits your existing agy login — no separate login
is required. As long as agy works for you normally (you've logged in via
the TUI at least once), it works in the sandbox too. start.bat checks for
this credential before launching.
A persistent conversation owns its DB, so it is not deleted after each run.
To stop those files accumulating, stateful mode wipes its own sandbox
conversations directory (every *.db, its SQLite sidecars, and every
brain/<id>/ directory under the sandbox) on two occasions:
- on startup, because the in-memory session index starts empty and any
.dbleft by a previous run is an unreachable orphan; and - on any process exit (graceful shutdown, Ctrl-C,
sys.exit) — a last-resortatexithook guarantees it even when the graceful-shutdown path doesn't fire.
This dual wipe means stateful memory never survives a restart, by design. Disk usage cannot grow unbounded.
- No true streaming: the CLI writes the final result into SQLite after completion.
- Latency is usually several seconds because each request starts an
agyrun. - Antigravity is an agent and may use tools for complex prompts.
- The protobuf fields are reverse-engineered and may need updates if
agychanges its cache schema. - Long replies can fail mid-generation with
agy upstream error: ... connection forcibly closedwhen a proxy/VPN drops the long-lived connection to Google (e.g. a ~60s connection cap). The reasoning phase dominates generation time, so for long chats prefer a low-reasoning model (e.g.gemini-3.5-flash-low) to finish sooner, and/or route*.googleapis.comthrough a proxy that allows long-lived connections (or direct).
agy2api parses agy's internals by reverse engineering and pins agy (auto-update suppressed), so a new agy build can break it. A scheduled GitHub Actions workflow (.github/workflows/agy-version-watch.yml) polls agy's auto-updater endpoint weekly for the latest stable version and, on a bump, opens an issue with a re-validation checklist (DB schema, protobuf fields, flags, env behaviour). There is no public per-version agy-CLI changelog to keyword-scan, so it's a version-bump alert plus a manual checklist — not a diff.
Apache-2.0. This project is written from scratch and does not copy gcli2api code.