Skip to content

Model Ordering

The Codex model picker does not preserve the order of provider declarations or model arrays in the opencodex configuration. Its final order comes from catalog priorities, with a deterministic alphabetical order for routed models that share the same priority.

Codex’s models-manager sorts picker-visible catalog entries by priority in ascending order. It discards the catalog array order, so moving an entry earlier in a generated JSON array does not move it earlier in the picker. The implementation records this constraint directly in src/codex/catalog/sync.ts.

opencodex therefore controls featured placement by assigning lower priorities, not by relying on array position. Unless noted otherwise, the fixed priorities and worked example below describe a catalog with no eligible Codex account selectors. With N eligible selectors, featured priorities use N as a stride: a bare native choice at configured rank i expands to selector rows at priorities i * N + j, where j is the selector’s zero-based position; a routed choice uses i * N; and an exact selector-qualified choice uses i * N + j for its selector. Unselected routed rows are moved outside those selector groups. Codex still advertises only the first five picker-visible rows.

Without complete-picker ordering, the relevant no-selector priorities are:

Catalog entry Priority Source
subagentModels[i] i (0 through 4) The featured rank map in src/codex/catalog/sync.ts
Other routed models 5 Routed entry creation in src/codex/catalog/sync.ts
Non-featured routed models listed in modelPickerOrder 1000 + i Display-only picker rank in src/codex/catalog/sync.ts
Native GPT slugs by default 9 Native entry creation in src/codex/catalog/sync.ts
Unselected native models while a featured list exists At least featured.length + 100 Native catalog merge in src/codex/catalog/sync.ts

The management API limits subagentModels to five entries with slice(0, 5) in src/server/management/agent-settings-routes.ts. This matches the Codex spawn_agent surface, which advertises only the first five model overrides. Models outside those five can still remain visible in the main picker and callable by their exact id.

All ordinary routed models have priority 5, so they need a tie-breaker. Before catalog entries are built, gatherRoutedModels() sorts the routed model list by provider name and then by model id, both alphabetically (src/codex/catalog/provider-fetch.ts).

This means neither of these configuration details changes the final order:

  • the declaration order of keys in the providers object;
  • the order of ids in a provider’s models array.

orderForSubagents() then uses a stable sort to move configured featured picks to the front in the same order as subagentModels. Non-featured models keep the provider/id alphabetical relative order established earlier (src/codex/catalog/sync.ts). The featured rank is also converted to priorities 0 through 4 when entries are built, so Codex’s priority sort preserves that leading sequence.

selectedModels and disabledModels decide which routed models are exposed; they are not ordering controls. filterCatalogVisibleModels() converts both selections to Set lookups and filters the gathered list without using the arrays as ranks (src/codex/catalog/provider-fetch.ts).

As a result, reordering selectedModels or disabledModels has no effect on picker position. It can only change whether a model is included.

With no eligible account selectors and a non-empty featured list, the resulting order is:

  1. Models in the exact configured subagentModels order, with priorities 0 through 4.
  2. All remaining routed models, ordered alphabetically by provider and then model id, at priority 5.
  3. Unselected native models, pushed below the featured block during catalog merge.

Without subagentModels, routed models remain at priority 5, native GPT entries use their normal priority (normally 9 for entries built by opencodex), and the routed group remains provider/id alphabetical.

Suppose subagentModels contains these five ids in this exact order:

subagentModels = [
"gpt-5.5",
"opencode-go/glm-5.2",
"anthropic/claude-opus-4-6",
"gpt-5.6-sol",
"gpt-5.6-terra",
]

The picker begins as follows:

Picker position Model Priority Why it appears there
1 gpt-5.5 0 First subagentModels selection
2 opencode-go/glm-5.2 1 Second selection, even though its provider sorts after anthropic
3 anthropic/claude-opus-4-6 2 Third selection
4 gpt-5.6-sol 3 Fourth selection
5 gpt-5.6-terra 4 Fifth selection
6 anthropic/claude-fable-5 5 First remaining routed id in provider/id alphabetical order
7 onward Remaining routed models 5 Provider alphabetically, then model id alphabetically
After routed models Remaining native models featured.length + 100 or higher Unselected natives are moved below the featured block

The first five entries are the overrides advertised to spawn_agent; the rest continue in the normal picker order. With account selectors, the five-entry limit applies after bare native choices have expanded into selector-qualified groups.

Use subagentModels to choose and order the leading models that Codex also advertises to spawn_agent. The dashboard’s Sub-agents page can reorder bare native and routed ids. Use ocx agent subagents set or edit the opencodex configuration for exact <selector>/<native-openai-model> choices; the dashboard retains those ids once saved, including choices currently unavailable. Use at most five configured ids. With account selectors, one bare native choice can expand into multiple selector-qualified catalog rows, so configured choices and advertised rows are not necessarily one-to-one.

Use modelPickerOrder for display-only ordering of routed <provider>/<model> rows beyond that featured block:

{
"modelPickerOrder": [
"tyler/deepseek-v4-pro",
"jd-chat/kimi-k3",
"jd-chat/glm-5.2"
]
}

Listed routed rows appear in the configured order. A routed row omitted from the array keeps its normal priority, so it remains ahead of the modelPickerOrder display band; list every routed row whose relative position you want to control. A row also present in subagentModels keeps its featured priority. With a routed-only list, native rows keep their normal positions.

To order the complete picker, include a bare native id:

{
"modelPickerOrder": ["gpt-5.6-sol", "opencode-go/glm-5.3"]
}

Listed rows appear first in array order, followed by unlisted rows in natural priority order. Matching uses exact catalog ids: gpt-5.6-sol and openai/gpt-5.6-sol are separate rows. Raw and encoded spellings of the same routed id are also accepted, with exact matches taking precedence. Empty entries are ignored. Account-qualified rows need their selector-qualified id in the list.

Migration note: native ids in existing orders

Section titled “Migration note: native ids in existing orders”

Previously, native ids in modelPickerOrder were ignored. An existing list containing a bare native id now activates complete-picker ordering, including featured rows. Remove bare native ids to keep the previous routed-only behavior. Unset, empty and routed-only lists retain their behavior; OpenCodex’s natural-priority guidance candidate calculation is unchanged.

modelPickerOrder preserves OpenCodex’s natural-priority calculation of up to five preferred candidates for subagent guidance. Each moved row retains its natural priority separately from its native priority; changing picker order alone must not change that OpenCodex calculation. It does not restrict eligibility for an exact-name model override: the native advertised list is not an allowlist, and existing authentication, model/effort and backend constraints still apply.

Native Codex uses native priority to select the first five eligible picker-visible models advertised by spawn_agent on V1 and on V2 when model overrides are exposed. Those advertised five may therefore change with picker order, even when OpenCodex’s preferred candidates remain unchanged. V1 receives no OpenCodex preferred-roster injection. V2 may additionally receive OpenCodex’s natural-priority guidance when the client catalog state permits; that guidance does not reorder the native tool’s advertised list.

disabledModels and each provider’s selectedModels remain visibility fields, not ordering controls. There is no separate modelOrder, providerOrder, or priority-map setting.

On Models, choose Default, A–Z by model, Group by provider, or Most used snapshot, then Apply order. This saves the currently visible routed ids and modelPickerOrderMode (alphabetical, provider, or most-used). Most used reads all retained usage once when applied; reloads restore the snapshot without fetching usage again. New or removed models do not automatically recompute it. A manually saved order, including a complete/native order, remains untouched until you explicitly apply a replacement. Default clears both picker fields, even when no routed models are available.

The controls use GET/PUT /api/subagent-models: chosen and available retain saved roster choices, including disabled or missing models; pickerAvailable contains only eligible routed catalog ids. The Models page sends pickerOrder and pickerOrderMode, never models. Roster-only saves preserve picker settings. Invalid combined updates and failed persistence leave the previous picker/roster state intact.

Routed-only presets keep the existing featured/native priority bands. They affect the Codex catalog and Claude discovery’s routed groups; Claude’s native prefix and explicit Desktop profile/alias ownership remain unchanged. OpenCodex guidance ranks and configured fallback settings are preserved, but native Codex’s advertised five and recommended default can change with display priority. Saving does not restart clients; a catalog refresh may remain pending, and clients holding an old catalog may need reopening.

Choose Custom order on Models to load a fresh routed snapshot. Drag a movable row before another row, or use its Up/Down buttons, then Save draft. Featured routed rows stay at the front in their configured rank and cannot move. Native rows are not shown; this is not a preview of the complete native picker. Surviving saved rows keep their relative order and new candidates follow the current candidate list. Every save sends the complete routed list, without changing the featured roster.

An order containing bare native ids remains protected until you explicitly apply a routed preset or Default. Selecting a different option alone does not replace it. Unknown featured state blocks editing. Before saving, the editor checks a fresh snapshot; changes preserve your draft and block saving until Reload and discard draft loads current settings. Request failures retain the draft. Accepted saves can still have a pending catalog refresh; reload before editing again.

The editor also requires an unambiguous model identity for every routed candidate. If the model catalog is incomplete, refresh the Models page before editing; reloading picker settings alone cannot restore missing catalog identities. Featured choices are matched exactly without trimming; duplicate choices use their last configured position, and canonical ids take precedence over raw ids.