Skip to content
Yoink

Use a custom provider in Codex CLI

Codex CLI only talks to custom providers over the OpenAI Responses API. yoink therefore connects a provider to codex only when it has an openai-responses endpoint, and writes it as a [model_providers.<id>] table in ~/.codex/config.toml. Run yoink connect <name> --to codex --default <model> to add it and make it active.

On this page

At a glance

codex facts
FactValue
Harness idcodex
Config yoink writes~/.codex/config.toml
FormatTOML
Protocols, in order of preferenceopenai-responses
Default modelmodel = "<model>" and model_provider = "<provider>"
Path overrideCODEX_HOME
Providers at oncemany, side by side
Experimentalno
Presets that reach it1 of 7: openai
Connect commandyoink connect <name> --to codex

Generated from the yoink CLI source and docs/harnesses.md.

What yoink writes

For a provider saved under the profile id openai-api, yoink connect openai-api --to codex --default gpt-5.2-codex produces this, with the key redacted:

model = "gpt-5.2-codex"
model_provider = "openai-api"
 
[model_providers.openai-api]
name = "OpenAI"
base_url = "https://api.openai.com/v1"
wire_api = "responses"
experimental_bearer_token = "<your key>"

name is the provider's display name, base_url is its Responses endpoint, and wire_api is always "responses", which Codex's config reference lists as the only supported value. The key goes in experimental_bearer_token as a literal, because yoink keeps one key in sync across harnesses instead of asking you to export an environment variable. Your other tables and keys in config.toml are left as they were.

Which providers work

Only providers with an openai-responses endpoint can be connected. Among the presets that is openai alone:

PresetReaches codexWhy
openaiyeshas an openai-responses endpoint
kimi-code, moonshot, openrouter, deepseek, zainoChat Completions and Anthropic Messages only
ollamanoChat Completions only

In the harness picker those rows show needs an OpenAI Responses endpoint. From the command line, the attempt fails with a message that names the protocol codex needs:

✖ codex: openrouter has no endpoint codex can use (needs one of: openai-responses).

A custom provider gets a Responses endpoint when its /responses route answers yoink's probe, or when you declare it with --protocol openai-responses. See codex is responses-only for the probe details.

Pick a profile id Codex does not reserve

Codex reserves the provider ids openai, ollama and lmstudio for its built-in providers, and its config reference says they cannot be overridden. yoink uses your profile id as the table name, so save the OpenAI preset under a different id before connecting it to codex:

echo "$OPENAI_API_KEY" | yoink add --external --name openai-api --preset openai \
  --models gpt-5.2,gpt-5.2-codex --token-stdin
yoink connect openai-api --to codex --default gpt-5.2-codex

The same applies to a custom provider: avoid naming it ollama or lmstudio if you plan to use it in codex.

Set the default model

--default writes two root keys: model with the model id, and model_provider with the profile id. Codex reads model_provider to choose which provider is active, so a provider you connect without --default sits in the file unused until you pick it. Codex ignores model_provider in a project-local .codex/config.toml, which is why yoink writes the user-level file under CODEX_HOME or ~/.codex.

ChatGPT login versus API key

A model_provider that points at a custom provider overrides your ChatGPT login. When yoink sees a ChatGPT login in auth.json and the provider you just connected is the active one, it prints a notice after connecting, with the full path to your config:

Codex is set to model_provider = "openai-api" in ~/.codex/config.toml, which overrides the ChatGPT login. Run `yoink disconnect openai-api --from codex` or remove model_provider from that file to use ChatGPT.

Switching between several ChatGPT logins is a separate feature that does not touch config.toml; see switch between Codex accounts.

Backups and disconnect

The first time yoink changes an existing config.toml, it saves config.toml.yoink.bak once and never overwrites it. yoink disconnect openai-api --from codex removes the [model_providers.openai-api] table, and removes model and model_provider together when model_provider points at that provider, which hands control back to your ChatGPT login.

FAQ

Why can't codex use my OpenRouter or DeepSeek key?

Those presets expose Chat Completions and Anthropic Messages endpoints, and codex only speaks the Responses API to custom providers. yoink refuses the pairing instead of writing a config codex cannot use. The same keys still work in harnesses that accept Chat Completions, such as opencode or pi.

Why should the OpenAI profile not be named openai for codex?

It writes the table, but Codex treats openai as its built-in provider id and does not let a config table override it. Save the preset under another id such as openai-api, as shown above.

  • Switch between Codex (ChatGPT) accounts

    Save several ChatGPT logins for Codex and switch between them. yoink swaps auth.json or the Codex Auth Keychain entry and re-saves the live login first.

  • One API key in every coding agent

    Add an API key once and yoink writes it into the native config of up to 13 coding agents: pi, opencode, codex, Claude Code, Qwen Code, Crush and more.

  • Harnesses

    What yoink writes into pi, omp, opencode, codex, Claude Code, Qwen Code, Kilo, Droid, Crush, Continue, Goose, Zed and Claude Desktop: paths and keys.

  • Use any provider in pi

    Connect any OpenAI- or Anthropic-compatible provider to pi. yoink writes ~/.pi/agent/models.json with model limits from models.dev and sets the default.

  • Use any provider in omp

    Connect a provider to omp. yoink writes ~/.omp/agent/models.yml (or models.yaml), carries over a legacy models.json and sets modelRoles.default in config.yml.

  • Use any provider in opencode

    Connect OpenRouter, DeepSeek, Ollama or any compatible API to opencode. yoink edits opencode.json or .jsonc in place, keeping your comments and formatting.