FS
← Back
● OSS CONTRIBUTION — Active

Claude Code Router

Open-source contribution to claude-code-router — extended the cli:// provider system to support Antigravity (AGY) CLI as a local, API-key-free backend. Built a new transformer, subprocess runner with SSE streaming, and cross-session conversation continuity.

TypeScriptFastifyNode.jsSSENDJSONSQLite
AGY CLINew Transformer
cli://URL Scheme
SSE StreamReal-time Output
Session MapConversation Continuity

// Context

claude-code-router is an open-source proxy that intercepts ANTHROPIC_BASE_URL and routes Claude Code requests to alternative LLM backends. The existing cli:// URL scheme supported spawning local CLI tools as providers. I extended this to integrate agy — the Antigravity CLI — as a fully functional provider with streaming output and persistent sessions.

// What I Built

AgyCLITransformer: New transformer that adapts AGY CLI output to Anthropic's message format. Handles both SSE streaming (text_delta events) and non-streaming paths. Strips the MEMORY INJECTED header block that AGY prepends to every response — split on the ━━━ delimiter, discarding the first two segments so only assistant text reaches Claude Code.
runAgyCLI subprocess runner: Spawns agy as a child process per request, pipes the prompt via stdin, then closes stdin to signal completion. Deletes ANTHROPIC_BASE_URL from the subprocess env to prevent recursive routing back through CCR. Reads stdout as a line-by-line SSE stream and forwards events in real time.
Session continuity via .db mtime scan: AGY writes a SQLite conversation file to ~/.gemini/antigravity-cli/conversations/ after each turn. The runner scans for the most recently modified .db, maps the CCR sessionId to that AGY UUID, and passes --conversation=<uuid> on subsequent turns — keeping multi-message exchanges in a single AGY conversation.
cli:// URL scheme (upstream contribution): Extended routing and URL validation to recognise cli://command as a valid api_base_url. The router spawns the referenced binary instead of making an HTTP request — enabling any local CLI tool to act as an LLM provider with zero config overhead.

// Architecture

Claude CodePOST /v1/messagesrouter middlewareAgyCLITransformer
runAgyCLI (spawn + stdin close)agy binarySSE stdoutAnthropic format back
session map:CCR sessionId.db mtime scan--conversation=<uuid>
cli:// prefix bypasses HTTP entirely — no API key, no network call

// Key Engineering Decisions

Strip MEMORY INJECTED via delimiter split, not line filter: AGY prepends a MEMORY INJECTED block separated by ━━━ lines. A line-by-line filter broke on multi-line memory entries. Splitting the full output on ━━━ and taking parts.slice(2) handles the block atomically regardless of its internal structure.
Delete ANTHROPIC_BASE_URL from subprocess env: Without removing this variable, agy inherits it from the CCR process and routes its own requests back through CCR — an infinite loop. Stripping the key before spawn breaks the cycle while leaving all other env vars intact.
Close stdin to signal end-of-input: AGY reads the prompt from stdin and waits for EOF before responding. Not closing stdin causes the process to hang indefinitely. Calling subprocess.stdin.end() immediately after writing the prompt is the minimal fix.
mtime scan over process-level session tracking: AGY does not expose the conversation UUID synchronously. Scanning ~/.gemini/antigravity-cli/conversations/ for the most recently modified .db after each response ties the CCR session to the correct AGY conversation without requiring changes to AGY internals.