Guide

Codex CLI and Desktop App with Local Models

Point OpenAI Codex at your own Macs. One provider block in config.toml, no model map to maintain, and the same fleet routing that serves Claude Code. Verified end to end on both the CLI and the desktop app.

TL;DR

Add this to ~/.codex/config.toml, then run codex:

model_provider = "herd"

[model_providers.herd]
name = "Ollama Herd"
base_url = "http://localhost:11435/v1"
wire_api = "responses"

No model map needed. Herd auto-routes whatever model id Codex sends to the best coding model you actually have loaded. Pull a model and go:

ollama pull qwen3-coder:30b

The same config block also works for the Codex desktop app, which reads the same file. See Quickstart if the herd is not running yet.

First, the wall you probably just hit

If you tried pointing Codex at Ollama, LM Studio, or any OpenAI-compatible server and it failed, this is why: Codex removed Chat Completions support in February 2026. wire_api = "responses" is the only valid value now, and it is the default.

That breaks most advice you will find. A server that implements only /v1/chat/completions cannot serve Codex at all, no matter how OpenAI-compatible it is otherwise. Guides still showing wire_api = "chat" predate the change.

Ollama Herd implements the Responses API directly at /v1/responses, so there is no translating gateway in the middle. That is what the wire_api = "responses" line above is telling Codex.

The config mistake that costs an hour

If you are appending to an existing ~/.codex/config.toml, model_provider = "herd" must go above the first [table] header. TOML assigns a bare key to whatever table precedes it, so pasting it at the bottom silently turns it into desktop.model_provider. Codex never sees it, no error is raised, and it quietly keeps using the default provider.

model_provider = "herd"     # first line, before ANY [section]

[some.existing.section]
...

[model_providers.herd]      # a table header, so this can live anywhere

Using the Codex desktop app

No extra setup. The macOS desktop app reads the same ~/.codex/config.toml as the CLI, so the one provider block above serves both surfaces. Configure it once, and the app routes to your fleet the next time you open it.

Three things behave differently in the app, all verified against a real conversation:

Everything else on this page, the provider block, the TOML gotcha, model resolution, and troubleshooting, applies identically to both surfaces.

Verified end to end, on both surfaces

Plenty of projects document Codex on local models. This one was run against a real client on a real fleet, and the findings are published rather than asserted.

Then a 26 hour soak across every code change in the release: 11,925 requests at 99.85% success, including 302 requests to /v1/responses with zero failures. The 18 failures all trace to a known slowness issue with one specific model, not to the Codex path.

Verification also found bugs unit tests had not, including tool calls being dropped in both directions and a model-listing schema that failed Codex's whole decode. Those are fixed. Spec-complete is not the same as client-verified.

Getting good results

Three things make the difference between a loop that finishes and one that wanders, all measured on local models:

Budget for tokens too: a one-line fix cost about 109K tokens end to end, because agentic loops resend the whole conversation each turn and Codex's system prompt alone is around 27 KB.

How model selection works

Codex sends a model id such as gpt-5-codex. Herd resolves it in this order:

  1. You pinned it. An explicit FLEET_ANTHROPIC_MODEL_MAP entry for that id wins.
  2. It names a real local model. If the id matches a model your fleet actually has (qwen3-coder:30b), it is used as-is. This is why codex -m qwen3-coder:30b works.
  3. Auto-routing, the default. Otherwise Herd picks the best coding model currently loaded across the fleet, falling back to the best one on disk.
  4. Nothing available. A clear 404 telling you to pull a model.

To pin one id without affecting anything else:

export FLEET_ANTHROPIC_MODEL_MAP='{"gpt-5-codex": "qwen3-coder:30b"}'

To disable auto-routing and require an explicit map, set FLEET_ANTHROPIC_AUTO_ROUTE=false.

What the fleet gives you

Choosing a model

Codex calls tools constantly, so tool-use quality matters more than chat quality. Coding-tuned models with a real tool-call parser hold up; general chat models drop calls and hallucinate arguments.

We verified with qwen3-coder:30b (about 19 GB, 256K context). Newer coding families have since landed in Ollama's library: Qwen 3.6, Gemma 4, GLM-5, Kimi K2 Code, DeepSeek V4. See the current tool-capable list.

You do not need to tell Herd which one you picked. Auto-routing sends Codex to the best coding model you have loaded, so upgrading is ollama pull and nothing else.

Limitations, stated plainly

Troubleshooting

404 not available on any node. You have not pulled a chat or coding model, or the one you pinned is not on the fleet. Run ollama pull qwen3-coder:30b, or check curl localhost:11435/v1/models.

Codex errors about the wire protocol. Confirm wire_api = "responses" in ~/.codex/config.toml. wire_api = "chat" was removed from Codex in February 2026.

400 previous_response_id not supported. Your client is using server-side conversation state. Stateless mode, which Codex uses by default, is what Herd supports.

Codex ignores your config entirely. Check that model_provider = "herd" sits above the first [table] header. See the config mistake above.

Tool calls come back as plain text. The model is too small or not coding-tuned. Switch to one of the recommended models above.

Related Reading