Docs menu

Codex CLI

Codex CLI talks to model providers over the OpenAI Responses wire, which Sator serves at POST /v1/responses — stateless, which is exactly how Codex uses it: it sends store: false and the whole conversation on every turn. State: verified against Codex CLI 0.149.

Install#

bash
npm install -g @openai/codex

Configure#

Add a provider and make it the default in ~/.codex/config.toml:

toml
model = "muse-spark-1.2"
model_provider = "sator"
web_search = "disabled"

[model_providers.sator]
name = "Sator"
base_url = "https://sator-api.princep.org/v1"
env_key = "SATOR_API_KEY"
wire_api = "responses"

Then export the key in the shell Codex runs from:

bash
export SATOR_API_KEY=sk-sator-v1-...

wire_api must be "responses"; it is the only value Codex accepts. web_search = "disabled" keeps Codex from sending OpenAI's built-in web-search tool, which no model here can run — on a model that is not Responses-native the request is refused rather than the tool silently dropped. The key stays in the environment — env_key names the variable, and nothing secret goes into the file. Pick any model id from Models; Codex does not know Sator's ids, so model must be set explicitly, and /model inside a session switches between ids you type, not a list.

To keep Sator beside another provider, put model and model_provider under a profile instead and start Codex with --profile sator:

toml
[profiles.sator]
model = "muse-spark-1.2"
model_provider = "sator"

Verify#

bash
codex exec "Reply with the single word pong."

A working setup prints pong and the request appears on your dashboard with the model you named.

Troubleshooting#

  • 401 on the first requestSATOR_API_KEY is not exported in the shell Codex was started from, or env_key names a different variable.
  • 404 on the first requestbase_url is missing its /v1.
  • 400 invalid_body naming tools of type web_searchweb_search = "disabled" is missing from config.toml; Codex sends the tool by default.
  • 400 unsupported_parameter — the request named previous_response_id; Codex does not send it over HTTP, so this is another client on the same provider entry. See Responses.
  • Reasoning is not shown — Codex asks for a reasoning summary with model_reasoning_summary; models that are not Responses-native return a summary only when one is asked for. Set model_reasoning_summary = "auto".
  • Answers stop short — Codex caps output at its own model_max_output_tokens; a value above the model's max output is lowered to it, never rejected.