Skip to content

Model Gateway

Model Gateway adds subscription-backed GPT and Grok models to Claude Code. Claude Code v2.1.129+ can show those gateway models in its /model picker. Claude models keep using Anthropic normally.

Run these in Claude Code:

/plugin marketplace add Eigenwise/eigenwise-toolshed
/plugin install model-gateway@eigenwise-toolshed --scope project

Reload the plugin, then start the Model Gateway skill:

Set up Model Gateway for me.

The skill runs setup with project-local wiring, installs and starts the local gateway, checks your subscription login, and confirms the current project’s .claude/settings.local.json. If setup asks for login, complete the browser sign-in, then let Claude run setup again to finish and confirm the project wiring.

After the wiring is confirmed, fully restart the Claude Code process for that same project. A plugin reload alone does not reload the picker cache or the settings in the new process. Select a gateway model only after that restart.

Model Gateway writes ANTHROPIC_BASE_URL to .claude/settings.local.json, never the committed .claude/settings.json. That keeps your local gateway endpoint out of other people’s checkouts. You can opt into one shared fallback URL in ~/.claude/settings.json, but a project’s local setting wins. model-gateway doctor marks the effective source and calls out conflicting gateway modes.

A Claude alias pin applies to every project already registered as wired. SessionStart checks those projects again on every pin refresh, so a newer shipped default or CLI alias reaches all of them, not only the project you opened. Model Gateway updates only gateway-owned pin values, tells you about any user-owned value it skipped, and prunes missing project directories from the registry. Restart each affected open Claude Code session before its /model alias reflects the new pin.

For a direct recovery command, use node ~/.claude/model-gateway/model-gateway.js <command>. SessionStart writes this version-independent launcher from Claude Code’s installed-plugin registry, so it follows upgrades and uses the highest remaining installed version after an uninstall or downgrade.

A process ANTHROPIC_BASE_URL has higher precedence than either settings file. If doctor or SessionStart says it shadows a wired file, Model Gateway is bypassed. If you control the Claude Code CLI launch, correct or unset that value, then restart. If the host replaces it, use the supported Claude Code CLI on the wired project instead. Model Gateway does not support Desktop routing under forced overrides on Windows or macOS, and settings, parent, or User-scope edits cannot be promised to win.

You may need to complete a browser sign-in or restart Claude Code. Claude will ask only when either step is actually needed.

The gate guards router health only (owned listener, installed serving version and /healthz); a Codex-only auth or upstream failure never blocks a prompt and stays visible in doctor and per-request errors. A healthy current router costs one local health request (750 ms timeout) and PID-record reads, without loading the recovery CLI or taking its lifecycle lock.

Wiring now installs readiness hooks alongside the endpoint in the same settings file. Project wiring stays in .claude/settings.local.json and adds no global hooks. The opt-in user fallback gets its hooks in user settings. These hooks use the stable launcher and don’t require the plugin to be enabled in the project.

Maintenance setup --preserve-wiring preserves intentional stop even if acquisition fails, and never starts a stopped gateway. Intentional stop is cleared once an explicit start or setup creates the supervisor process and records its PID; a launch that fails before that, including a spawn that yields no PID, leaves it stopped, and a PID-record failure after a successful spawn leaves both the marker and the process, so the next automatic path still refuses. Run the stable launcher with setup --preserve-wiring after updating to migrate registered projects and existing user fallback without wiring a new directory. ensure also migrates existing wiring. Restart Claude Code after migration so it loads those settings. The launcher resolves the installed version from the plugin registry, so old cache removal and installed downgrades don’t pin hooks to a deleted path.

On startup or resume, SessionStart attempts early recovery. SessionStart cannot block. Before a submitted prompt reaches the model, UserPromptSubmit checks readiness and tries to recover. Its child has a 25-second deadline, with a 35-second hook timeout and onFailure: block. Failed recovery blocks locally with instructions; fix the reported issue and resubmit the prompt.

Use node ~/.claude/model-gateway/model-gateway.js recover without model access to restore readiness without settings, pin or cache maintenance. stop persists across reboot and upgrades; automatic recovery honors that choice. Explicit start or setup resumes it. A healthy gateway is left running, including active streams.

Run doctor to see hook presence, the persistent stop file, startup failure evidence and logs under ~/.claude/model-gateway/logs/. Missing installation, unavailable authentication and unknown port ownership require local attention; recovery leaves foreign listeners untouched. Keep auth files and the control token private.

Recovery is a cheap no-op before CLI resolution when the effective endpoint isn’t Model Gateway, even without an install. An absent plugin entry leaves recovery active. An explicit effective enabledPlugins: {"model-gateway@eigenwise-toolshed": false} disables recovery without starting, stopping or touching gateway state, and prints how to re-enable the plugin or unwire. Project-local settings win over project settings, then user settings; process endpoint env wins over settings endpoints. doctor reports explicit plugin disable. Host-disabled hooks remain disabled. A supervisor dying inside an active turn, subagent, compaction or discovery step is outside prompt-gate coverage. No OS service or scheduled task is installed. Simulated process recovery tests don’t prove an actual reboot or real-provider inference.

Before uninstalling the plugin, run env --remove in each wired project and env --remove --write-user if you opted into user fallback. This removes only owned wiring and hooks. Removing the plugin first leaves a gate that reports a missing install until you restore it or remove its owned wiring.

Setup now requires the proxy release’s checksum file and stops before extraction if verification fails. Keep that refusal in place and report the error rather than running the downloaded archive manually.

To find the latest proxy release, setup asks the GitHub API. It uses your GitHub login when one is available: the GH_TOKEN or GITHUB_TOKEN environment variable, or else the GitHub CLI’s gh auth token. GitHub allows only 60 anonymous API calls an hour per IP address, and a machine running several agents can use those up. Setup then fails with “GitHub API returned 403”. The fix is to sign in with gh auth login or set GH_TOKEN, then run setup again. The token goes only to the GitHub API. It is never sent with the proxy download, and never printed.

Gateway restart and drain commands use a private local control token automatically. Do not share the ~/.claude/model-gateway/control-token file. After an update, fully restart Claude Code so it uses the current lifecycle protocol. A hot worker update is limited to the same plugin cache; switching between a development checkout and an installed copy requires stopping the old supervisor through its bundled CLI first. The supervisor rejects every request carrying an Origin header or a foreign Host header with HTTP 403, including inference requests. Origin-less requests using 127.0.0.1:<port> or localhost:<port> still work. The compatibility listener also accepts api.anthropic.com, with its listener port optional. Relayed request bodies above 64 MiB return HTTP 413 before reaching the worker. The separate proxy’s inference endpoint and programs running as the same OS user remain outside these protections.

If a client disconnects while uploading a request, the public shim relay discards that upload without stopping the supervisor or interrupting other streams. The internal RC-compatibility control endpoint uses the same guarded reader and 64 MiB limit. Upload failures never reach the worker or count as worker failures. A non-disconnect read failure gets a non-retryable HTTP 400 only if the response is still writable. This protection is limited to incoming uploads: disconnecting after an upload completes does not guarantee cancellation of provider work or charges.

In Claude Code v2.1.129+, open /model and choose a row labeled From gateway. Claude Code only refetches gateway discovery with an API-key credential. Model Gateway writes its discovery cache for OAuth subscriptions, and new rows appear after a full Claude Code restart. /reload-plugins does not reload the picker cache. The cache is written only from a model list the proxy actually answered. While the proxy is unreachable, for example in the moment after the gateway starts, the gateway serves a short built-in list, keeps the previous cache, and status reports fallback catalog (proxy unreachable).

Updating Toolshed never wires a project. Only setup or env --write-project run inside a project wires it.

  • claude-gpt-*[1m] uses your ChatGPT/Codex subscription. MODEL_WINDOW_POLICY in Model Gateway’s runtime is the authority for every gateway picker row. GPT-6.1 Sol, GPT-5.6 Sol, Terra, Luna, and GPT-6 Astra are measured rows; other Codex proxy rows use its explicit unmeasured 920k default until measured. GPT-6.1 Sol is the default Codex model; GPT-6 Astra is reserved for frontier or high-stakes tickets.
  • A [1m] alias gives Claude Code a 1M client window, but a lower explicit autoCompactWindow still wins. An autoCompactWindow is one number for the whole session, so it caps Claude rows too; the Codex cost cap lives in context-window instead (see Context window and cost). The alias is removed before forwarding to the backend and does not promise a 1M backend input limit. Use /context to inspect the selected model and effective cap.
  • claude-grok-4.5[1m] uses your Grok subscription when the Grok CLI is installed and signed in. Its measured backend window is 500k. The shared synthetic-413 sentry returns Claude Code’s compaction signal 40k tokens before that backend limit if the client has not compacted first. The alias is removed before requests reach the backend.
  • Claude models keep using Anthropic.

Codex rejects some JSON Schema regex Unicode property escapes, including \p{Cc} and \P{Cf}. When a deferred tool resolves, Model Gateway can make a narrow Codex-only compatibility copy of its input_schema. It supports a missing dialect or Draft 2020-12, and only a pattern on the documented positive paths: properties, compatible patternProperties values, additionalProperties, items, prefixItems, allOf, anyOf, dependentSchemas, propertyNames, and unevaluatedProperties or unevaluatedItems. Each real property atom has to be a standalone member of a negated character class, with no range, set syntax, capture, backreference, or negative regex context. The lexer consumes every allowed escape as one token, so escaped parentheses, brackets, and backslashes stay literal data rather than group or class structure. The copy removes only that atom and keeps every other regex byte. Unsupported affected schemas return a local 400 with the tool name, JSON Pointer, and reason code, before any request is forwarded or sent to another provider. Claude Code still holds the original tool schema and Anthropic requests stay byte-identical.

Claude Code’s Agent tool takes an optional model override, but that parameter only accepts sonnet, opus, haiku, or fable — a fixed list on the host, independent of any gateway or installed plugin. Passing a gateway id there (for example claude-gpt-5.6-luna[1m]) is refused.

To send one subagent through a specific gateway model, skip that parameter and give the subagent its own definition file instead. Claude Code reads model: frontmatter from a subagent definition and accepts a full model id there (see Claude Code’s subagent docs):

---
name: luna-reviewer
description: Reviews code changes using the GPT-5.6 Luna gateway model.
model: claude-gpt-5.6-luna[1m]
tools: Read, Grep, Glob
---
Review the diff for correctness and report findings.

Save that as .claude/agents/luna-reviewer.md, then start a new Claude Code session before invoking it — definitions are read at session start, so a session already running won’t see a file you just added. Invoke it with subagent_type: "luna-reviewer" and no model argument in the call: the invocation param takes precedence over frontmatter when set, so leaving it out is what lets the frontmatter’s gateway id apply.

This works with Model Gateway alone; Sidequest isn’t required. Sidequest’s own execution subagents use this same frontmatter path internally, pinned to its claude-codex-auto id, which is reserved for Sidequest’s own dispatch marker system. A concrete gateway id like the one above needs no such marker. The frontmatter contract above and Model Gateway’s routing for a concrete id are both confirmed; spawning a custom agent end-to-end through this path hasn’t been separately verified here, so treat it as documented, not guaranteed.

Claude Desktop has its own native Gateway configuration, separate from the Claude Code CLI settings above. You can point it at Model Gateway’s endpoint, but installed Desktop 1.49585.0 validates every Gateway model ID on the client side and rejects any gpt, codex, or other non-Anthropic family marker before it reaches the picker or a session. This applies to both an explicit model entry you add yourself and an ID Desktop discovers automatically; a trailing [1m] is stripped first and does not change the outcome. Only a genuinely Anthropic-backed route, such as a real Claude alias, is usable there.

This is a Desktop-side restriction, not a Model Gateway bug, and there is no supported workaround: no Anthropic-named alias to disguise a Codex or Grok route, no binary patch, no credential or auth substitution, no TLS interception, no global env or hosts trick. The Claude Code CLI remains the verified way to use gateway models. VS Code success has been reported by users but is not independently verified here. This limitation is specific to the installed Desktop version and can be revisited if a future release removes the model-family filter.

Claude keeps its native 1M window. OpenAI bills Codex input above 272k tokens at 2x. Model Gateway saves one policy per backend in ~/.claude/model-gateway/context-window.json, shared by the orchestrator and executors. Existing installations keep their current policy until you configure a change.

Backend Default window Compaction
Claude full Native 1M window through [1m] aliases; native engine headroom applies
Codex 272000 Legacy trigger 187000 unless you save a direct maximum
Grok full Backend window minus 40000 unless you save a lower direct maximum

Show or set windows:

Terminal window
node ~/.claude/model-gateway/model-gateway.js context-window
node ~/.claude/model-gateway/model-gateway.js context-window --claude full --codex 272000 --grok full

The window flags still accept full or their supported whole token counts up to 1,000,000. CODEX_GATEWAY_CONTEXT_WINDOW applies only when no Codex window is saved. /v1/models advertises the window cap and keeps [1m] picker ids. Claude Code’s discovery cache retains only model ids and names, so the gateway’s synthetic-413 sentry enforces Codex and Grok compaction.

Set a direct Codex or Grok maximum before compaction:

Terminal window
node ~/.claude/model-gateway/model-gateway.js context-window --codex-compact-at 242000
node ~/.claude/model-gateway/model-gateway.js context-window --grok-compact-at 400000
node ~/.claude/model-gateway/model-gateway.js context-window --codex-compact-at cap

These flags save positive whole token counts in compactAt.codex or compactAt.grok. cap removes that explicit entry and restores the legacy policy. Changing a window preserves saved maxima. The 242000 example leaves the Codex 272000 cap unchanged. Explicit maxima have no hidden 85000 subtraction: the effective trigger is limited by the requested number, the window cap when present, and the actual backend window minus 40000. status, doctor, and catalog notes report requested and effective numbers, the backend window, and the limiting source. A saved maximum overrides CODEX_GATEWAY_COMPACT_TRIGGER; its ignored value is reported without changing the environment.

A direct maximum is a compaction trigger, with one-turn detection delay. The gateway records input usage after each response, per session and agent, and sends a synthetic overflow on that agent’s next request when usage passed the trigger. A subagent never inherits its parent’s or a sibling’s crossing.

Compaction requests bypass the synthetic sentry. After it fires, retries remain admitted until a completed ordinary response still reports usage above the trigger; the next ordinary request is refused again with that observed count. Stream chunks, failed or incomplete requests, and high-usage compaction completions do not rearm it. Successful compaction that lowers usage below the existing headroom watermark still resets the latch. State remains separate for each session, agent, and model. This prevents a failed compaction from disabling later checks; it does not establish the original failure’s cause. Codex JSON rearms only for ordinary end_turn, stop_sequence, or tool_use responses; a tool handoff completes that assistant response. Null, missing, unknown, truncated, paused, and refused stop reasons leave the current attempt latched. This stop-reason rule applies only to sentry rearming; transport success, readiness recovery, and route telemetry keep their existing semantics.

Every overflow error (HTTP 413 request_too_large) ends with what was too large and what fixes it, for example [model-gateway: phase first_turn, refused by upstream; request 912344 bytes, 250000 tokens from upstream, limit 242000 tokens; recovery: nothing to compact, ...]. A first_turn overflow has nothing to compact, so the fix is a smaller first prompt (for a dispatched subagent, a smaller briefing) or a model with a larger window. A continuation compacts and retries. A compaction overflow means the summary request itself is too big. The same values appear in the error’s overflow object and as overflow_* attributes on the codex_gateway.route span. The crossing turn and the compaction request can still exceed 272k and pay double, including with 242000 configured. This setting gives no per-request price guarantee.

With no explicit maximum, the legacy cap policy still subtracts 85000 (two budgeted 40000-token turns plus a 5000-token compaction prompt). Thus Codex’s default trigger stays 187000. Gateway window caps keep their existing 185000 minimum; direct maxima have no 100000 floor. The actual provider capacity remains authoritative.

Claude’s supported separate number remains --claude <tokens|full>, synced through existing project-wired autoCompactWindow settings. A numeric value requires a project wired at project scope. Gateway-owned values are synced; unrelated user-owned values stay untouched. A lower session-wide native window can also bound gateway models. Current native engine headroom and the exact direct Claude trigger are unverified, so --claude-compact-at and compactAt.claude are refused without writing. Same-model main/subagent thresholds are unverified; this policy applies one number per backend and uses no role guessing.

Configuration is read at gateway startup. After deliberately changing it, stop the gateway and run ensure; restart open Claude Code sessions for native-window or picker changes. Updating or installing the plugin alone never adopts the 242000 example.

The shim lists the upstream Anthropic catalog before Codex and Grok models. One normal Anthropic turn through a wired gateway starts a background refresh when the one-hour catalog cache is absent or stale. Authenticated discovery also refreshes it. Only allowlisted OAuth or API-key headers are used, in memory for that call. Successful refreshes write Anthropic rows first into ~/.claude/cache/gateway-models.json, followed by Codex/Grok rows. ensure also merges cached Anthropic rows and updates forward-only default pins. Failures keep previous rows; doctor shows the last refresh error. After one normal Claude turn, check that the picker cache contains claude-fable-5-2 if upstream advertises it, then fully restart Claude Code to load the new picker rows. Credentials are never saved.

Behind the gateway, Claude Code lists the picker rows Anthropic’s own servers send instead of its built-in Fable row, and that row can still point at an older Fable while being labelled just “Fable”. Model Gateway can’t change that row, so a wired project gets its own “Fable” row on the current Fable (through ANTHROPIC_CUSTOM_MODEL_OPTION), and the older server row shows up as “Fable 5.1 (previous)”. Your Codex and Grok rows stay. Nothing to do after updating except restarting Claude Code. doctor checks that the Fable, Opus and Sonnet rows match what Claude Code shows without the gateway, and SessionStart repeats that check once per Claude Code version and tells you if it fails.

SessionStart and updates advance Opus, Sonnet and Fable pins from the cached same-family catalog, without adopting older or retired versions. Registered projects get gateway-owned pin updates; restart their open Claude Code sessions afterward. An explicit override always wins. Ask Claude to remove a Fable override with pin --fable default when you want catalog updates again. status and doctor show catalog age, shipped/detected/catalog/override pin sources and the newest family ids. A lagging override is called out rather than changed.

There are no routine Model Gateway commands to remember. The shim supervisor checks the proxy’s /v1/models endpoint while it runs and confirms a failed probe through a fresh connection before recovering an unavailable proxy with bounded backoff. It leaves a healthy proxy alone. If a session survives a plugin update, its older plugin copy leaves the newer shim running and asks you to reload plugins or restart Claude Code. Claude handles setup, updates, authentication checks, model discovery, and settings repair through the skill.

SessionStart launches a missing supervisor outside the hook’s process tree, then waits no more than 12 seconds inside its 30-second hook budget. A slow proxy keeps starting in the background. Claude asks you to retry the Codex model in a few seconds instead of holding the session-start hook open.

Setup and updates wait up to 42 seconds (the 30-second drain timeout plus 12) for a restarted supervisor. On a heavily loaded machine that can run out while the new supervisor is still coming up. If its process is still alive and the shim wrote no failure reason, setup prints a warning with the supervisor’s PID and exits successfully, so update-toolshed doesn’t count it as a failure; run status a minute later to confirm it is running-ours. A supervisor that died during the wait, or a shim that recorded why it failed, still fails setup.

status, doctor and ensure share one probe of the shim, so they print the same state: running-ours (with the version it serves), running-foreign (a listener from another install, or one whose owner can’t be identified), starting, or stopped. ensure treats a running-ours shim at the installed version as done, and gives a starting one its startup window instead of binding a second supervisor against it. While a proxy the supervisor just started is still warming up (it holds its port before /v1/models answers), recovery waits up to 30 seconds before replacing it. On Windows the port owner is read from netstat’s address and PID columns, so a German or French UI language no longer hides it and upgrades replace the running shim.

After confirming a same-install current-version healthy shim, startup still cleans up conclusively owned stale workers under the install lifecycle lock. A stale older-version orphan needs a saved birth record in ~/.claude/model-gateway/worker-births/ matching its PID, start time, command, install root and version, plus proof that its recorded birth parent has exited or been replaced. Current ancestry must exclude the serving supervisor; reparenting alone is not proof of ownership. The healthy worker and active streams survive concurrent ensure calls. Missing records, unreadable identities, foreign installs and uncertain or cyclic ancestry are left untouched. Cleanup rechecks identity immediately before requesting single-target termination, without tree termination or escalation (Node’s native termination is not graceful on Windows), and removes only the unchanged birth record after confirming the old identity is absent. Deliberate stop/restart behavior is unchanged. Ownership probes, settings/cache refresh and version reconciliation still run, so ensure is not globally read-only and these protections do not make every PID-record update transactional.

When the gateway disappears or restarts, ask Claude to run doctor. It names ~/.claude/model-gateway/logs/lifecycle.jsonl and says whether it found an observed supervisor, worker, or proxy exit. The bounded records include PIDs, orderly setup/stop/restart requests, signals, and recovery outcomes. A force-killed supervisor or OS termination can leave no final record, so a missing exit entry does not prove an orderly shutdown. If the Claude CLI alias resolves an older native model than the shipped fallback, the shipped fallback wins, and doctor and pin name the older id the CLI resolved next to it. A saved pin --<alias> override still wins over both.

doctor can report upstream-unavailable for 30 seconds after a final Codex inference fails, and the message names the failure’s HTTP status, when it happened, and when the hold ends. It is passive evidence, independent of telemetry consent: a completed successful Codex response clears it. An attributed OpenAI 401, 403, or 429 rejection enters upstream-blocked. A 401 or 403 stays until setup or a completed successful Codex response clears it. A 429 block expires: upstreamBlocked.expiresAt comes from the 429’s Retry-After, else claude-code-proxy’s usage-limit reset header, else 60 seconds, and the doctor message names that time. It lifts by itself then, or sooner on a completed successful Codex response, and a later rejected request can latch it again. When Codex completes a turn with no output at all, claude-code-proxy reports a 503 “Codex completed without producing output”; the shim answers that turn as an empty end_turn so the session moves on instead of retrying into the same empty answer. Sidequest reads a cached catalog, but while that catalog says Codex isn’t ready it asks the gateway again every 30 seconds, so a transient failure stops blocking dispatch within about a minute of the last failed request.

SIDEQUEST_DISCOVERY_DIRS accepts comma-separated extra catalog roots. Sidequest always keeps ~/.claude in discovery, so adding a root does not hide the installed Model Gateway catalog. Only that installed catalog has a refresh command. Fixture or shared catalogs at extra roots keep using their recorded contents without a five-minute expiry.

That refresh command is catalog --refresh --json, and Sidequest runs it whenever the installed catalog has expired. If it cannot write a fresh catalog it exits non-zero and says why on stderr: /healthz returned an error status (named), the shim didn’t answer /healthz at all (with the connection error), /v1/models returned an error, or the model list held no gateway ids. It keeps the stored catalog and its timestamp as they were, so Sidequest treats the attempt as a failure instead of accepting an expired file, and adds that stderr reason to its Codex dispatch refusal as Last gateway catalog refresh: .... If your gateway models disappear from a board a few minutes after each shim start, run that command yourself and read its exit code and stderr.

The shim’s /healthz is a liveness check: a 200 means the shim is up and serving, and it answers right away. Its codexReadiness block is the last known readiness, not a fresh one. The slow parts (the proxy’s /v1/models and codex auth status, which can take several seconds on macOS when it reads the Keychain) run in the background, one check at a time however many probes arrive. checkedAt and ageMs say when that check finished. stale: false means it’s under 15 seconds old. stale: true means it’s older, and the next check is already running. Right after a shim start, before the first check has finished, the state is checking, with checks: null. upstreamBlocked and upstreamUnavailable are always current. doctor, ensure, and catalog --refresh don’t use this cached block. They run their own full readiness check.

On macOS and Linux, a shim that died without closing can leave ~/.claude/model-gateway/gateway.sock behind. The next shim connects to it first. If nothing answers and the file is a socket, the shim removes it, logs that it did, and binds. A socket with a live listener is never touched.

Running Model Gateway’s own suite uses a separate test home and never touches the installed gateway. Codex sessions dropping while tests ran was a supervisor cleanup bug, fixed in this version. Cleanup uses this home’s recorded PIDs and targeted ownership checks only: the recorded command or start time must match the live process. Windows hides the command line of a process running at a higher privilege level than the session asking, so a record whose start time still matches is accepted on that alone, and a record is discarded only when a command line it can read contradicts it. A reused PID is never stopped. When the command line is unavailable, doctor says so and names elevation as the likely cause: stop and setup then have to run from a session with the same privileges as the one that started the gateway. If startup, restart, or drain cannot confirm who owns a listener, it leaves that listener alone and startup records owner-unknown; confirmed foreign listeners are refused too. On POSIX, process probes pin their child locale to C so they can read start times without requiring a global locale settings change.

If something breaks, describe the symptom:

My gateway models disappeared from /model. Diagnose and fix it.

Codex fails, but Claude models still work. Repair Model Gateway.

If GPT-6 Astra is missing from /model, check the installed and serving claude-code-proxy version before diagnosing account access. Astra requires version 0.1.36 or newer. Version 0.1.35 does not include its backend allowlist, and the current doctor check can still report PASS when Astra is the missing row. Ask Claude to rerun setup, which fetches the latest GitHub release, then fully restart Claude Code. A models.json edit cannot add a backend that the proxy does not allow.

Authentication recovery has a different boundary. Complete login and let Claude run setup again; the refreshed credential can serve the already-running proxy, so a process restart is not required just for auth. Settings, discovery-cache, plugin, or model-row changes do require a full restart of the affected project process. /reload-plugins alone is not enough.

The shim writes request-route metadata to ~/.claude/model-gateway/logs/request-routes.jsonl by default. Records contain the time, backend, model, request path, route and effort when present, and safe session or agent correlation fields. They do not contain request bodies, prompts, messages, tools, authentication, or arbitrary headers. Set CODEX_GATEWAY_REQUEST_LOG=0 before the shim starts, then restart the shim through setup or ensure, to disable this route log. The setting is read by the shim process at startup. CODEX_GATEWAY_REQUEST_LOG_PATH changes the file location.

Usage observability also keeps one high-water JSON file per valid session under ~/.claude/model-gateway/request-body/. It records only the largest forwarded request-body byte count seen for that session and an observation timestamp. It does not contain the request body. No retention period is promised for either local record.

When project telemetry is already enabled, route traces carry the terminal request status and status code. A failed inference cannot fabricate usage, so it does not create token-usage or limit records.

Remote Control gives each project two choices.

RC-compatibility keeps the project’s HTTP Model Gateway transport configured. It maps api.anthropic.com to loopback in the hosts file and needs the gateway shim to bind port 80. A detected hosts entry or bound listener proves that local HTTP transport only. It also makes Claude Code treat the gateway as first-party, which can enable experimental message threading. Model Gateway refuses Codex and Grok thread continuations locally with HTTP 400 because neither backend has conversation state. Nothing is forwarded or rerouted. A client version that recognizes the refusal drops the threading beta and retries the turn with full message history. The experiment and client version can change that behavior, so do not promise a single refusal per session. On inspected Claude Code 2.1.267, Remote Control session creation uses HTTPS while the compatibility listener is HTTP; the reported 2.1.259 client and the inspected client have no verified end-to-end RC result. Normal gateway mode remains the verified inference path.

At 2.1.267, the api.anthropic.com hostname also disables client gateway discovery, so gateway rows disappear from /model in RC-compatibility mode and a cache refresh cannot restore them. Claude Code can accept and persist an explicit id such as /model claude-gpt-5.6-terra[1m], but that client-side action does not prove its later request reaches the gateway. The current cache cleaner preserves canonical [1m] ids; it is not a proposed fix for a reported request error.

Tell Claude you want to enable, disable, or diagnose RC-compatibility. After you directly confirm remote-control enable --confirm, Model Gateway creates a backup and writes its marked hosts block. Its read-only diagnosis reports the current serving supervisor as bound, bindable, unavailable (CODE), or unknown, never an untested availability claim. Start the normal-user gateway supervisor before enabling unless it reports bound or bindable. Enable checks that serving process before any backup or hosts-file write, then asks the same process to open the compatibility listener without restarting the main gateway or worker. If activation, verification, or wiring fails, it restores the exact original hosts bytes only when the file still has the bytes it wrote. Later external edits stay in place, and the command names the backup for manual recovery. A bound result permits adoption of an existing unmarked loopback mapping, including when the serving supervisor already owns the compatibility listener. An unavailable result can name another port holder and enable refuses before any hosts-file write. Docker Desktop is a common holder. Enabling also refuses before any backup, hosts write, gateway startup, or reconciliation when effective process ANTHROPIC_BASE_URL is HTTPS api.anthropic.com (including port 443), because the loopback mapping would send TLS traffic to an unsupported endpoint. If you control the Claude Code CLI launch, correct or unset that value, then restart. If the host replaces it, use the supported Claude Code CLI on the wired project instead. Desktop routing is unsupported under forced overrides on Windows and macOS, and settings, parent, or User-scope edits cannot be promised to win. Enabling synchronizes and verifies an existing writable settings target for future sessions. Existing env-only compatibility remains env-only and applies only to processes that inherit that environment. Enable never claims to change the current process environment. Disabling stays available without a bindability preflight and uses the normal safe recovery path to remove the compatibility listener.

To get Remote Control without RC-compatibility, run env --remove for this project, then restart Claude Code. It removes the gateway base URL, discovery flag, static gateway values and gateway-owned alias pins. User-set pins with values the gateway does not own survive and are named in the output. Native Claude aliases then follow Claude Code’s defaults. The project talks to api.anthropic.com directly and Remote Control becomes available.

That project has no gateway models after the restart: gateway rows disappear from /model and typed gateway ids do not work either. A process-exported ANTHROPIC_BASE_URL still wins over the file edit. If you control the Claude Code CLI launch, correct or unset that value, then restart. If the host replaces it, use the supported Claude Code CLI on the wired project instead. Desktop routing is unsupported under forced overrides on Windows and macOS, and settings, parent, or User-scope edits cannot be promised to win.

The generated Model Gateway reference records the agent-facing commands and configuration details used by the skill.

ensure repairs leftover gateway discovery flags and owned alias pins in settings files without a base URL, and reports the removed aliases in one line. It also registers the current wired project if pin sync was missing it. doctor reports “leftover gateway settings: aliases pinned to , no gateway routing” or “wired-but-unregistered project” and names ensure as the fix, without changing those settings or the wiring registry. Settings that name another endpoint are left alone.