0a33c1b706138d5cff2e419a364a54bfa0a5a34a
SendUserCascadeMessageRequest proto field layout (from JS bundle analysis): - Field 6 is 'images' (repeated ImageData) at the REQUEST level - NOT a Blob sub-message inside ChatMessage (field 2) ImageData proto uses base64_data (field 1) + mime_type (field 2), not raw bytes. The LS was silently ignoring our ChatMessage blob because the field structure didn't match. Also protect MITM modifier from stripping messages containing inlineData (image parts in Google API JSON).
Antigravity Proxy
OpenAI-compatible proxy that intercepts and relays requests to Google's Antigravity language server, impersonating the real Electron webview.
Quick Start
# Build
cargo build --release
# Run (language server must be running)
RUST_LOG=info ./target/release/antigravity-proxy
# Custom port
RUST_LOG=info ./target/release/antigravity-proxy --port 9000
Default port: 8741
Endpoints
| Method | Path | Description |
|---|---|---|
POST |
/v1/responses |
Responses API (primary) — supports stream: true/false |
POST |
/v1/chat/completions |
Chat Completions API (OpenAI compat shim) |
GET |
/v1/models |
List available models |
GET |
/v1/sessions |
List active sessions |
DELETE |
/v1/sessions/:id |
Delete a session |
POST |
/v1/token |
Set OAuth token at runtime |
GET |
/v1/usage |
MITM-intercepted token usage stats |
GET |
/v1/quota |
LS quota — credits, per-model rate limits, reset timers |
GET |
/health |
Health check |
Available Models
| Name | Label |
|---|---|
opus-4.6 |
Claude Opus 4.6 (Thinking) — default |
opus-4.5 |
Claude Opus 4.5 (Thinking) |
gemini-3-pro-high |
Gemini 3 Pro (High) |
gemini-3-pro |
Gemini 3 Pro (Low) |
gemini-3-flash |
Gemini 3 Flash |
Example: Responses API
Sync
curl -s http://localhost:8741/v1/responses \
-H "Content-Type: application/json" \
-d '{
"model": "gemini-3-flash",
"input": "Say hello in exactly 3 words",
"stream": false,
"timeout": 60
}' | jq .
Streaming
curl -N http://localhost:8741/v1/responses \
-H "Content-Type: application/json" \
-d '{
"model": "gemini-3-flash",
"input": "Say hello in exactly 3 words",
"stream": true,
"timeout": 60
}'
Multi-turn (session reuse)
# First message
curl -s http://localhost:8741/v1/responses \
-H "Content-Type: application/json" \
-d '{
"model": "gemini-3-flash",
"input": "What is 2+2?",
"conversation": "my-session-1",
"stream": false
}' | jq .
# Follow-up in same cascade
curl -s http://localhost:8741/v1/responses \
-H "Content-Type: application/json" \
-d '{
"model": "gemini-3-flash",
"input": "Now multiply that by 10",
"conversation": "my-session-1",
"stream": false
}' | jq .
Authentication
The proxy needs an OAuth token. Three ways to provide it:
- Environment variable:
export ANTIGRAVITY_OAUTH_TOKEN=ya29.xxx - Token file:
echo 'ya29.xxx' > ~/.config/antigravity-proxy-token - Runtime API:
curl -X POST http://localhost:8741/v1/token -d '{"token":"ya29.xxx"}'
Stealth Features
- TLS fingerprint: BoringSSL with Chrome JA3/JA4 + H2 fingerprint via
wreq(version auto-detected) - Protobuf: Hand-rolled encoder producing byte-exact match to real webview traffic
- Warmup: Mimics real webview startup RPC calls
- Heartbeat: Periodic keep-alive matching real webview lifecycle
- Jitter: Randomized polling intervals to avoid automation fingerprint
- Session reuse: Cascades are reused for multi-turn, matching real webview behavior
- Version detection: Auto-detects Antigravity/Chrome/Electron versions from installed app
MITM Proxy
Built-in TLS-intercepting proxy captures real token usage from LS ↔ Google/Anthropic traffic. Disabled with --no-mitm.
Setup
# 1. Start proxy (generates CA cert automatically)
RUST_LOG=info ./target/release/antigravity-proxy
# 2. Install wrapper (patches LS binary to route through MITM)
sudo ./scripts/mitm-wrapper.sh install
# 3. Restart Antigravity — done!
# Check status
./scripts/mitm-wrapper.sh status
# Uninstall
sudo ./scripts/mitm-wrapper.sh uninstall
Usage Stats
curl -s http://localhost:8741/v1/usage | jq .
Standalone Language Server
Launch an isolated LS instance for experimentation:
# Basic test (starts, checks quota, exits)
./scripts/standalone-ls.sh
# Foreground mode (stays alive)
./scripts/standalone-ls.sh --fg
# With MITM traffic interception
./scripts/standalone-ls.sh --mitm
# Capture a clean traffic snapshot
./scripts/standalone-ls.sh --snapshot
# Snapshot with custom prompt
./scripts/standalone-ls.sh --snapshot --prompt "Explain quantum computing"
The standalone LS shares the main Antigravity app's OAuth (via its extension server) but has its own port, data directory, and cascades.
Traffic Snapshots
The --snapshot flag captures all HTTP/2 traffic and formats it into a clean, color-coded report:
══════════════════════════════════════════════════════════════════════
STANDALONE LS TRAFFIC SNAPSHOT
══════════════════════════════════════════════════════════════════════
▸ Outbound Connections
→ antigravity-unleash.goog (Feature Flags)
→ play.googleapis.com (Telemetry)
══════════════════════════════════════════════════════════════════════
antigravity-unleash.goog — Feature Flags
══════════════════════════════════════════════════════════════════════
→ POST /api/client/register
authorization: *:production.e4455...
unleash-appname: codeium-language-server
Body (561 bytes, JSON):
{"appName":"codeium-language-server","instanceId":"..."}
Architecture
graph LR
A[Your App<br/>OpenAI SDK] -->|HTTP| B[Proxy<br/>:8741]
B -->|gRPC| C[Language<br/>Server]
C -->|HTTPS| D[Google /<br/>Anthropic]
E[MITM Proxy<br/>:8742] -.->|intercept| D
C -.->|routed via| E
CLI Flags
antigravity-proxy [OPTIONS]
Options:
--port <PORT> API server port (default: 8741)
--no-mitm Disable MITM proxy
--mitm-port <PORT> Override MITM proxy port (default: auto)
License
Private. Do not distribute.
Languages
Rust
98.6%
Shell
0.7%
C
0.4%
PowerShell
0.3%