Codex CLI
OpenAI's terminal coding agent, pointed at Melious through a custom TOML provider block
Codex is OpenAI's terminal coding agent — one codex binary from npm, configured through TOML, with a provider system that points it at any backend speaking the OpenAI Responses API. That last part is the whole story here. Codex removed Chat Completions support in February 2026, so wire_api = "responses" is the only value it accepts, and this integration rides on our Responses endpoint rather than the /v1/chat/completions route the rest of this section uses. Both are live, so pointing Codex at us is a provider block and an API key. One rough edge up front: our Responses stream delivers the finished answer in a single event instead of token by token, so Codex prints the reply all at once rather than typing it out — the answer is the same, the theater isn't.
Setup
Install Codex
Codex ships as an npm package wrapping a native binary per platform. Requires Node.js 18 or newer:
npm install -g @openai/codexOr Homebrew (macOS, Linux):
brew install codexWindows works natively in PowerShell — no WSL required, though WSL2 is fine if you'd rather the agent's sandbox ran on the Linux side.
Check it landed:
codex --versionAdd Melious as a provider
Codex reads ~/.codex/config.toml (or .codex/config.toml inside a trusted project, or wherever CODEX_HOME points). Add a provider block and select it:
model = "<MODEL_ID>"
model_provider = "melious"
model_context_window = 131072
[model_providers.melious]
name = "Melious"
base_url = "https://api.melious.ai/v1"
env_key = "MELIOUS_API_KEY"
env_key_instructions = "Create a key at melious.ai/account/api/keys"
wire_api = "responses"Exporting OPENAI_BASE_URL does not redirect Codex at us. Current releases ignore that variable and send traffic to api.openai.com regardless — you get a 401 naming OpenAI's host, which reads like an auth problem and isn't one. The provider block is the only way in.
base_url carries /v1, unlike the Anthropic-shape endpoint that Claude Code uses. No trailing slash.
Don't name the provider openai. That ID is reserved, and Codex refuses to load a config that reuses it — you get model_providers contains reserved built-in provider IDs before the session starts. Any other name is fine.
model_context_window is the window Codex plans against. It ships metadata for OpenAI's own models only, so set this from _meta.context_length on GET /v1/models?include_meta=true. Leave it out and Codex warns that it's falling back to default metadata, then plans against that instead of your model's real window.
Run a session
Codex reads the key from the environment variable named in env_key, once, at startup:
export MELIOUS_API_KEY=sk-mel-<YOUR_API_KEY>
codexWindows PowerShell:
$env:MELIOUS_API_KEY = "sk-mel-<YOUR_API_KEY>"
codexCodex prints its wiring in the session header. The provider line is the one to check:
model: <MODEL_ID>
provider: melious
approval: never
sandbox: read-onlyIf provider says anything else, model_provider didn't take.
Picking a model
Codex defaults to a gpt-5-family model name, and we don't run those. There's no name substitution on the OpenAI-shape endpoints either — only claude-* names map, and only on the Anthropic path — so an unset model fails on the first turn. Set it explicitly and keep it set.
Beyond that, Codex leans hard on long tool-call chains and multi-file edits, so pick something that holds a sequence together without losing the thread. Filter GET /v1/models?include_meta=true on _meta.capabilities.function_calling and _meta.context_length, or browse melious.ai/hub/models.
Append a flavor suffix to the model ID to bias provider selection — <MODEL_ID>:speed, :price, or :eco. See Routing for the decision table.
Profiles
A profile is a whole config file layered over your base one, named <name>.config.toml in your Codex home — not a section inside config.toml:
model = "<LIGHTWEIGHT_MODEL_ID>"
model_provider = "melious"
model_context_window = 131072codex --profile melious-fast
codex -c model_provider="melious" -m "<MODEL_ID>"There's no --provider flag; -c is how you override any config key from the command line, and it parses values as TOML before falling back to a literal string. Precedence runs CLI flags, then the profile, then project config, then user config.
Non-interactive runs
codex exec is the scripted path — same config, no TUI:
export MELIOUS_API_KEY=sk-mel-<YOUR_API_KEY>
codex exec --skip-git-repo-check "summarize the diff on this branch"
codex exec --json "run the test suite and report failures"In CI, set MELIOUS_API_KEY in the job environment rather than a dotfile — Codex reads it at launch and never re-reads it. Sandbox policy is a flag: -s read-only (the default), -s workspace-write to let it edit, -s danger-full-access when you've already decided.
What's different
- Responses, not Chat Completions. Codex is the one tool in this section that talks to
/v1/responses. Everything else here uses/v1/chat/completions. Same key, same base URL, different endpoint — andwire_api = "responses"is what selects it. OPENAI_BASE_URLis ignored. Setting it points nowhere useful. The provider block is mandatory, not a nicety.- Streaming is coarse. Our Responses stream emits
response.created,response.in_progress, andresponse.completed— no incremental text deltas. Codex renders the whole reply at once. Nothing breaks — the answer lands in one piece instead of unspooling. We'd like to fix this and haven't yet. - No
environment_impactorbilling_coston the wire. The Responses shape doesn't carry our two extension objects the way Chat Completions does. Usage is still metered and still shows up in your usage dashboard — you can't read it off the response. - No Melious CLI support.
melious tools installcovers Claude Code, OpenCode, Mistral Vibe, and Pi. Codex you wire by hand — OpenAI doesn't accept third-party providers upstream, so this page is the integration. - No explicit cache control. Nothing marks a prefix as cacheable. Transparent prefix caching still happens on the provider side and bills at the cheaper cache-read rate. See Models.
- Sandboxing is Codex's, not ours.
sandbox_modeandapproval_policygovern what the agent may touch on your machine. Unrelated to routing, but it's what usually refuses an edit.
When it breaks
401 Unauthorizednamingapi.openai.com— you exportedOPENAI_BASE_URLand expected it to redirect. It doesn't. Add the[model_providers.melious]block and setmodel_provider = "melious".stream disconnected before completion: stream closed before response.completed, after five reconnects — a model ID we don't have. Most often that's an unsetmodel, because Codex then falls back to its own default (agpt-5-family name). On a streaming request we report the failure as aresponse.errorevent, which Codex doesn't treat as terminal, so it retries instead of showing you the message. That's on us. Check the ID withGET /v1/models; a non-streaming call returns the real error,Model not found: <MODEL_ID>.warning: Model metadata for <MODEL_ID> not found— expected, and harmless. Codex ships metadata for OpenAI's own models only. Setmodel_context_windowso its planning is based on your model's real window rather than a fallback.Missing environment variable— Codex readsenv_keyonce, at launch, from the shell that launched it. Export it there, or set it in the CI job environment. Filling inenv_key_instructionsmakes this message tell the reader what to do.model_providers contains reserved built-in provider IDs— your provider is namedopenai, which Codex reserves. Rename it tomeliousand pointmodel_providerat the new name.- Config edits appear to do nothing — a project-level
.codex/config.tomlis skipped entirely in untrusted projects. Move the block to~/.codex/config.toml, trust the project, or pass-con the command line. 429mid-session — per-plan token caps, and a long agent session carries a lot of context per turn. Rate limits covers which plan lifts which limit.
Errors and retry patterns: Errors.