Repository navigation
Expose every Gateway model to Claude Code with fixed-name and role mapping #77
Description
Part of #73.
Blocked by: #74, #75 (native dependencies). The catalog/protocol contract must be settled before any client UI consumes it.
Objective
Make every Gateway-exported model selectable inside real Claude Code, and define how Claude Code's fixed model names and role aliases map onto those models — with automatic catalog synchronization and fail-closed diagnostics.
Authority
ADR-0014 "Model selection": every model in the existing enabled, Gateway-exported catalog must be selectable inside Claude Code, not merely visible in CodexHub or usable as one custom default. No capability-based filtering, no second editable model list. Claude-compatible IDs must resolve unambiguously to the original Provider/model identity; display labels are not routing identities. Existing clients' discovery must remain compatible. Exact discovery format, role names, and refresh behavior are facts to establish in #74, not assumptions.
Scope
1. Complete, compatible model surface
- Source set: the existing enabled, Gateway-exported catalog (
provider.enabled && model.enabled && model.gateway_exported; ADR-0009/ADR-0011). Do not create a second list, a per-client allowlist, or capability filtering. - Every model in that set must be selectable in the pinned real Claude Code picker. Spike Claude Code Messages compatibility through CodexHub #74 records the mechanism the CLI actually supports: Anthropic-shaped discovery, an alias-per-model projection, a custom-model option, or a combination. If the verified CLI constrains discovery IDs (e.g. a
claude*/anthropic*prefix rule), project a stable, collision-free alias per exported model rather than dropping models from the list. - Projection follows ADR-0011 republish semantics: catalog changes update the Client Projection;
display_nameis presentation only, and routing identity remains the canonicalprovider/modelselector. - Keep the existing OpenAI-shaped
GET /v1/modelscontract compatible for current consumers; a Claude-specific projection must not break them.
2. Identity and round-trip
- Every projected ID (alias or canonical slug) resolves to exactly one canonical Gateway selector, with no case loss, no prefix ambiguity, and no fuzzy matching.
- Collisions are impossible by construction, or fail closed at publish time with an actionable diagnostic.
- Removed/disabled/renamed models: the mapping becomes visibly invalid; never silently fall back to another model. Define migration, deprecation, and historical-session behavior.
3. Fixed names and role mappings
- Define the mapping contract from Claude Code's fixed/hardcoded model names and role aliases (main, fast/background, subagent) to Gateway-exported models, using the role names, variables, and effective-model behavior Spike Claude Code Messages compatibility through CodexHub #74 observes.
- Mappings and the default model are separate user choices. An explicit in-session model selection must not be overridden by a role mapping.
- Semantics live here; the client card's settings dialog and config writing live in Add a managed Claude Code client config adapter and settings UI #76. Add a managed Claude Code client config adapter and settings UI #76 consumes this contract — do not implement a parallel mapping model there.
- No mapping is required for basic operation: the default model plus the complete selectable list must work with zero mappings configured.
4. Synchronization
- Catalog changes automatically update the projection; no stale client list.
- Invalid mapping targets surface as an explicit, user-visible state (invalid, not silently substituted).
- Record the refresh/restart behavior Spike Claude Code Messages compatibility through CodexHub #74 observed and state it for Add a managed Claude Code client config adapter and settings UI #76's UI copy.
Out of scope
The inbound Messages route (#75), client configuration writing, the card and settings dialog (#76), the release matrix (#78), and any ACP/AgentProvider work (#85).
Acceptance criteria
- Evidence from the pinned real Claude Code shows every exported model present and selectable in the client's own model picker.
- A model with no capability claim still appears as selectable; requests it cannot serve fail explicitly at Add inbound Anthropic Messages API for Claude Code clients #75's layer rather than disappearing from the list.
- Each projected ID round-trips to exactly one canonical Gateway selector in tests, including provider-qualified IDs and mixed case.
- Alias/ID collisions and removed or disabled models fail closed with actionable diagnostics and visible invalid mapping state.
- Fixed-name and role mappings route as configured in traces, without overriding an explicit model selection.
- An empty mapping set still yields a working default-model path.
- Catalog change ⇒ projection republish, covered by a test (added, removed, disabled, renamed).
- Existing
/v1/modelsconsumers and their tests remain green. - Discovery/projection stays disabled or inert until the Add inbound Anthropic Messages API for Claude Code clients #75 route is available.
Required verification
Risk class: strict — routing identity, persisted contract, catalog projection. Use the repository launcher; never a bare python/pytest.
.\scripts\codexhub-python.cmd -m pytest tests/test_route_plan_seam.py tests/test_providers_config.py tests/test_maintained_catalog.py -q
.\scripts\codexhub-python.cmd -m pytest -q --ignore=tests/test_real_client_e2e.py
.\scripts\codexhub-python.cmd scripts/report_quality_gates.pyRust/frontend contract suites when the projection touches exported Rust structures:
Push-Location src-tauri
cargo test --locked
cargo clippy --locked --all-targets -- -D warnings
Pop-LocationLinux: ./scripts/verify-linux.sh for the affected boundaries. Real-CLI picker evidence is recorded with the exact pinned version from #74.
References
src-python/gateway_catalog_runtime.py,src-python/providers_config.py,src-tauri/src/gateway/inject.rs(projection helpers),src-python/maintained_catalog.py- ADR-0009, ADR-0011
docs/research/2026-07-12-claude-code-external-client-support.md(discovery request shape — verify against the pinned CLI)
Document status
ADR-0014 is committed in draft PR #556 at ed76f0a6e22d3188879504638b2943f5bb855d41, not yet merged to main. The pinned link is readable now; the document is accepted direction, not live protocol evidence.
Activity
[-]Export stable Claude-compatible model aliases and discovery[/-][+]Expose every Gateway model to Claude Code with fixed-name and role mapping[/+]NOirBRight commentedon Sep 20, 2026
Early version-pinned preparation finding (STATIC source inspection only, not yet runtime acceptance): the installed Claude Code 2.1.278 discovery path is opt-in via CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY and filters returned IDs with /(claude|anthropic)/i (substring, not an anchored prefix). It accepts a data array with id plus optional display_name/description, so a new Anthropic envelope is not automatically required.
Implication to verify in #74: discovery-based full-catalog selection needs stable Claude-compatible aliases for otherwise nonmatching Gateway IDs. Preserve canonical Provider/model identity and existing clients’ /v1/models behavior. The one-custom-model environment option alone cannot meet the complete-catalog requirement. Other picker configuration mechanisms and alias normalization are still being checked; do not generalize a discovery filter into a claim that every possible picker source rejects arbitrary IDs.
#74 implementer has the opt-in/filter details for a credential-free loopback test. No live provider calls or user configuration changes occurred.