Every new model provider looks simple until it reaches your actual coding tools.
Qwen has DashScope's OpenAI-compatible mode. OpenRouter gives you one API for a huge list of models. Both sound like they should be easy to plug into an AI coding workflow.
Then the tools remind you that "OpenAI-compatible" does not mean "compatible with everything I use."
Claude Code expects Anthropic Messages. Codex expects the Responses shape. Other clients speak Chat Completions. A provider can have a perfectly good API and still force you into another round of base URLs, API keys, model aliases, and small wrapper scripts.
That was the part I wanted to avoid.
The annoying part was not the API key
Adding one more key is easy.
The mess starts when every tool wants to own the provider decision.
If I want to try Qwen for cheap coding tasks, I do not want to edit Claude Code's environment, then Codex's config, then a chat client's model list. If I want to test an OpenRouter model slug like anthropic/claude-3.7-sonnet, I do not want a routing layer to accidentally remap it because it looks unfamiliar.
The shape I wanted was simpler:
- tools keep pointing at localhost
- providers are added once
- model names are mapped or passed through in one place
- protocol conversion happens behind the gateway
So the latest CliGate change adds Qwen and OpenRouter as provider presets instead of making them another pile of one-off config.
The fix was a preset, not another bespoke provider
CliGate already runs as a local control plane for AI coding tools. Claude Code, Codex CLI, Gemini CLI, OpenClaw, and OpenAI-compatible clients can point at one local server, while CliGate owns credentials, routing, logs, and model mapping.
For Qwen and OpenRouter, the interesting part is that they are both OpenAI Chat-style providers. That means the new provider definition can be mostly data:
{
id: 'qwen',
apiFormat: 'openai_chat',
baseUrl: 'https://dashscope.aliyuncs.com/compatible-mode/v1',
models: ['qwen-max', 'qwen-plus', 'qwen-turbo', 'qwq-32b'],
tiers: { standard: 'qwen-plus', fast: 'qwen-turbo' }
}
OpenRouter gets the same treatment, with one important rule: model ids containing / pass through as native model slugs. If I ask for openai/gpt-4o-mini or qwen/qwen-2.5-72b-instruct, CliGate should not pretend it knows better and remap that into a generic tier.
That small rule matters because OpenRouter is not one model family. It is a catalog.
The protocol bridge is the real feature
The provider preset is only half the story.
Qwen and OpenRouter expose Chat Completions. Claude Code does not speak Chat Completions. Codex may enter through a Responses-compatible path. So the gateway now treats these providers as chat-native upstreams and bridges the tool-facing protocols around them.
For Claude Code, CliGate translates Anthropic Messages into OpenAI Chat, sends the request to Qwen or OpenRouter, then translates the answer back into an Anthropic-style message. Tool calls and tool results are preserved in the translation.
For Codex, CliGate deliberately does not pretend these providers have a native /responses endpoint. It leaves native Responses support disabled, so the existing Responses-to-Chat fallback handles the request through Chat Completions instead.
That detail is boring in the best way. The tools keep speaking their own protocols. The provider only has to support the API it actually supports.
What setup looks like now
The user-facing setup is intentionally small:
npx cligate@latest start
# Add a Qwen or OpenRouter key in API Keys
# Keep Claude Code and Codex pointed at localhost:8081
After that, routing can happen inside CliGate. Qwen can fill a cheap fast or standard tier. OpenRouter can be used when you want to try a specific upstream model slug. Existing OpenAI, Anthropic, Gemini, Azure OpenAI, DeepSeek, Vertex, and local routes can stay in the same dashboard.
No CLI needs to know which provider won the route.
Why this feels better than another config file
The main win is not that CliGate supports two more providers.
The win is that adding a provider no longer means teaching every tool about that provider.
Qwen and OpenRouter are now just credentials and routing choices inside the local control plane. Claude Code can still think it is talking to an Anthropic-shaped API. Codex can still enter through its expected path. OpenAI-compatible clients can still use Chat Completions directly.
The provider decision moves out of the tool and into the layer that can actually inspect, route, price, and log the request.
Source: github.com/codeking-ai/cligate
How are you handling OpenRouter-style model catalogs in your AI coding setup? Do you pass model slugs through directly, map everything into tiers, or keep separate configs per tool?
Top comments (1)
Happy to answer questions about the setup. I am especially curious how others handle OpenRouter model slugs: pass-through, tier mapping, or separate configs per tool?