Skip to content

custom-models

Register Responses-API-compatible model slugs in the official Codex app/CLI model picker.

This package writes Codex-native files under CODEX_HOME: a provider block in config.toml, a root-level model_catalog_json, and a catalog JSON built by cloning a native Codex model entry. It does not run a proxy, server, account pool, OAuth flow, or model discovery service.

Terminal window
npm install -g @codex-modules/custom-models

For local development from this repository:

Terminal window
cd modules/custom-models
npm install
npm run build

Register a provider and make it the default Codex provider:

Terminal window
codex-custom-models add \
--provider openrouter \
--name "OpenRouter" \
--base-url https://openrouter.example/v1 \
--model anthropic/claude-sonnet-4.6 \
--model google/gemini-3-pro \
--set-default

If config.toml already has a root model_provider or a non-owned model_catalog_json, the command aborts. Re-run with --force only when you intentionally want this module to take over the Codex catalog root key or proceed with an existing default provider:

Terminal window
codex-custom-models add \
--provider openrouter \
--base-url https://openrouter.example/v1 \
--model anthropic/claude-sonnet-4.6 \
--set-default \
--force

Use a sandbox instead of your real Codex home:

Terminal window
codex-custom-models add \
--codex-home /tmp/codex-home \
--provider local \
--base-url http://127.0.0.1:8000/v1 \
--model qwen3-coder

List registered models:

Terminal window
codex-custom-models list
codex-custom-models list --json

Remove models tracked by this module:

Terminal window
codex-custom-models remove --provider openrouter --model anthropic/claude-sonnet-4.6
codex-custom-models remove --provider openrouter --all

Rollback the latest journaled transaction:

Terminal window
codex-custom-models rollback

Check the install:

Terminal window
codex-custom-models doctor
codex-custom-models doctor --json
import {
doctor,
listModels,
planRegister,
registerModels,
removeModels,
rollback,
} from "@codex-modules/custom-models";
await registerModels({
codexHome: "/tmp/codex-home",
providerId: "openrouter",
providerName: "OpenRouter",
baseUrl: "https://openrouter.example/v1",
setDefaultProvider: true,
models: [
{
slug: "anthropic/claude-sonnet-4.6",
displayName: "Claude Sonnet 4.6",
contextWindow: 200000,
inputModalities: ["text"],
reasoningEfforts: ["low", "medium", "high"],
},
],
});

The package exports:

  • planRegister(options)
  • registerModels(options)
  • listModels(options?)
  • removeModels(options)
  • rollback(options?)
  • doctor(options?)

codex-custom-models reads the native Codex catalog shape from the active catalog or models_cache.json. A conservative built-in template is used when neither exists. It clones one native entry for each custom model, preserves unknown catalog fields, changes the slug to <provider>/<model>, updates the display metadata, and removes native-only fast-tier fields such as service_tier, service_tiers, default_service_tier, and additional_speed_tiers.

model_catalog_json and, when requested, model_provider are written at the TOML document root before the first table header. The provider table is appended as a marked owned block:

model_provider = "openrouter"
model_catalog_json = "/Users/me/.codex/codex-custom-models-catalog.json"
# Auto-injected by codex-custom-models
[model_providers."openrouter"]
name = "OpenRouter"
base_url = "https://openrouter.example/v1"
wire_api = "responses"
requires_openai_auth = false

After registration, models_cache.json is rewritten as an expired wrapper so Codex refreshes the catalog promptly.

  • Existing root model_provider conflicts abort unless --force.
  • Existing non-owned root model_catalog_json conflicts abort unless --force.
  • Existing non-owned provider tables for the same provider id abort unless --force.
  • remove deletes only slugs tracked in codex-custom-models-state/state.json.
  • Every normal write creates a transaction journal and backup files under CODEX_HOME/codex-custom-models-state/.
  • Registration and removal automatically restore every touched file if any write in the transaction fails.
  • rollback restores journaled files only when their current hashes still match the transaction. If a file changed after the transaction, rollback skips that file and reports it.
  • State, catalogs, profiles, journals, and backups are confined to the resolved CODEX_HOME; corrupt state and journals fail closed.

doctor verifies tracked catalog entries and asks the official Codex app-server model/list method whether every tracked model is actually picker-visible. An unavailable app-server is reported as a warning; a reachable picker that omits a tracked model is a failure.

Remove all models for each provider you registered:

Terminal window
codex-custom-models list
codex-custom-models remove --provider openrouter --all

If you want to undo the latest write exactly:

Terminal window
codex-custom-models rollback

Then remove the package:

Terminal window
npm uninstall -g @codex-modules/custom-models

The verification scripts use temporary CODEX_HOME sandboxes and never touch your real ~/.codex. The behavioral check uses the documented app-server lifecycle and model/list API:

Terminal window
npm run verify

Parts of the Codex home resolver, root TOML editing, catalog cloning, cache invalidation, and journal rollback logic are adapted from opencodex, licensed under the MIT License.