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.
Install
Section titled “Install”npm install -g @codex-modules/custom-modelsFor local development from this repository:
cd modules/custom-modelsnpm installnpm run buildQuickstart
Section titled “Quickstart”Register a provider and make it the default Codex provider:
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-defaultIf 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:
codex-custom-models add \ --provider openrouter \ --base-url https://openrouter.example/v1 \ --model anthropic/claude-sonnet-4.6 \ --set-default \ --forceUse a sandbox instead of your real Codex home:
codex-custom-models add \ --codex-home /tmp/codex-home \ --provider local \ --base-url http://127.0.0.1:8000/v1 \ --model qwen3-coderList registered models:
codex-custom-models listcodex-custom-models list --jsonRemove models tracked by this module:
codex-custom-models remove --provider openrouter --model anthropic/claude-sonnet-4.6codex-custom-models remove --provider openrouter --allRollback the latest journaled transaction:
codex-custom-models rollbackCheck the install:
codex-custom-models doctorcodex-custom-models doctor --jsonimport { 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?)
How It Works
Section titled “How It Works”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 = falseAfter registration, models_cache.json is rewritten as an expired wrapper so Codex refreshes the catalog promptly.
Safety And Rollback
Section titled “Safety And Rollback”- Existing root
model_providerconflicts abort unless--force. - Existing non-owned root
model_catalog_jsonconflicts abort unless--force. - Existing non-owned provider tables for the same provider id abort unless
--force. removedeletes only slugs tracked incodex-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.
rollbackrestores 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.
Uninstall
Section titled “Uninstall”Remove all models for each provider you registered:
codex-custom-models listcodex-custom-models remove --provider openrouter --allIf you want to undo the latest write exactly:
codex-custom-models rollbackThen remove the package:
npm uninstall -g @codex-modules/custom-modelsVerification
Section titled “Verification”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:
npm run verifyAttribution
Section titled “Attribution”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.