Interactive coding agents with single-provider auth¶
Route Codex or Claude Code between models from one provider using your saved CLI login. Every target, including the classifier, must use that provider.
These composite routing recipes use a
classifier to choose the starting tier for each user turn. Stage adjusts routing
during tool calls. forward_auth
passes your login through to the models.
Choose one recipe. Each uses local port 4123.
Codex with OpenAI¶
Sign in with codex login. Terra classifies, and Stage routes between Sol and Luna.
This recipe needs Codex classifier support added after v0.3.0. Install from a
checkout of current main:
Save as codex-routing.toml:
schema_version = 1
[llm_clients.chatgpt]
format = "openai_responses"
base_url = "https://chatgpt.com/backend-api/codex"
forward_auth = true
[targets.capable]
id = "gpt-5.6-sol"
llm_client = "chatgpt"
[targets.efficient]
id = "gpt-5.6-luna"
llm_client = "chatgpt"
[targets.judge]
id = "gpt-5.6-terra"
llm_client = "chatgpt"
extra_body = { store = false, stream = true }
omit_body_fields = ["max_output_tokens"]
[routes.switchyard]
id = "switchyard"
type = "composite"
[routes.switchyard.classifier]
target = "judge"
base_threshold = 0.5
classify_trigger = "user_turn"
[routes.switchyard.stage]
capable_target = "capable"
efficient_target = "efficient"
confidence_threshold = 0.5
Start the server:
switchyard-server --config codex-routing.toml --dry-run
switchyard-server --config codex-routing.toml --host 127.0.0.1 --port 4123
Create ~/.codex/switchyard.config.toml (or place it beside your config.toml if
you use a custom Codex config directory):
model = "switchyard"
model_provider = "switchyard"
[model_providers.switchyard]
name = "Switchyard"
base_url = "http://127.0.0.1:4123/v1"
wire_api = "responses"
requires_openai_auth = true
In another terminal, launch Codex:
Claude Code with Anthropic¶
Sign in to Claude Code with your Claude account. Haiku classifies, and Stage routes between Opus and Sonnet.
Install the latest release:
Save as claude-routing.toml:
schema_version = 1
[llm_clients.anthropic]
format = "anthropic_messages"
base_url = "https://api.anthropic.com"
forward_auth = true
[targets.capable]
id = "claude-opus-5-5"
llm_client = "anthropic"
[targets.efficient]
id = "claude-sonnet-5-5"
llm_client = "anthropic"
[targets.judge]
id = "claude-haiku-4-5-20251001"
llm_client = "anthropic"
[routes.switchyard]
id = "switchyard"
type = "composite"
[routes.switchyard.classifier]
target = "judge"
base_threshold = 0.5
classify_trigger = "user_turn"
[routes.switchyard.stage]
capable_target = "capable"
efficient_target = "efficient"
confidence_threshold = 0.5
Start the server:
switchyard-server --config claude-routing.toml --dry-run
switchyard-server --config claude-routing.toml --host 127.0.0.1 --port 4123
In another terminal, launch Claude Code:
env -u ANTHROPIC_API_KEY -u ANTHROPIC_AUTH_TOKEN \
ANTHROPIC_BASE_URL=http://127.0.0.1:4123 \
ANTHROPIC_DEFAULT_OPUS_MODEL=switchyard \
ANTHROPIC_DEFAULT_SONNET_MODEL=switchyard \
ANTHROPIC_DEFAULT_HAIKU_MODEL=switchyard \
claude --model switchyard
Use your saved Claude login, without an apiKeyHelper or gateway token.
Check the routing¶
Send a prompt, then check which models handled the answer and classification: