Skip to main content

Codex CLI

Codex CLI can call GenAI Smart Router through the OpenAI Responses-compatible API. Use a router-issued caller token in an environment variable.

These docs are built into the hosted GenAI Smart Router server delivered for your deployment. Examples that show the router base URL use this browser origin, so on this deployment they render as https://<router-host> and https://<router-host>/v1.

For Codex CLI deployment access, contact contact@metrum.ai.

One-Shot Check

Use one of the model group IDs returned by /v1/models for model. See Available Models And Access if you need to check which groups your token can request.

Record the Codex CLI version used for deployment validation with codex --version; CLI flags can change over time.

Codex also needs Codex-native metadata for deployment-defined group names. Fetch the caller-filtered catalog with the same token before starting Codex. The catalog contains only safe group-level behavior metadata; it does not expose upstream providers, targets, weights, credentials, or routing policy.

export METRUM_ROUTER_KEY="rtr_metrum_<user>_<project>_<env>_<key>_<secret>"
export METRUM_ROUTER_URL="https://<router-host>"

umask 077
mkdir -p "$HOME/.codex"
curl -fsS "$METRUM_ROUTER_URL/v1/codex/models.json" -H "Authorization: Bearer $METRUM_ROUTER_KEY" -o "$HOME/.codex/metrum-models.json"

/v1/models remains the caller-facing source of allowed groups. /v1/codex/models.json is its Codex-compatible Responses projection: it includes only groups with a normal text target eligible for Responses, natively or through a validated Responses-to-Chat bridge. A 401 or 403 means the caller token cannot fetch the catalog; a missing group can be disallowed or unavailable to Codex's Responses surface.

If Codex should show reasoning choices for a group, /v1/models is the caller-facing source of truth. The group entry and the Codex catalog should include supported_reasoning_levels and default_reasoning_level for the same router token that Codex uses. When active reasoning is not advertised, the catalog omits both reasoning-default fields (default_reasoning_level and default_reasoning_summary), even if source config or provider catalogs mention reasoning.

export METRUM_ROUTER_KEY="rtr_metrum_<user>_<project>_<env>_<key>_<secret>"

codex exec --ignore-user-config --ephemeral --ignore-rules --skip-git-repo-check -c 'model="<allowed-model-group>"' -c 'model_provider="metrum-router"' -c 'model_catalog_json="~/.codex/metrum-models.json"' -c 'model_providers.metrum-router.name="Metrum Router"' -c 'model_providers.metrum-router.base_url="https://<router-host>/v1"' -c 'model_providers.metrum-router.env_key="METRUM_ROUTER_KEY"' -c 'model_providers.metrum-router.wire_api="responses"' "Reply with exactly: router codex ok" </dev/null

exec is required for these non-interactive flags. The top-level interactive codex command does not accept every codex exec flag.

The fetch must complete before codex exec. Do not hand-create entries for raw upstream model IDs: select a group returned by /v1/models and use the generated local catalog file. Without it, Codex can fall back to generic metadata for an unknown group name; routing can still work, but coding-agent behavior may be less accurate.

Interactive Usage

export METRUM_ROUTER_KEY="rtr_metrum_<user>_<project>_<env>_<key>_<secret>"

codex -c 'model="<allowed-model-group>"' -c 'model_provider="metrum-router"' -c 'model_catalog_json="~/.codex/metrum-models.json"' -c 'model_providers.metrum-router.name="Metrum Router"' -c 'model_providers.metrum-router.base_url="https://<router-host>/v1"' -c 'model_providers.metrum-router.env_key="METRUM_ROUTER_KEY"' -c 'model_providers.metrum-router.wire_api="responses"'

Tool Smoke

Agentic tool calls should be tested with real file and shell activity inside a disposable container or equivalent isolated workspace. Pass only the router base URL and a scoped router token into the sandbox, and mount only the scratch directory where the smoke file should be written. Tool-bearing requests bypass response caching because the filesystem and shell state are part of the result.

Codex sends OpenAI Responses traffic. A model group may contain native Responses targets and validated Chat-only targets exposed through the router's stateless Responses-to-Chat bridge. The bridge is deployment-controlled and request-shape gated; text and basic function tools can use a bridged Chat target when the target has responses_to_chat metadata. Responses reasoning can use a bridged Chat target only when responses_to_chat.reasoning and compatible target reasoning metadata were validated for that exact upstream. Stateful previous_response_id, provider-hosted tools, images, structured output, and streaming need separately validated targets.

mkdir -p "$PWD/codex-tool-smoke"
curl -fsS "https://<router-host>/v1/codex/models.json" -H "Authorization: Bearer $METRUM_ROUTER_KEY" -o "$PWD/codex-tool-smoke/metrum-models.json"
docker run --rm --network host --cap-drop ALL --security-opt no-new-privileges --cpus 1 --memory 1g --pids-limit 256 --read-only --tmpfs /tmp:rw,nosuid,nodev,size=256m --mount type=bind,source="$PWD/codex-tool-smoke",target=/workspace -e "METRUM_ROUTER_KEY=$METRUM_ROUTER_KEY" -e "ROUTER_BASE_URL=https://<router-host>/v1" -w /workspace "$TOOL_SMOKE_IMAGE" codex exec --ignore-user-config --ephemeral   --ignore-rules   --skip-git-repo-check   --dangerously-bypass-approvals-and-sandbox   -C /workspace   -c 'model="<allowed-model-group>"'   -c 'model_provider="metrum-router"'   -c 'model_catalog_json="/workspace/metrum-models.json"'   -c 'model_providers.metrum-router.name="Metrum Router"'   -c 'model_providers.metrum-router.base_url="https://<router-host>/v1"'   -c 'model_providers.metrum-router.env_key="METRUM_ROUTER_KEY"'   -c 'model_providers.metrum-router.wire_api="responses"'   "Create codex_tool_smoke.txt containing exactly codex-tool-ok, run cat codex_tool_smoke.txt, then finish with codex-tool-ok." </dev/null

Image Smoke

Codex CLI supports image attachments with --image. Use the same deployment-defined coding model group for mixed code and image tasks. Some hosted examples use big-coder as a coding-oriented group name; your deployment may use a different group name. The router receives image attachments as OpenAI Responses image inputs and filters that request to multimodal tool-capable upstream targets inside the group.

mkdir -p tmp/router-vision-smoke
mkdir -p "$HOME/.codex"
curl -fsS "https://<router-host>/v1/codex/models.json" -H "Authorization: Bearer $METRUM_ROUTER_KEY" -o "$HOME/.codex/metrum-models.json"
curl -fsSL "https://cdn.learnopencv.com/wp-content/uploads/2018/06/04100007/receipt.png" -o tmp/router-vision-smoke/receipt.png

codex exec --ignore-user-config --ephemeral --ignore-rules --skip-git-repo-check --image tmp/router-vision-smoke/receipt.png -c 'model="<allowed-model-group>"' -c 'model_provider="metrum-router"' -c 'model_catalog_json="~/.codex/metrum-models.json"' -c 'model_providers.metrum-router.name="Metrum Router"' -c 'model_providers.metrum-router.base_url="https://<router-host>/v1"' -c 'model_providers.metrum-router.env_key="METRUM_ROUTER_KEY"' -c 'model_providers.metrum-router.wire_api="responses"' "Read the attached receipt image. Reply with only the merchant name." </dev/null

Image-bearing Codex requests bypass router response caching. Codex is offered image attachment for a group only when the caller-filtered catalog finds an eligible mixed text/image Responses path for that exact group. That path can be native Responses or a bridge explicitly validated with image support; a text-only bridge or target-level image request-shape exclusion leaves image metadata out of the catalog and the request is safely rejected before upstream. Usage records include input_has_image, image count, and VLM cost fields when the upstream returns enough usage detail.

For the full VLM routing configuration and equivalent API examples, see Image Analysis And VLM Routing.

For the broader coding-agent validation matrix, including opencode, aider, and IDE/agent clients, see Coding-Agent Client Matrix.