Claude Code OpenAI Compatible Proxy: The Bridge Register and the Removal Drill
Claude Code bridges expose an Anthropic-format endpoint and translate outward. Register each one, canary what it breaks, and pin allowedProviders every quarter.
Go deeper. Build your own.
Since Sep 29, one managed setting can make Claude Code refuse a session pointed at anything but your gateway, including Anthropic’s own API and a developer’s proxy on localhost. Version 2.1.285 added allowedProviders; set it to ["customEndpoint"] and a session pointed anywhere else is refused. Bridge policy for coding CLIs can now be enforced, which means somebody has to write the list first.
Most of those bridges arrive through a search for a Claude Code OpenAI compatible proxy, and the phrase has the direction backwards. Claude Code speaks the Anthropic Messages, Bedrock and Vertex formats and nothing else. Every tool that lets it reach a GPT or Gemini model exposes an Anthropic-format endpoint to Claude Code and translates outward to the other provider. The translation is where things break, mostly without an error.
This piece gives you a bridge register, three tiers to sort every route into, and a quarterly removal drill that ends with the list pinned in managed settings. It starts with the first-party options, because the cheapest bridge to maintain is the one you never needed.
Anthropic’s gateway line and the Sep 15 to Sep 29 controls
Anthropic’s Other LLM gateways page states the policy in one sentence: “Anthropic doesn’t endorse, maintain, or audit third-party gateway products, and doesn’t support routing Claude Code to non-Claude models through any gateway.” It also warns that a gateway that doesn’t forward what Claude Code sends “breaks the corresponding features, so the gateway product needs to be kept updated as Claude Code evolves.”
Screenshot: Claude Code Docs, “Other LLM gateways” (undated docs page), captured Oct 5, 2026.
The page sits beside the Claude apps gateway and a compatibility guide, and the window’s changes all point the same way. None of them is an enforcement action. They are first-party controls, listed in the Claude Code changelog:
- Sep 15 and Sep 25 (2.1.273, 2.1.283): gateway hint headers such as
x-claude-code-request-class(main, subagent, workflow, compaction, auxiliary),x-claude-code-agent-type,x-claude-code-compactionandx-claude-code-prompt-id. They stay off by default behind a custom base URL “because a proxy that rejects unknown headers would fail the request.” - Sep 18 (2.1.278): auto-mode classifier billing. On Enterprise, API, Bedrock, Agent Platform and Foundry, the server runs auto-mode safety checks inside the session’s own requests “and doesn’t charge for them.” A gateway that “strips or rewrites request headers, drops request fields … or edits responses” pushes the session back to billed classifier requests, with a “this session isn’t eligible” notice.
- Sep 29 (2.1.285): “Added
allowedProvidersmanaged setting to limit which API providers a machine may use.”
On the community side, Claude Code Router (musistudio/claude-code-router) shipped v3.1.0 on Sep 10 and v3.1.1 on Sep 16, and now calls itself “a local model gateway and control plane for coding agents”, fronting Claude Code, Codex, Kimi CLI, OpenCode and others from a local endpoint; v3.1.1 was still the npm latest on Oct 5. Further back, Gemini CLI stopped serving personal accounts on Jun 18; The New Stack reports the successor is Antigravity CLI (agy).
The gateway compatibility guide is the document every bridge owner should read before anything else. The section on screen shows Claude Code changing what it sends by connection method: for a model ID it doesn’t recognize, such as a gateway alias, one method gets thinking with a fixed budget and no effort or context-management fields.
Screenshot: Claude Code Docs, “Claude Code gateway compatibility guide” (undated docs page), captured Oct 5, 2026.
Why a translator in front of an agent is not a chat proxy
A translator in front of a chat window fails where you can see it. In front of an agent it fails inside the loop: a stripped field gets a request rejected mid-task, a missing stream ping aborts a long tool run, and a dropped cache marker multiplies the bill with no error at all. In an unattended lane, nobody sees the stall until the morning.
Build the bridge register for every coding CLI
One row per route, not per product. A route is the path from one client CLI, through one bridge, to one set of upstream models. The illustrative rows below show the columns; the values are examples, not recommendations.
| Client CLI | Bridge (exact repo, version) | Tier | Credential carried | Upstream models | What it breaks | Owner | Removal date |
|---|---|---|---|---|---|---|---|
| Claude Code | Claude apps gateway (in the claude binary) |
1 | SSO via /login |
Claude on Bedrock | Nothing seen; canary green | Platform lead | Review each quarter |
| Claude Code | LiteLLM proxy at a pinned release, /v1/messages route |
1 | LiteLLM key | Claude on Vertex | Check cache_control pass-through |
Gateway owner | Review each quarter |
| Claude Code | musistudio/claude-code-router v3.1.1 |
2 | Own API keys per upstream | GPT, Gemini | Caching, thinking, usage display | Named developer | End of quarter |
| Codex | model_providers entry to org gateway |
1 | env_key variable |
OpenAI models | Responses features not forwarded | Gateway owner | Review each quarter |
| Any CLI | Wrapper carrying a Pro or Max login for others | 3 | Subscription OAuth | Any | Terms | Nobody | Today |
Two rules make the register useful. The bridge column names the exact project and a pinned version, with an owner/repo whenever the name is generic, or the row is incomplete. And the tier belongs to the route: the same LiteLLM proxy is tier 1 when it forwards Claude models and tier 2 when it routes Claude Code to GPT.
Sort every route into one of three tiers
Tier 1, first-party gateway. The Claude apps gateway, or any Anthropic-format gateway that forwards Claude models to a supported upstream; for Codex, a documented model_providers entry that forwards OpenAI models. This is the documented path. It can still break features if it strips fields, so it still gets a canary.
Tier 2, model-swap translator. Claude Code Router, a LiteLLM route to GPT or Gemini, and the several unrelated repositories that share the name claude-code-proxy (1rgs/claude-code-proxy and fuergaosi233/claude-code-proxy share a name and nothing else). The LiteLLM tutorial shows the shape plainly: Claude Code gets ANTHROPIC_BASE_URL=http://0.0.0.0:4000 and ANTHROPIC_AUTH_TOKEN=$LITELLM_MASTER_KEY, and the proxy translates /v1/messages to OpenAI, Gemini, Vertex or Azure. The tutorial lists no feature caveats; Anthropic’s compatibility guide lists many. Run on your own API keys, these routes sit under the docs’ “doesn’t support” line (the terms text quoted below targets consumer-plan credentials), and they are where silent breakage concentrates.
Tier 3, consumer-login wrapper. Anything that carries a Free, Pro or Max login into another app or for other people. Anthropic’s legal and compliance page says it “does not permit third-party developers to offer Claude.ai login into their own applications, or to route requests through Free, Pro, or Max plan credentials on behalf of their users.” The account risk is covered in unofficial AI wrappers; in this register a tier-3 row has one valid removal date, today.
Start with the first-party routes before you register a translator
Before anyone adds a tier-2 row, check whether a first-party route does the job. The Claude apps gateway is built into the claude binary, signs users in through SSO with /login, exports OTLP telemetry, and forwards to the Anthropic API, Bedrock, Claude Platform on AWS, Google Cloud or Foundry. If your organization already runs a gateway, point Claude Code at it and keep Claude models upstream. The connection shape from the docs, with your values filled in:
export ANTHROPIC_BASE_URL="<your gateway URL>"
export ANTHROPIC_AUTH_TOKEN="<token your gateway issues>"
An apiKeyHelper script in settings can supply the token instead of a static variable. Either way, record the credential in the register, because the docs draw a billing line here. With a gateway credential, users’ “claude.ai subscriptions aren’t used or charged.” Setting only ANTHROPIC_BASE_URL keeps the claude.ai login active, and “the subscription’s usage limits and billing apply”; a gateway on that path must forward the OAuth anthropic-beta value or requests fail with 401.
If the real need is a different model, the first-party answer is usually that model’s own CLI as a separate lane, not a translator in front of Claude Code. A bridge is a rented loop part like any other, and own the loop, rent the model covers how to label one.
Fill “what it breaks” from the compatibility guide
Don’t guess the breakage column. Copy it from the compatibility guide and the auto-mode billing page, then confirm each row with the canary in the drill below.
Sorted by how you find out. The silent-cost rows show up on the invoice, not in the terminal.
The two rows that cost money without an error deserve a sentence each. A bridge that strips cache_control produces “No error: the conversation bills as uncached input on every turn.” A bridge that rewrites headers, fields or responses makes auto-mode safety checks fall back to billed classifier requests on plans where they would otherwise be free. Neither shows up as a failed request.
One more row belongs in every register: per the compatibility guide, the fast-mode availability check and the WebFetch safety check call api.anthropic.com directly regardless of ANTHROPIC_BASE_URL. If the bridge is meant to be the only egress, it isn’t; record that in the last-hop register too.
Turn on gateway hint headers only where the canary passes
Hint headers let a tier-1 gateway tell main turns from subagents, workflows, compaction and auxiliary calls, which is what you need to attribute cost by request class instead of by user. They are off by default behind a custom base URL for a good reason: a proxy that rejects unknown headers fails every request. Set CLAUDE_CODE_GATEWAY_HINT_HEADERS=1 for one lane, run the canary from the drill, and only then roll it to the rest. Never turn it on in front of a tier-2 translator you don’t maintain.
Add the Codex and Antigravity rows
Codex reads custom providers from model_providers in config.toml, with a base_url, an env_key and wire_api = "responses" per the Codex advanced config docs. The shape, with illustrative values:
[model_providers.org-gateway]
base_url = "<your gateway URL>"
env_key = "ORG_GATEWAY_KEY"
wire_api = "responses"
The direction flips for Codex. Its bridges must speak the Responses API to Codex and translate outward from there, so community translators for it, such as lidge-jun/opencodex, go in tier 2 with the same exact-repo rule. Any Gemini CLI row that relied on a personal account stopped working on Jun 18; mark it retired and re-check API-key and Vertex rows by hand.
Run the quarterly removal drill
The drill takes one sitting per team, every quarter, and its output is a shorter register. Each step below matches a box in the diagram.
Six steps, one loop a quarter. A bridge that fails its canary or has no owner leaves the register before the pin goes on.
Step 1: Inventory every endpoint override on every machine
List every ANTHROPIC_BASE_URL, ANTHROPIC_AUTH_TOKEN, apiKeyHelper, Codex model_providers entry and OPENAI_BASE_URL, in shell profiles, project settings and user settings. A rough per-machine sweep, illustrative; adjust paths to your fleet:
env | grep -E '^(ANTHROPIC_BASE_URL|ANTHROPIC_AUTH_TOKEN|OPENAI_BASE_URL)='
grep -rnE 'ANTHROPIC_BASE_URL|apiKeyHelper' ~/.claude .claude 2>/dev/null
grep -nA4 'model_providers' ~/.codex/config.toml 2>/dev/null
lsof -nP -iTCP -sTCP:LISTEN | grep -iE 'node|python|litellm|router'
The last line catches local listeners that a developer started by hand. Claude Code Router’s local endpoint and a LiteLLM proxy both show up there.
Step 2: Register or retire each hit
Every hit becomes a row or a removal. A row needs the exact repo and version, the tier, the credential and a named owner before the end of the day. A hit nobody claims within a week gets removed from the machine, and the developer gets a note explaining the first-party route.
Step 3: Canary each bridge
Run the same short canary through every registered bridge after each Claude Code upgrade and at every drill:
- A two-turn session shows cache-read tokens above zero on the second turn.
- One tool call (read a file, run a harmless command) succeeds.
-
/statusshows “Auto mode server: Enabled” on plans where that applies. - The usage display is populated, so rate-limit headers made it through.
-
/contextshows real counts, not approximations, socount_tokensis forwarded. - The gateway log shows zero
400responses for the session.
A failed box is a row in the breakage column, with a date. Two failed boxes on a tier-2 route is a removal.
Step 4: Flip the lane to direct and confirm it still runs
Unset the bridge for one lane, point it at a first-party route, and run the same task. If the lane cannot run without the bridge, the register says so, and the owner writes down what would replace it. A lane that only works through a translator has a single point of failure you chose without a fallback.
Step 5: Pin allowedProviders in managed settings
Once the register is current, pin it. The managed settings entry, as the docs describe it for a fleet that should only use your gateway, is the setting plus the gateway’s ANTHROPIC_BASE_URL in the same file’s env block:
{
"allowedProviders": ["customEndpoint"],
"env": { "ANTHROPIC_BASE_URL": "<your gateway URL>" }
}
With that in place, Claude Code “refuses a session pointed anywhere else, including at Anthropic directly or at a developer’s own proxy”, and accepts ANTHROPIC_BASE_URL only with the value in that file. The 2.1.285 changelog says the setting can limit a machine to “Anthropic API, a custom endpoint, Bedrock, Mantle, Vertex AI, Foundry, Claude Platform on AWS, or a Cloud gateway”; check the settings reference for each value’s identifier before you write it. Then test the pin on one machine by pointing Claude Code at a local translator and confirming the refusal. Managed settings are fleet policy, the same way permission modes are fleet policy.
Step 6: Retire tier-3 rows today
Any row that carries a subscription login for another client or another person comes out the day you find it. Remove the wrapper, revoke the session it held, and move the work to an API key or a first-party gateway. This is the one step with no review period.
The unattended-lane rule
A tier-2 translator never fronts an unattended lane. Overnight jobs, CI agents and scheduled sweeps run on tier-1 routes only, because the failure classes in the chart, from stalls and idle-timeout aborts to uncached billing, are exactly the ones nobody is awake to catch.
Where bridges fail quietly, and the signal for each
Each failure below has a cheap signal. Wire the signal to the register owner, not to a shared channel.
- Uncached billing. Signal: cache-read tokens stay at zero after turn one, or cost per session jumps right after a bridge upgrade.
- Billed classifier. Signal: on API or Enterprise sessions,
/statusshows “Auto mode server: Disabled”, or users report the “this session isn’t eligible” notice. - 400s after a CLI upgrade. Signal: errors cluster in the hours after a Claude Code release, because the bridge strips a new beta field.
- Stalls and aborts. Signal: long tool runs end with idle timeouts only on bridged lanes.
- Blank usage display. Signal: developers on a bridge can’t see their limits, so they hit them blind.
- Shadow proxy returns. Signal: refusal messages from
allowedProvidersin a team channel, which is the pin doing its job and the register missing a row. - Name collision. Signal: a row that says claude-code-proxy with no owner or repo.
For LiteLLM rows, the patch posture lives in the LiteLLM patch clock; for MCP and tool gateways, which are a different layer from model-traffic bridges, see the agent gateway control plane.
Bridges are fleet policy, not a developer preference
A bridge on one laptop is a preference. The same bridge on forty laptops, with a subscription login on three of them and no owner on any, is fleet state nobody chose. The register and the pin turn it back into a decision with a name next to it, and the drill keeps it that way each quarter.
Keep the register next to the other lists that describe what runs in-process and in front of your CLIs. Mods ship as in-process code and get their own manifest in the Claude Code mods fleet manifest. The session-level view of which lane ran through which bridge belongs in the same place you watch every session, the multi-agent command center.
FAQ
Can Claude Code use an OpenAI compatible API?
Not directly. Claude Code speaks only the Anthropic Messages, Bedrock and Vertex formats. Bridges such as Claude Code Router or a LiteLLM proxy expose an Anthropic-format endpoint and translate outward to OpenAI-compatible providers. Anthropic’s docs say it doesn’t support routing Claude Code to non-Claude models through any gateway, so expect silent breakage.
What does allowedProviders do in Claude Code?
Added in Claude Code 2.1.285 on Sep 29, 2026, the managed setting limits which API providers a machine may use. Set to customEndpoint only, Claude Code refuses any session pointed elsewhere, including Anthropic directly and a developer’s own local proxy. It turns a bridge register into enforced fleet policy.
Sources
- Claude Code Docs: Other LLM gateways
- Claude Code Docs: Gateway compatibility guide
- Claude Code Docs: Run Claude Code through a gateway (Claude apps gateway)
- Claude Code Docs: Auto-mode classifier billing
- Claude Code Docs: Legal and compliance
- Claude Code CHANGELOG (2.1.273, 2.1.278, 2.1.283, 2.1.285)
- Claude Code Router, musistudio/claude-code-router
- LiteLLM: Use Claude Code with Non-Anthropic Models
- OpenAI Codex: advanced config, custom model providers
- The New Stack: Gemini CLI replaced by Antigravity CLI (Jun 20, 2026)
