Skip to content

Add Router One models to the Zed Agent with a custom LLM provider

Zed is the Rust-built code editor with its own agent, the Zed Agent, which runs in the Agent Panel. The Zed Agent, the Inline Assistant, Git commit-message generation and thread summaries all call the LLM provider you configure, and Zed accepts custom OpenAI-compatible providers in settings.json. Register Router One once as an openai_compatible provider and the chat models you list, from the Claude, GPT, Gemini, Grok and DeepSeek families, appear in Zed's model picker behind one key. Each agent turn is one POST /v1/chat/completions, billed and recorded in Dashboard → Logs. Zed does not fetch a model list from this provider, so every model is an entry you write, with its context window and capabilities. Checked against Zed 1.21.0 (stable, September 23, 2026) on 2026-09-27.

Find the right settings surface in Zed 1.21

Zed 1.21 has two settings surfaces. agent: open settings (the agent::OpenSettings action, also in the Agent Panel's top-right menu) opens the graphical Settings Editor on its AI page, where LLM Providers → Add Provider asks for a provider name, API URL, model ID and context window. That form is enough for a single model. For several models, capability flags and background-feature models, edit the JSON instead: zed: open settings file (zed::OpenSettingsFile) opens settings.json, which lives at ~/.config/zed/settings.json on macOS and Linux unless XDG_CONFIG_HOME points elsewhere. zed: open settings, the command older guides mention, now opens the graphical editor rather than the file. Before you start, create a Router One key for Zed with a maxSpend cap: agent threads send one request per model turn, and the background features add requests of their own.

Configure Zed to use the Router One base URL

Add an openai_compatible entry under language_models. router-one is the provider ID: it labels the models in the picker and names the environment variable for the key. api_url is the /v1 base URL, because Zed appends /chat/completions itself. Each available_models entry is one model in the picker. name is the exact catalog ID, sent as the model field; display_name is only the label; max_tokens is the model's context window as an integer. The model page on /models shows the window rounded (1.05M, 200K), so write it as a whole number rounded down (1000000, 200000); Zed also uses it to decide when to compact a thread, by default at 90% of the window. Zed's capability defaults for a custom model, tools on, images off, chat_completions on and max_tokens_parameter off, fit most text work, so the example leaves them alone; the next sections cover when to change them. reasoning_effort (none, minimal, low, medium, high, xhigh or max) turns on thinking for that model in the Agent Panel and is sent as reasoning_effort. Router One does not turn it into a thinking setting for Claude IDs, except on Claude Opus 5.5, where it maps the value to output_config.effort (none and minimal become low); other models may ignore it or reject the request with 400. Leave max_output_tokens out unless you choose your own cap, and never put the key in settings.json:

zed-settings.json
{
  "language_models": {
    "openai_compatible": {
      "router-one": {
        "api_url": "https://api.router.one/v1",
        "available_models": [
          {
            "name": "anthropic/claude-sonnet-5",
            "display_name": "Claude Sonnet 5 · Router One",
            "max_tokens": 1000000
          },
          {
            "name": "openai/gpt-5.5",
            "display_name": "GPT-5.5 · Router One",
            "max_tokens": 1000000,
            "reasoning_effort": "medium"
          }
        ]
      }
    }
  }
}

Give Zed the key: keychain or ROUTER_ONE_API_KEY

Zed keeps provider keys out of settings.json. Paste the key on the Settings → AI → LLM Providers page, next to the router-one provider, and Zed stores it in the system keychain. Alternatively, set an environment variable in the environment Zed starts from: its name is the provider ID in upper snake case followed by _API_KEY, so router-one reads ROUTER_ONE_API_KEY. A non-empty environment variable takes precedence over the keychain value, which is the usual reason a newly pasted key seems to have no effect; unset the variable and restart Zed to stop using it. For SSH, dev container and other remote projects, Zed reads keys from the local keychain and from the local Zed process's environment, not from the remote machine. Either way the key sits on your computer, so a dedicated key with a maxSpend cap limits what a leaked key can cost.

Give Zed the key: keychain or ROUTER_ONE_API_KEY
Provider ID in settings.jsonEnvironment variable Zed reads
router-one (openai_compatible)ROUTER_ONE_API_KEY
router-one-messages (anthropic_compatible, optional)ROUTER_ONE_MESSAGES_API_KEY

Choose the agent's default model and the background models

agent.default_model sets the model a new Zed Agent thread starts with. Zed's background features can each use their own model: commit_message_model writes Git commit messages, thread_summary_model summarizes threads, inline_assistant_model runs the Inline Assistant, subagent_model runs subagents and compaction_model summarizes long threads. The openai_compatible provider declares no fast model of its own, so name these explicitly if you want them on a cheaper ID, each as a provider and model pair; every model you name must also be listed in available_models. Zed's docs ask for a compaction model whose context window is at least as large as the thread's model, so a thread on a 1M-window model needs a 1M-window compaction model such as deepseek-v4-flash, not anthropic/claude-haiku-4.5 with its 200K window. Commit messages and thread summaries have no such constraint. Automatic compaction runs at 90% of the window by default; agent.auto_compact.threshold changes that, and /compact in the message editor compacts a thread by hand.

settings.json
{
  "agent": {
    "default_model": { "provider": "router-one", "model": "anthropic/claude-sonnet-5" },
    "commit_message_model": { "provider": "router-one", "model": "anthropic/claude-haiku-4.5" },
    "thread_summary_model": { "provider": "router-one", "model": "anthropic/claude-haiku-4.5" },
    "compaction_model": { "provider": "router-one", "model": "deepseek-v4-flash" }
  }
}

What each capability flag changes on the gateway

The capability flags decide what Zed puts into each request, so they are where most Router One problems with Zed start. To change one, add a capabilities object to that model's entry in available_models. Copy the object whole from the OpenAI-compatible example in Zed's docs rather than writing only the flag you want: most of its flags have no default inside the object, so a partial one does not load. Then change the flags below; the others in Zed's example can stay as they are.

What each capability flag changes on the gateway
Flag (default)What Zed doesWith Router One
tools (true)Sends the Zed Agent's tool definitions with each turnThe agent edits files and runs commands through tools; prefer IDs whose model page lists tool calling
images (false)Sends no images at all unless set to trueSet true only for IDs whose model page lists image input; a text-only ID such as deepseek-v4-flash answers an image with HTTP 400
max_tokens_parameter (false)Sends an output cap from max_output_tokens as max_completion_tokensSet true so the cap goes out as max_tokens, as Router One's Chat Completions reference documents
chat_completions (true)false switches the model to POST {api_url}/responses/v1/responses serves GPT-family, DeepSeek and Grok chat IDs; keep true for Claude and Gemini IDs

Optional: Claude and DeepSeek over /v1/messages

Zed also has an anthropic_compatible provider for services that implement Anthropic's Messages API, and Router One serves the currently listed Claude-family IDs and DeepSeek IDs natively on /v1/messages. Its api_url is the host root, https://api.router.one, because Zed appends /v1/messages itself and sends the key in the X-Api-Key header along with Anthropic-Version 2023-06-01. An api_url ending in /v1 produces /v1/v1/messages, which Router One answers with 404 and a hint to remove the trailing /v1. Give this provider its own ID, such as router-one-messages, so its key variable becomes ROUTER_ONE_MESSAGES_API_KEY. The ID must differ from your openai_compatible entry: when the same name is configured under both, Zed keeps the OpenAI-compatible entry and logs the Anthropic one as shadowed. Its capabilities default to tools true and images false; to set images to true for Claude IDs, whose model pages list image input, write the object with all three of its flags, as in the example. The OpenAI-compatible provider above already reaches the same models, so add this one only if you want the native Messages API for them, and check that the model page lists POST /v1/messages before adding an ID.

settings.json
{
  "language_models": {
    "anthropic_compatible": {
      "router-one-messages": {
        "api_url": "https://api.router.one",
        "available_models": [
          {
            "name": "anthropic/claude-sonnet-5",
            "display_name": "Claude Sonnet 5 · Messages",
            "max_tokens": 1000000,
            "capabilities": { "tools": true, "images": true, "prompt_caching": false }
          }
        ]
      }
    }
  }
}

What this provider does not configure: External Agents

The LLM providers you add serve the Zed Agent, the Inline Assistant, commit messages and thread summaries. External Agents, which Zed runs over the Agent Client Protocol, own their authentication and billing: Zed's docs state that an Anthropic API key configured for the Zed Agent does not configure Claude Agent, and an OpenAI API key does not configure Codex. Those agents keep their own login flow or configuration, and how they pick up a custom endpoint depends on the agent; the Claude Code and Codex guides cover the standalone tools' own settings. In Dashboard → Logs, the Zed Agent's turns appear under the key you gave Zed, with each request's model, tokens, cost, status, total time and, for a streamed request that produced output, time to first token (TTFT).

Which model ID should Zed send?

Copy the exact model ID from /models, preserving case, hyphens, and version suffixes; do not substitute a display name. Open its detail page and match the supported API endpoints, context window, and capabilities such as tool calling to the provider and features selected in Zed. A catalog listing does not mean the client can use every feature of that model. Give each client or application a dedicated API key with a maxSpend cap.

Which API protocol is Zed using?

OpenAI-compatible describes an interface format; it does not make Chat Completions (/v1/chat/completions), Responses (/v1/responses), and Anthropic Messages (/v1/messages) interchangeable. Check the installed client version, provider configuration, and actual request path against the model detail page and API compatibility fact sheet. A successful plain-text chat does not establish support for hosted tools, conversation state, or file-editing features.

Verify the Zed call in your request trace

Send a simple text request from Zed, then match its trace in Dashboard → Logs by time, model, and request_id: tokens, cost, latency, and status. Next, test streaming, tool calls, and multi-turn history separately. For failures, retain the actual request path, full error message, and request_id. If there is no matching log, check client configuration and connectivity before attributing the error to the gateway or upstream.

FAQ

Where does the API key go in Zed 1.21?

On the Settings → AI → LLM Providers page, which agent: open settings opens: paste it next to the router-one provider and Zed stores it in the system keychain. Alternatively, set ROUTER_ONE_API_KEY in the environment Zed starts from; Zed derives the name from the provider ID in upper snake case plus _API_KEY. A non-empty environment variable wins over the keychain, so if a pasted key has no effect, check for the variable. The key never goes into settings.json.

Why doesn't the model see my screenshot?

Because images defaults to false for custom OpenAI-compatible models, and Zed sends no images to a model with that flag off. Add a capabilities object to the model's entry, copied whole from Zed's OpenAI-compatible example because a partial object does not load, and set images to true for IDs whose model page lists image input, such as anthropic/claude-sonnet-5. Leave it false for text-only IDs such as deepseek-v4-flash: an image sent to such an ID gets HTTP 400 from the gateway, with a message saying no candidate supports the requested vision capability.

What number goes in max_tokens?

The model's context window as a whole number, not an output limit. The model page on /models shows it rounded, 1.05M or 200K for example, so write 1000000 or 200000, rounding down rather than up. Zed uses the number to size the thread and to trigger automatic compaction, by default at 90% of it. An output limit is a separate, optional field, max_output_tokens.

Should I set max_tokens_parameter to true?

Yes, if you set max_output_tokens; it goes in the model's capabilities object. With the default false, Zed sends that output cap as max_completion_tokens; with true, it sends max_tokens, the parameter Router One's Chat Completions reference documents. Without max_output_tokens the flag changes nothing, and your key's maxSpend remains the spending limit either way.

Should GPT models use the Responses API in Zed?

They don't have to. With chat_completions left at true, GPT IDs work over /v1/chat/completions like every other model. Setting it to false for a model makes Zed call POST https://api.router.one/v1/responses instead, which Router One serves natively for GPT-family, DeepSeek and Grok chat IDs; Zed's docs suggest it for models that need the Responses API to keep reasoning state. Claude and Gemini IDs must stay on chat_completions true.

Claude Agent or Codex in Zed still asks me to log in. Why?

External Agents keep their own authentication. The key you configured for the Zed Agent does not carry over: Zed's docs say an Anthropic API key for the Zed Agent does not configure Claude Agent, and an OpenAI key does not configure Codex. Use the agent's own login or configuration; the Claude Code and Codex guides describe those tools' own endpoint settings.

Why do I get a 404 on /v1/v1/messages?

The anthropic_compatible provider's api_url ends in /v1. Zed appends /v1/messages itself, so the api_url must be the host root, https://api.router.one. Router One's 404 message for that path says the same: remove the trailing /v1 from the base URL. The openai_compatible provider is the opposite and keeps exactly one /v1.

How do I keep commit messages and thread summaries on a cheaper model?

List a cheaper chat ID such as anthropic/claude-haiku-4.5 in available_models, then point agent.commit_message_model and agent.thread_summary_model at it as provider and model pairs. The openai_compatible provider has no fast model of its own, so naming these is how you move background requests off your main model. For compaction_model, pick a model whose context window is at least as large as the thread's model.

Which models can Zed use through the gateway?

Choose a current catalog model that supports both the endpoint and the features Zed uses. Check /models and the model detail page for the exact ID, current rates, and capabilities; a family name such as GPT or Claude is not a compatibility guarantee. A client that lists a model has only read the ID, from its own configuration or from GET /v1/models; verify an actual request too.

Models are listed, but requests fail with 400 or 404. What should I check?

Record the actual request path and error message, then check the exact model ID. A 400 can indicate invalid parameters, unsupported tools, or a model/endpoint mismatch; a 404 can indicate an incorrect path or missing resource, so it does not by itself establish that a model was retired. If the error says must be called via, use the named endpoint or select a model supported on the current endpoint. Do not add or remove /v1 or /chat/completions across all clients indiscriminately.

Does this work from Mainland China?

Yes. The gateway is reachable from Mainland China without a VPN, and the configuration is identical to the global setup.

How do I debug a 401/402/403/429?

Match the request and error message in Dashboard → Logs. For 401, check whether the key was sent and is valid; for 402, check wallet balance and maxSpend; for 403, check key permissions and access restrictions. For 429, distinguish request/token limits from upstream throttling using the error details. Keep the request_id and follow the error-codes reference.