Area
Catalog / models
What are you trying to accomplish?
I need the Codex model catalog (model_catalog_json) to stay truthful as provider quotas shift, so that Codex's model picker and its pinned default model never point at models the proxy no longer exposes.
Concrete failure we hit (opencodex 2.55.0, macOS arm64, Codex CLI with model_provider="opencodex"):
- opencodex-catalog.json contained 5 native OpenAI slugs (gpt-5.5, gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna, gpt-6-astra) that were all listed in disabledModels and absent from GET /v1/models (upstream quota exhausted).
- POST /api/sync returned ok:true but catalogWritten:false — the rewrite was skipped because the file already existed, so the stale entries stayed.
- After deleting the file and re-posting /api/sync (catalogWritten:true), the regenerated catalog still contained the 5 disabled slugs, each with visibility:"hide".
- Separately, Codex's config.toml had model="gpt-5.6-luna" pinned while that slug was unexposed; every default run failed with rate_limit_exceeded and nothing surfaced the mismatch.
What prevents this today?
- /api/sync treats an existing catalog file as up-to-date and skips rewriting it (catalogWritten:false), even when its slug set has drifted from the live /v1/models set.
- Disabled native slugs are only omitted from the catalog when native-alias combos are configured (desktopAllowlistSuppressedNativeSlugs in src/codex/catalog/metadata.ts); otherwise they remain as visibility:"hide" rows, which the same code comments note Codex Desktop's remote allowlist can ignore.
- ocx doctor and /api/startup-health do not check whether Codex's configured default model is currently exposed by the proxy, so a quota-driven exposure change silently breaks the default path.
What should OpenCodex do?
- Rewrite on staleness, not only on absence: when /api/sync finds an existing catalog, compare its slug set (or a content hash) against the current visible set and rewrite when drifted, instead of reporting catalogWritten:false for a stale file.
- Clarify or change the contract for disabled native slugs: either omit them from the catalog unconditionally, or document that visibility:"hide" is best-effort and Codex Desktop may still list them.
- Warn on unexposed pinned default: if Codex's configured model is not in the proxy's exposed set, surface a warning in ocx doctor and/or /api/startup-health (e.g. an extra check alongside status=protected/rebootSafe).
Example usage or interface
Before/after for request 1:
# today: stale file is kept
curl -X POST localhost:10100/api/sync -H "Authorization: Bearer $TOK"
# => {"ok":true,"catalogWritten":false} # catalog still lists 5 disabled slugs
# expected: drift detected and rewritten
# => {"ok":true,"catalogWritten":true,"catalogDrift":{"removed":["gpt-5.5",...]}}
For request 3:
ocx doctor
# [WARN] Codex default model "gpt-5.6-luna" is not in the exposed model set
# (disabled or upstream quota). Pick one of: anthropic/claude-opus-4-8, ...
Alternatives or workarounds
Workaround we now run locally: delete ~/.codex/opencodex-catalog.json and re-post /api/sync to force regeneration, then manually verify the pinned default model against GET /v1/models. This is operational toil that recurs every time a provider quota resets.
Additional context
Docs consulted: https://opencodex.me/guides/model-routing/ and https://opencodex.me/reference/cli/. This failure mode (pinned default model silently dying after quota exhaustion) recurred three times in two weeks of our ops logs, which is why a built-in doctor check would be high-leverage. Happy to test a patch.
Checks
Area
Catalog / models
What are you trying to accomplish?
I need the Codex model catalog (model_catalog_json) to stay truthful as provider quotas shift, so that Codex's model picker and its pinned default model never point at models the proxy no longer exposes.
Concrete failure we hit (opencodex 2.55.0, macOS arm64, Codex CLI with model_provider="opencodex"):
What prevents this today?
What should OpenCodex do?
Example usage or interface
Before/after for request 1:
For request 3:
Alternatives or workarounds
Workaround we now run locally: delete ~/.codex/opencodex-catalog.json and re-post /api/sync to force regeneration, then manually verify the pinned default model against GET /v1/models. This is operational toil that recurs every time a provider quota resets.
Additional context
Docs consulted: https://opencodex.me/guides/model-routing/ and https://opencodex.me/reference/cli/. This failure mode (pinned default model silently dying after quota exhaustion) recurred three times in two weeks of our ops logs, which is why a built-in doctor check would be high-leverage. Happy to test a patch.
Checks