This guide explains the backend-aware Codex path owned by
cli_subprocess_core.
Why Codex Needs Backend Metadata
Codex does not have a single backend shape.
The upstream CLI distinguishes:
- the default OpenAI path
- OSS mode
- the selected OSS provider
- model-provider routing
The core keeps those concepts intact instead of flattening everything into one generic external-model switch.
Current Backend Contract
For provider :codex, the core selection payload carries:
provider_backend: :openai | :oss | :model_providerbackend_metadata["oss_provider"]for OSS routingbackend_metadata["model_provider"]for model-provider routing
For the current local Ollama path, the contract is:
provider_backend: :ossbackend_metadata["oss_provider"] = "ollama"
Live CLI Assumption Check
This backend path was validated against the installed tools before the Elixir implementation landed:
codex-cli 0.116.0ollama 0.18.2
Direct CLI check:
codex exec --json \
--config 'model_provider="ollama"' \
--config 'model="gpt-oss:20b"' \
"Respond with exactly: OK"
The more general local route also runs with arbitrary installed models such as
llama3.2:
codex exec --json \
--config 'model_provider="ollama"' \
--config 'model="llama3.2"' \
"Respond with exactly: OK"
Upstream does not hard-reject that model. Instead, when the slug is missing from Codex's own model metadata catalog, the CLI warns and uses fallback model metadata. That distinction matters:
gpt-oss:20bis the default validated OSS model- arbitrary Ollama models can still run
- fallback metadata can degrade behavior on those non-catalog models
What Core Owns
CliSubprocessCore.ModelRegistry owns:
- validating the requested Codex backend
- validating that the selected OSS provider is supported
- validating Ollama availability and minimum version
- validating the external model id
- choosing the effective default model for the backend
- returning the resolved payload consumed by downstream renderers
CliSubprocessCore.Ollama owns the actual HTTP checks used by the Codex OSS
path:
- version lookup
- installed-model lookup
- running-model lookup
- model-detail validation
Current Ollama Rules
The current long-term supported Codex external path is local Ollama.
Core rules:
- minimum Ollama version:
0.13.4 - default Codex OSS model:
gpt-oss:20b - arbitrary installed Ollama models are accepted on the shared Codex/Ollama route
- explicit local provider required conceptually, even though the current core
defaults the OSS provider to
ollamafor the local path - model ids are validated through Ollama before the payload is returned
- the feature manifest records which models are the validated defaults, not a hard allowlist
- non-default models may still trigger upstream fallback metadata behavior
The resolved payload includes:
resolved_modelreasoningprovider_backendbackend_metadata["oss_provider"]backend_metadata["loaded"]backend_metadata["support_tier"]- model-family and catalog visibility fields
Downstream Consumption
Downstream repos do not make a second backend decision.
In this stack:
CliSubprocessCore.ProviderProfiles.Codexrenders payload-owned--configoverrides formodel_providerandmodelon the local Ollama path, and closes stdin on start for one-shot exec runs so upstream Codex does not wait for EOF after argv prompts/home/home/p/g/n/codex_sdkreads the same payload inCodex.Options,Codex.Runtime.Exec, and app-server startup/home/home/p/g/n/agent_session_managerforwards Codex backend intent into the core registry and passes the resolved payload through unchanged
Example
{:ok, selection} =
CliSubprocessCore.ModelRegistry.build_arg_payload(
:codex,
"gpt-oss:20b",
provider_backend: :oss,
oss_provider: "ollama"
)
selection.provider_backend
# => :oss
selection.backend_metadata["oss_provider"]
# => "ollama"Reviewer Checklist
When reviewing Codex backend changes, verify:
- backend policy stays in
CliSubprocessCore.ModelRegistry - provider renderers only read payload fields
- local Ollama validation stays explicit and hard-failing
- validated defaults stay metadata, not an invented hard allowlist
- blank or placeholder model ids still fail
- no renderer emits stale Codex OSS argv flags when the upstream CLI expects config-driven model-provider routing