Coding agents and desktop clients
Point Zed at TokenTriage
Two fields, two different roots.
Zed has one endpoint field per dialect family, and they take different roots. Set both. A wrong root is relayed unparsed and never priced.
{ "language_models": {
// OpenAI dialect. The root PLUS /v1.
"openai_compatible": { "tokentriage": {
"api_url": "http://127.0.0.1:8787/v1",
"available_models": [{ "name": "gpt-4o-mini", "max_tokens": 128000 }] } },
// Anthropic dialect. The BARE root. Zed adds /v1/messages itself.
"anthropic_compatible": { "tokentriage-anthropic": {
"api_url": "http://127.0.0.1:8787",
"available_models": [{ "name": "claude-sonnet-4-5", "max_tokens": 200000 }] } }
} }- The setting
language_models.<dialect>_compatible.<id>.api_url- The base URL
http://127.0.0.1:8787/v1 for OpenAI · http://127.0.0.1:8787 for Anthropic
How to tell it worked
Send one message through each provider in the model picker. Then read the last two ledger rows. Each must name a dialect. An empty dialect is the root mistake.
tail -n 2 ~/.tokentriage/decisions.jsonl | jq -c '{p:.http.path, d:.http.dialect}'What you should see
{"p":"/v1/chat/completions","d":"openai"} · {"p":"/v1/messages","d":"anthropic"}
How sure we are
Follows from the wire
It speaks a dialect we accept, so it works by the same contract every such client uses. Nothing tests this one specifically.
Verified against Zed 1.16.2 on
The gotcha
The two api_url fields take opposite roots
Zed appends /chat/completions to one and /v1/messages to the other. Copy a root across and the path matches no dialect. TokenTriage relays it onward with the path you sent, so what you see is your upstream answering. The row shows an empty dialect.
// WRONG. Zed sends /v1/v1/messages, which matches no dialect.
"anthropic_compatible": { "tokentriage-anthropic": {
"api_url": "http://127.0.0.1:8787/v1" } }
// RIGHT. The bare root. Zed appends /v1/messages.
"anthropic_compatible": { "tokentriage-anthropic": {
"api_url": "http://127.0.0.1:8787" } }“Use an Anthropic-compatible endpoint when a service implements Anthropic's Messages API (/v1/messages) and gives you a custom base URL, model ID, and API key.”
zed.dev/docs/ai/use-api-access#anthropic-compatible · read 2026-08-25
What you get now
What the ledger holds once a message arrives.
Three things that start the first time a message arrives. Each links its evidence. None of them is a claim about Zed.
Editor traffic you can tell apart
Add custom_headers to either provider block. Give it x-tt-agent: zed. The ledger then groups editor traffic apart from your scripts, and TokenTriage strips the header before the upstream sees it.
How a row gets its agentOne price table for both dialects
The same gateway serves the OpenAI family and the Anthropic family. Both providers land in one ledger. Each row carries a pricing key and the dated snapshot the price came from.
What a ledger row carriesA budget the editor cannot talk past
TokenTriage mints the key Zed holds and stores only its hash. Attach a budget to it. An overrun is refused with a 429, and that refusal is its own ledger row.
How budgets and keys work
- 2 endpoint fields
- one per dialect family, in adjacent objects
- 1 gateway port
- both providers point at the same listener
- 0 runs of Zed here
- nobody on this side has opened the editor
- 2 open questions
- a key on a local endpoint, and a plain http root
What does not carry across
Six things to know before you paste it.
Six of them, and the first two are about our evidence rather than about Zed. Read those first. The rest are traps in the settings file.
Nobody here has driven Zed
The settings and the URL forms come from Zed’s own current documentation, read on the date beside the chip. No Zed session exists. The two gateway paths were driven by hand from other clients, not from this editor.
Two questions only a hand-run can settle
Zed never says whether a custom provider may have an empty API key. And every api_url in its documentation is https, so a plain http root is unconfirmed. Both stay open here.
anthropic_compatible is not the anthropic key
They are two separate top-level entries. Edit language_models.anthropic and you retarget Zed’s built-in Anthropic provider instead. The custom provider you meant to add is simply not in the file.
Nothing rescues a failed call for you
TokenTriage does not retry and does not hedge: no retry chain, no failover, no health probes. Zed receives the failure itself. Cooldown protects the next call, not that one.
What routing does not doThe API key is not in settings.json
Zed derives the variable name from the provider id, upper snake case plus _API_KEY. Two providers mean two variables. Keys typed into Zed go to the system keychain instead.
A Responses-only model leaves the chat path
Zed posts to the Responses endpoint for any model whose capabilities.chat_completions is false. That is a third path. Check the row before you decide the base URL is what broke.
Which endpoints are registered
Paste it, then send one message.
Open the file with agent: open settings, or use Add Provider under Settings, AI, LLM Providers. Then send one message. Then read the row.
Also: What the ledger is forWhich paths are registeredEvery integration
Names and trademarks
These are independent integrations. No product named here has endorsed, reviewed or sponsored TokenTriage; every name is its owner's trademark, used only to say what works with what.