Most desktop AI apps still assume the backend is fixed.
Claude Desktop assumes Anthropic. ChatGPT.app assumes OpenAI.
That works until you want to route the same desktop app across local and cloud models, keep one gateway for caching and fallback, and pin stronger or cheaper models without changing frontend UX.
That is the problem we just solved in Lynkr.
Lynkr is an open-source LLM gateway. In the latest code changes, we added native support for two desktop surfaces that normally do not give you much backend control: Claude Desktop and ChatGPT.app (Codex Desktop).
Claude Desktop: using the hidden third-party gateway path
Claude Desktop does not expose a normal bring-your-own-provider flow. The new Lynkr support works by using Claude Desktop's undocumented third-party gateway mode — the same general mechanism Ollama's Claude Desktop launcher relies on.
The new install flow is:
lynkr desktop-token <oauth-token>
Under the hood, Lynkr edits config in ~/Library/Application Support/ and manages:
Claude/claude_desktop_config.jsonClaude-3p/claude_desktop_config.jsonClaude-3p/configLibrary/_meta.jsonClaude-3p/configLibrary/<uuid>.json
The installer also writes Claude-3p/configLibrary/.lynkr-backup.json, which means restore is not a blind delete. Lynkr saves the original deployment mode and applied profile, then restores them exactly later.
lynkr desktop-token --restore
That restore command removes the Lynkr profile, resets deployment bookkeeping, and puts Claude Desktop back into its previous mode.
Why Claude Desktop needs a token
Once Desktop is switched into third-party gateway mode (deploymentMode: "3p"), it is no longer talking directly to Anthropic. Lynkr becomes the API layer receiving Desktop traffic.
That is why the install command expects a Claude OAuth token. The current implementation explicitly validates that the token starts with sk-ant-oat.
Lynkr does not mint or refresh that token. It installs the token into Claude Desktop's gateway profile so Desktop can send it to Lynkr, and Lynkr can forward it when a request routes to an Anthropic-backed tier.
Claude Desktop's model picker becomes a tier selector
Instead of treating the picker as cosmetic, Lynkr uses it as a routing control surface.
The docs describe fixed picker entries that map to Lynkr tiers:
- Auto -> no pin, normal content-based scoring
-
claude-opus-5->REASONING -
claude-sonnet-5->COMPLEX -
claude-sonnet-4-6->MEDIUM -
claude-haiku-4-5-20251001->SIMPLE
Because Claude Desktop validates model ids against its own catalog, Lynkr cannot advertise made-up ids like lynkr-medium. Instead, it reuses real Claude-family ids and treats them as tier pins.
So the contract becomes:
- Auto = gateway decides
- specific model = user decides
When the user picks anything other than Auto, Lynkr bypasses classifier-based routing for that request and pins the tier directly.
Claude Desktop detection is gated, not global
Lynkr does not force this behavior onto every Anthropic-compatible caller. The Claude Desktop gateway logic only intercepts callers that look like Desktop specifically — for example requests carrying an anthropic-version header or an explicit ?format=anthropic path.
Other Anthropic-format clients still fall through to the normal model list behavior.
ChatGPT.app: one backend for Desktop and CLI
ChatGPT.app required a different strategy.
The key detail is that Codex Desktop and Codex CLI share the same config surface:
~/.codex/config.toml
That means Lynkr can be added once as a provider block and then back both interfaces with the same gateway configuration.
ChatGPT.app exposes a real routing signal: reasoning.effort
The most interesting part of the ChatGPT.app work is that the model picker sends structured routing hints on the wire.
The latest code adds a dedicated mapping module in src/routing/openai-model-slots.js.
That file documents the behavior Lynkr now relies on:
- Codex sends a real OpenAI model id
- it also sends
reasoning.effort - Lynkr maps that pair into a routing tier
The current effort-to-tier mapping is:
minimal -> SIMPLElow -> MEDIUMmedium -> COMPLEXhigh -> REASONING
This was confirmed live from a captured request.
One verified path from the implementation:
- UI label: Light
- wire value:
reasoning.effort = "low" - Lynkr routing tier:
MEDIUM - classifier path: bypassed
If the app already tells the gateway how much reasoning the user wants, the gateway should respect it.
The pin is intentionally conservative
If Lynkr sees an unrecognized model or effort value, it falls back to normal content-based routing instead of guessing.
There is also an important scope note in the code: the model/effort pin only governs the first model call of a turn. If the turn becomes multi-step — tool calls, follow-up steps, more agent iterations — later steps can still be rescored by content.
Why these integrations matter
The reason these integrations matter is not just that Lynkr now supports two more apps.
It is that both apps normally own the backend relationship:
- Claude Desktop assumes Anthropic
- ChatGPT.app assumes OpenAI
Once both route through Lynkr, the control plane moves out of the app and into the gateway:
Claude Desktop / ChatGPT.app
-> Lynkr
-> local + cloud models
-> tier routing + token optimization + fallback
At that point:
- the app owns the UX
- Lynkr owns routing logic
- providers become interchangeable
That is the real story in these latest Lynkr changes.
Top comments (0)