BYOK
Bring your own provider and use it in Command Code CLI. Any OpenAI or Anthropic compactible API can serve models in Command Code. You can bring your key from hosted providers (DeepSeek, OpenRouter, Vercel AI Gateway), local servers (Ollama, vLLM), or other coding agent's APIs.
You can connect to any external provider in Command Code, requests go straight from your machine to that provider's endpoint with your key, never through Command Code's servers.
BYOK providers can be managed from /connect in the Command Code CLI. Below are providers and instructions on how to connect to them.
Command Code is the default and recommended provider. Every model in /model routes through your plan, and the models are optimized for the cmd harness. That optimization is real engineering: see Harness Engineering for how the harness repairs, steers, and optimizes models.
The /model menu can be used to access models from Command Code and BYOK providers. BYOK models are active alongside Command Code models, and you switch back to Command Code models anytime through the model menu.
You can use your ChatGPT Pro/Plus subscription directly in Command Code. Select OpenAI ChatGPT/Codex in /connect (or run cmd login openai, chatgpt works too) and sign in.
The provider package installs on demand at first login, and its models appear as their own section in /model. Requests run locally from the CLI over your subscription.
Same flow for an active GitHub Copilot subscription: select GitHub Copilot in /connect (or cmd login copilot), complete the device sign-in, and the copilot provider's models will be listed in /model.
The /connect menu supports 150+ providers out of the box. For those, the endpoint, wire, and current model list come prefilled. Anything else works too: any OpenAI-compatible or Anthropic-wire endpoint can also be setup.
Run /connect and pick (BYOK) Add your own provider.
The connect menu supports 150+ providers with endpoint, models, and config prefilled. You can search and pick a provider from this menu.
Pick the provider
Start typing at the id step (openrouter, deepseek, groq, …) and a browsable list of known providers shows under the input. Pick one with ↑/↓ + enter; the wire and endpoint prefill.
Paste your key
Keys are stored securely in ~/.commandcode/auth.json. Press enter on the empty field if the endpoint takes no key (local servers).
Models arrive on their own
Discovery is silent: the provider's current model list, names and context windows included, is imported for you. Finishing lands you in /model with the new models selectable and routing.
If your provider is not in the menu, or you want to declare a custom/local one, follow these steps:
Name it
Type any id, a short lowercase handle (work-llm). It names the entry in ~/.commandcode/providers.json and prefixes its models (work-llm/gpt-x).
Pick the wire
OpenAI-compatible (/chat/completions, the default: Ollama, vLLM, LM Studio, most hosted APIs), OpenAI Responses (/responses, for endpoints speaking the OpenAI Responses API), or Anthropic (/v1/messages, for endpoints speaking the Claude Messages API).
Point at the endpoint
The API root. OpenAI-compatible servers usually end in /v1; Anthropic roots get /v1 added on the wire when missing. A pasted URL carrying a route suffix (…/v1/chat/completions) is trimmed to the root automatically, with a note showing what was removed.
Add the key, or skip it
Key is securely stored in auth.json. Press enter on the empty field if the endpoint takes no key (local servers).
Declare the models
The menu asks the endpoint's own /models listing first. If that comes up empty, you can either type ids there or modify the providers.json file to add the models. See the config schema below for details.
Press h on any non-typing step for the condensed version of all of this; esc (or ← where it can't mean cursor movement) goes back one step.
Everything related to byok providers lives in ~/.commandcode/providers.json. It is yours to edit, and changes apply live (reopen /connect or /model). For example:
| Field | Values | Notes |
|---|---|---|
name | string | Display name in /connect and /model; defaults to the id |
api | openai-completions (default) | openai-responses | anthropic-messages | Omit for OpenAI-compatible endpoints. openai-responses posts to {baseURL}/responses. Any other value skips the provider |
npm | AI-SDK package name | Compat only: @ai-sdk/openai-compatible & @ai-sdk/openai map to openai-completions, @ai-sdk/anthropic to anthropic-messages; any other package warns and assumes openai-completions. Ignored when api is set. |
baseURL | URL | Required. The API root requests go to. Missing or invalid URL skips the provider. Also read from options.baseURL (top-level wins) |
apiKey | "$ENV_VAR" | "{env:VAR}" | "!command" | false | A key saved via /connect wins over this field. It is reference to the key, never the key itself. "$VAR" and "{env:VAR}" read that env variable; "!command" runs the command and uses its output; false = keyless endpoint, no auth header sent. A pasted raw secret is refused with a warning. |
headers | object | Extra request headers, string values only. One non-string value drops the whole object with a warning |
models | object | Required. {} per id is enough. Zero valid models skips the provider |
disabled | true | Tombstone: the entry is skipped silently, no warning. "enabled": false means the same |
Every field is optional but we recommend adding contextWindow as a bare minimum. "a-model-id": {} is a complete declaration:
| Field | Values | Notes |
|---|---|---|
name | string | Display name in /model |
contextWindow | number > 0 | Tokens. Compat alias: limit.context (contextWindow wins when both are set) Default: 200K |
maxOutput | number > 0 | Tokens. Compat alias: limit.output |
reasoning | boolean | true assumes the efforts low / medium / high; false declares none |
reasoningEfforts | string[] | Exact valid set: low | medium | high | xhigh | max. Unknown levels are dropped with a warning |
cost | object | $ per 1M tokens: input, output, cacheRead, cacheWrite (snake_case cache_read / cache_write accepted); 0 is valid for free models |
options | object | Extra request-body params merged into every call for this model (temperature, top_p, …) |
api | openai-completions | openai-responses | anthropic-messages | Per-model wire override. Defaults to the provider's api. One entry can serve some models over Chat Completions, some over the Responses API, and some over the Anthropic wire. An invalid value skips this model only |
baseURL | URL | Per-model endpoint override. Defaults to the provider's baseURL. An invalid URL skips this model only |
A non-object model value skips that model with a warning; sibling models survive.
Reasoning efforts are auto-detected for known providers. If not added automatically, the onus to add them manually is on the user. Declare the supported efforts in the model's reasoningEfforts field inside the ~/.commandcode/providers.json file.
Below are examples of BYOK providers added in ~/.commandcode/providers.json. Command Code is the default provider, nothing to declare for it.
OpenRouter
Mixed wires on one gateway: a gateway whose default is OpenAI-compatible can still serve individual models over the Responses API or the Anthropic wire. Declare the exception on the model.
Vercel AI Gateway
Cloudflare AI Gateway: its OpenAI-compatible root carries your account and gateway ids, and model ids are provider/model as the gateway spells them:
Hugging Face router
Ollama (local, keyless)
Selecting a custom provider in /connect opens its card: the endpoint, its declared model count (with a clickable config: providers.json link straight to the file), the key situation, and the actions that fit.
| Key state | Card shows | Actions |
|---|---|---|
| Stored key | key sk_… ✓ stored in auth.json | enter save · r replace key · c clear · u update models · d delete |
| File reference | key $VAR | r store key · u update models · d delete |
| Keyless | no key — the endpoint asks for none | r store key · u update models · d delete |
| No key yet | no key yet — requests fail until one is added | enter add key · u update models · d delete |
In the /connect menu itself, a healthy provider row shows a green ✓ with its model count. Only ○ needs a key appears when requests would fail without action.
Update u refetches the provider's model list (registry first, the endpoint's /models as fallback) and updates the provider's models. The key reference, headers, and wire are untouched.
Delete d removes the provider. It is deleted from providers.json, its stored key is cleared, and its models leave /model immediately; if it owned your active model, the session switches to the default model.
If there is a malformed entry in providers config, it never breaks its siblings. It's skipped with a specific warning shown under the /connect list and on --list-models:
An unreadable or unparseable file warns the same way (providers config <path>: invalid JSON (details redacted)). Your providers vanish for that run instead of crashing the CLI. The /connect writers never touch a file they can't parse: an add, model refetch, or remove against broken JSON refuses with nothing written.
For setups that must never contact Command Code's backend at all (a team running the CLI against their own endpoints, CI fleets, or other environments), they can turn on local-only mode:
or persist it in ~/.commandcode/config.json:
What it guarantees:
- No telemetry, anywhere. Trace exporters, lifecycle events, telemetry identity, and machine fingerprinting are all off. (
DO_NOT_TRACK=1also stops all of these, including fingerprinting; local-only also blocks the non-telemetry backend traffic below.) - No billing reads.