---
title: "Codex CLI custom providers: what works, what's tricky, and what's coming"
description: "A practical walkthrough of OpenAI Codex CLI's custom provider config: the TOML format, the Responses-API requirement that trips everyone up, and where jusCode fits."
tldr: "Codex CLI's custom provider config in ~/.codex/config.toml accepts any OpenAI-compatible base URL, but only over the Responses API. wire_api = \"chat\" was removed, so most open-weights hosts can't back it yet without a translation layer."
date: 2026-05-30
author: jusCode
cluster: integration
tags: codex-cli, openai-codex, custom-provider, openai-responses-api, llm-routing, byo-provider
---

# Codex CLI custom providers: what works, what's tricky, and what's coming

## What Codex CLI is

[Codex CLI](https://github.com/openai/codex) is OpenAI's open-source Rust-based coding agent, a terminal CLI that reads your repo, proposes edits, runs commands, and iterates. If you've used Claude Code, the mental model is the same: an autonomous agent loop driven by a frontier model. The default install signs into chat.openai.com via OAuth and routes everything through your OpenAI account.

## Why "custom provider" matters for Codex

Out of the box, Codex CLI talks to OpenAI's hosted endpoints over an OAuth-bound session. That's fine if your OpenAI bill is fine. It's not fine if you want to point Codex at Ollama on your laptop, at a fine-tune host running an experimental Qwen variant, at a corporate inference endpoint that never leaves your VPC, or at a routing gateway like jusCode that picks the cheapest capable model per call.

The custom-provider config is what makes those substitutions possible. Anything that speaks the right OpenAI-compatible wire format can stand in for `chat.openai.com`.

## The config file

Codex CLI reads `~/.codex/config.toml`. TOML, not JSON, not YAML. A minimal custom-provider config looks like this:

```toml
model = "<model-id>"
model_provider = "myprovider"

[model_providers.myprovider]
name = "My Provider"
base_url = "https://api.example.com/v1"
env_key = "MY_PROVIDER_API_KEY"
wire_api = "responses"
requires_openai_auth = false
```

Field by field:

- **`model`**: the model identifier Codex will send on every request. The provider has to recognize this string.
- **`model_provider`**: references one of the `[model_providers.*]` blocks below. Default for every session unless overridden by a profile.
- **`name`**: display label shown in Codex's UI; cosmetic.
- **`base_url`**: the root of the OpenAI-compatible endpoint. Codex appends paths like `/responses` itself; do not include them here.
- **`env_key`**: name of the environment variable Codex reads the API key from. You `export MY_PROVIDER_API_KEY=...` in your shell; Codex never persists the secret in the TOML file.
- **`wire_api`**: see the next section. This is the field that determines whether your setup actually works.
- **`requires_openai_auth`**: set to `false` for any non-OpenAI provider; setting it to `true` triggers Codex's OAuth flow against chat.openai.com, which a custom provider can't satisfy.

## The one thing that trips everyone up: `wire_api`

Codex only speaks the OpenAI **Responses API** now. The older `wire_api = "chat"` value (which targeted the classic `/v1/chat/completions` shape) was removed from the Codex CLI. See the [openai/codex repository](https://github.com/openai/codex) and the `config.toml` reference in its docs. So your custom provider must expose `POST /v1/responses`, not `/v1/chat/completions`.

This is the single most common failure mode for first-time custom-provider configs. The provider validates the API key, accepts the connection, and then 404s on the first tool call because it doesn't have a `/responses` route. Codex prints a generic error, the agent hangs, and the user assumes the provider list is wrong. It isn't. The wire protocol is.

Which OpenAI-compatible providers natively expose `/v1/responses` today (May 2026):

- **OpenAI**: the reference implementation.
- **DeepSeek v4 family**: Responses API support shipped in their April 2026 endpoint rollout.
- **OpenRouter**: added a Responses-compatible wrapper in Q1 2026 across its catalog.

Which providers do **not** speak Responses natively (and therefore cannot back Codex CLI directly without a translation shim):

- **Together**: Chat Completions only.
- **Fireworks**: Chat Completions only.
- **Cloudflare Workers AI**: Chat Completions only.
- Most self-hosted runtimes (vLLM, TGI, llama.cpp, Ollama): Chat Completions only out of the box.

Without a Responses route, tool calls silently drop and the agent appears to think but never to act. That's the trap.

## Profiles vs. defaults

The top-level `model_provider` is the default for every Codex session. If you want to keep your OpenAI account as the default and only opt into a custom provider for specific work, use profiles:

```toml
model = "gpt-5"
model_provider = "openai"

[profiles.work]
model = "jusCode-auto"
model_provider = "juscode"

[model_providers.juscode]
name = "jusCode"
base_url = "https://api.juscode.co/v1"
env_key = "JUSCODE_API_KEY"
wire_api = "responses"
requires_openai_auth = false
```

Then:

```sh
codex --profile work
```

Profiles are the right tool when your default already works and you want the custom provider to be deliberate. Top-level defaults are the right tool when the custom provider is your one and only setup.

## Reasoning effort

Codex sends a `reasoning.effort` field on every Responses request when the upstream model supports it. You can pin the default at the top level:

```toml
model_reasoning_effort = "high"
```

Valid values: `none`, `minimal`, `low`, `medium`, `high`, `xhigh`. Default is `medium`. This is only meaningful for reasoning-capable models (GPT-5, o-series, DeepSeek v4 reasoners, etc.); sending it to a non-reasoning model is a no-op rather than an error.

## What you can't do with custom providers (yet)

A few sharp edges worth knowing before you spend an evening debugging:

- **No XDG fallback.** Config has to live at `~/.codex/config.toml`. The XDG-conventional `~/.config/codex/` path is not read. Symlink if you care about XDG hygiene.
- **No `CODEX_PROVIDER` environment variable.** You cannot ad-hoc override the provider from the shell environment alone. The closest equivalent is the per-invocation flag: `codex -c model_provider=name`. Useful for one-off runs against a non-default provider.
- **Duplicate top-level keys break the TOML load.** If a setup script appends `model = "..."` to a file that already has `model = "..."` higher up, Codex refuses to load the config and prints a parse error. You have to edit in place, not append. Setup automation that assumes append-safety will silently corrupt the file.

## jusCode and Codex CLI

Honest status: we are shipping Codex CLI support soon. It is not shipping today.

The blocker is the Responses-vs-Chat translation layer. Our routing currently sends most coding-agent traffic to Chat-Completions-only upstreams (Together, Fireworks, Cloudflare Workers AI), and that is where the cost savings live, because those hosts are where the cheap-but-capable mid-tier models actually run. If we exposed a Responses endpoint today that fronts those upstreams without translating tool-call semantics correctly, Codex would silently drop tool calls on every routed request and quietly degrade on exactly the models that make routing worthwhile. That defeats the whole point.

So we are enhancing the gateway's Responses adapter to translate tool-call shape, streaming, and reasoning-effort fields bidirectionally: Responses on the Codex-facing side, Chat Completions on the upstream side, with full fidelity in both directions. When that's done, Codex CLI users will get the same one-line install as every other agent we support, and routing will work honestly across the catalog.

Until then, you have two choices, both described below.

If you want us to ping you when it lands, drop your email at [/preregister/?tier=codex](/preregister/?tier=codex).

## Practical workaround for now

**Option 1: Point Codex CLI at OpenAI direct.** This works today because OpenAI obviously speaks its own Responses API. You lose all of jusCode's routing benefits (every call goes to OpenAI at OpenAI's rates) but Codex CLI works end to end.

```toml
model = "gpt-5"
model_provider = "openai-direct"

[model_providers.openai-direct]
name = "OpenAI"
base_url = "https://api.openai.com/v1"
env_key = "OPENAI_API_KEY"
wire_api = "responses"
requires_openai_auth = false
```

**Option 2: Use Claude Code with jusCode for everything else.** Claude Code's wire protocol is the Anthropic Messages API, which our gateway speaks fully today. Set two environment variables and you're routed:

```sh
export ANTHROPIC_BASE_URL=https://api.juscode.co
export ANTHROPIC_AUTH_TOKEN=jcg_your_key_here
```

Full walkthrough: [/docs/claude-code/](/docs/claude-code/).

The drop-in install script for Codex CLI lands when the routing is honest. We'd rather ship late than ship a setup that quietly costs you tool calls.

## Related reading

- [Use jusCode with Claude Code](/docs/claude-code/)
- [Cline + custom endpoint](/blog/cline-custom-endpoint/)
- [Use Goose (Block) with a custom provider](/blog/goose-custom-provider/)
- [OpenAI-compatible drop-in](/docs/openai-drop-in/)

---

*Raw markdown: [/blog/codex-cli-custom-provider.md](/blog/codex-cli-custom-provider.md)*
