Area
Catalog / models
What are you trying to accomplish?
Make provider/model names readable in the dashboard, model picker, /v1/models, ocx models --json, usage views, and client exports without changing the canonical identifier used for routing.
What prevents this today?
The catalog currently conflates the machine-facing routed slug with the human-facing display name for automatically discovered provider models. In the local v2.28.0 catalog snapshot, NVIDIA NIM is exposed as:
| Field |
Current value |
| Provider |
nvidia |
| Routed slug |
nvidia/deepseek-ai-deepseek-v4-flash-0731 |
| Display name |
nvidia/deepseek-ai-deepseek-v4-flash-0731 |
That is technically unambiguous but poor for scanning. The same problem appears in the discovered NVIDIA rows nvidia/moonshotai-kimi-k3, nvidia/nvidia-nemotron-3.5-lightning-30b-a3b, and nvidia/z-ai-glm-5.2: the provider namespace and vendor path are repeated in the visible label.
The code already has a useful precedent: customModels[].displayName is display-only and is carried into the catalog without changing routedSlug(provider, modelId). That field does not provide an operator-facing override for ordinary live-discovery rows, which are the rows producing the unreadable labels.
What should OpenCodex do?
Add explicit, validated display metadata for discovered provider models while keeping identity and routing separate. At minimum, support:
- Canonical provider name / provider id — immutable routing key, for example nvidia.
- Native model id — the provider wire identifier, for example deepseek-ai/deepseek-v4-flash-0731.
- Routed slug — the stable public selector, for example nvidia/deepseek-ai-deepseek-v4-flash-0731.
- Configurable model display name — a short human-readable label, for example DeepSeek V4 Flash.
- Optional provider display name — for example NVIDIA NIM, so the UI can show DeepSeek V4 Flash (NVIDIA NIM) without embedding provider text in the model name.
- Optional description or vendor field — useful for tooltips/details, but never used as an identifier.
- Display-name source/precedence — explicit operator override, provider metadata, upstream marketing name, then the current slug fallback.
- Clear/reset semantics — removing an override must restore the derived name deterministically.
- Scope controls — allow a per-provider map for discovered models and a per-model override for exceptions.
- Migration compatibility — existing customModels[].displayName values and existing slugs must continue to work unchanged.
The override should be usable from config.json, the Management API, and the dashboard. A possible configuration shape is:
{
"providers": {
"nvidia": {
"displayName": "NVIDIA NIM",
"modelDisplayNames": {
"deepseek-ai/deepseek-v4-flash-0731": "DeepSeek V4 Flash",
"moonshotai/kimi-k3": "Kimi K3"
}
}
}
}
The exact field names are open for design; the important contract is that display metadata is separate from the provider id, native model id, routed slug, pricing key, disabled-model key, fallback key, and wire request model.
Example usage or interface
Before:
nvidia/deepseek-ai-deepseek-v4-flash-0731
nvidia/moonshotai-kimi-k3
nvidia/nvidia-nemotron-3.5-lightning-30b-a3b
After applying the overrides above:
DeepSeek V4 Flash (NVIDIA NIM)
Kimi K3 (NVIDIA NIM)
Nemotron 3.5 Lightning 30B (NVIDIA NIM)
The client must still send the original routed slug, and the proxy must still resolve the original provider/model pair. Renaming a display value must not create a second catalog row, alter cost matching, invalidate a saved selection, or change a Claude/Codex alias.
Alternatives or workarounds
Today an operator can create a separate custom model entry with a displayName, but that duplicates a live-discovered model and is not a good solution for a provider catalog that changes over time. Editing generated cache files is also non-persistent and is overwritten by discovery/sync. A client-side label map would need to be repeated independently in every consuming application.
Additional context
Evidence was checked against the v2.28.0 migration stack and the local generated catalog. Relevant implementation precedent:
- src/server/management/model-routes.ts already accepts and validates displayName for custom models.
- src/codex/catalog/provider-fetch.ts already propagates custom display names as display-only metadata.
- src/codex/catalog/effort.ts documents that display names must not affect routing slug, alias collision, provider behavior, or native identity.
- src/codex/catalog/parsing.ts carries CatalogModel.displayName as a display-only field.
This request is therefore an extension of an existing separation contract to ordinary live-discovery rows, not a request to rename wire models. Related catalog issues include #1690 (retain configured models), #1649 (picker ordering), and #1760 (context metadata import), but none of them provides configurable human-readable names for discovered rows.
Checks
Area
Catalog / models
What are you trying to accomplish?
Make provider/model names readable in the dashboard, model picker, /v1/models, ocx models --json, usage views, and client exports without changing the canonical identifier used for routing.
What prevents this today?
The catalog currently conflates the machine-facing routed slug with the human-facing display name for automatically discovered provider models. In the local v2.28.0 catalog snapshot, NVIDIA NIM is exposed as:
That is technically unambiguous but poor for scanning. The same problem appears in the discovered NVIDIA rows nvidia/moonshotai-kimi-k3, nvidia/nvidia-nemotron-3.5-lightning-30b-a3b, and nvidia/z-ai-glm-5.2: the provider namespace and vendor path are repeated in the visible label.
The code already has a useful precedent: customModels[].displayName is display-only and is carried into the catalog without changing routedSlug(provider, modelId). That field does not provide an operator-facing override for ordinary live-discovery rows, which are the rows producing the unreadable labels.
What should OpenCodex do?
Add explicit, validated display metadata for discovered provider models while keeping identity and routing separate. At minimum, support:
The override should be usable from config.json, the Management API, and the dashboard. A possible configuration shape is:
The exact field names are open for design; the important contract is that display metadata is separate from the provider id, native model id, routed slug, pricing key, disabled-model key, fallback key, and wire request model.
Example usage or interface
Before:
After applying the overrides above:
The client must still send the original routed slug, and the proxy must still resolve the original provider/model pair. Renaming a display value must not create a second catalog row, alter cost matching, invalidate a saved selection, or change a Claude/Codex alias.
Alternatives or workarounds
Today an operator can create a separate custom model entry with a displayName, but that duplicates a live-discovered model and is not a good solution for a provider catalog that changes over time. Editing generated cache files is also non-persistent and is overwritten by discovery/sync. A client-side label map would need to be repeated independently in every consuming application.
Additional context
Evidence was checked against the v2.28.0 migration stack and the local generated catalog. Relevant implementation precedent:
This request is therefore an extension of an existing separation contract to ordinary live-discovery rows, not a request to rename wire models. Related catalog issues include #1690 (retain configured models), #1649 (picker ordering), and #1760 (context metadata import), but none of them provides configurable human-readable names for discovered rows.
Checks