Feature request: managed, enforceable allowlist of selectable models

Open 💬 1 comment Opened Jun 16, 2026 by ajjuaire

What variant of Codex are you using?

CLI

What feature would you like to see?

What feature would you like to see?

A first-class, managed/enforceable allowlist of selectable models — a config
key that constrains which models a user may use, composes with Codex's existing
config-layering precedence, and cannot be widened by lower-priority layers.

Problem

There is currently no supported way to restrict which models a user can select.
Organizations that standardize on a specific model (or a small approved set) need
to guarantee every session uses an approved model regardless of what a user types,
picks in the picker, or sets in their own config.toml. The defining requirement
is enforcement: a forced default is not enough, because a user can still
switch models mid-session via the picker or /model.

Every existing model-related key falls short for this:

| Mechanism | Why it doesn't solve restriction |
|---|---|
| model (default) | Only sets the starting model; the user can still switch to any other model. Not enforcement. |
| Global policy model (cloud settings/policies) | Same limitation (a default, not a ceiling) — and per #24032 it is currently ignored by the CLI/app anyway. |
| model_provider / model_providers | Restricts the provider, not the model; a provider can expose many models. |
| model_catalog_json | Comes closest — a custom catalog replaces the built-in list, so a single-entry catalog does restrict the picker — but it requires authoring a complete model descriptor (every required field, including the full base_instructions system prompt) for each allowed model, kept byte-accurate against the bundled catalog and re-synced on every upgrade. It's a model-definition mechanism being misused for model-restriction. |
| Managed config (requirements.toml) | Can enforce approval policies, sandbox modes, permission profiles, web-search, network, feature flags, MCP allowlists, auto-review, command rules, hooks — but has no key for models. |

So there's an enforcement layer (requirements.toml) and a list-shaping
mechanism (model_catalog_json), but nothing that simply says *"restrict the
selectable models to this allowlist"* without redefining the models themselves.

Proposed solution

A key that takes a list of model slugs (the same identifiers the model key
already accepts), enforceable through the managed/requirements layer:

# Only these slugs are selectable — in the picker, via /model, and via the
# `model` key / `-c model=`. Selecting/defaulting outside the list is rejected
# with a clear error rather than silently falling back.
allowed_models = ["gpt-5.4"]

No full model descriptors — just slugs — so admins never reproduce
base_instructions and it never drifts against the bundled catalog across
upgrades.

Layered behavior (the key part)

Slot into the documented precedence (user → profile → project → CLI → managed)
so it works across layers:

  • Defaults layer (managed_config.toml): sets a starting allowlist; lower

layers may narrow it.

  • Enforcement layer (requirements.toml): a hard ceiling. Lower layers may

narrow (intersect) but never widen. A user/project config naming a
model outside the enforced set has it filtered out, not honored.

  • Effective set = intersection of every layer that specifies one. E.g. an

org enforces ["gpt-5.4", "gpt-5.5"]; a sensitive repo's project config
narrows to ["gpt-5.4"]; neither can escape an enforced constraint above it.

  • Treat an enforced allowed_models as a protected key (like

model_provider) that project-local .codex/config.toml cannot widen.

  • Apply uniformly to the **picker, /model, the model key, and -c

overrides** — and to exec/non-interactive paths, not just the picker.

Edge cases

  • Empty intersection → fail with a clear error rather than silently allowing all.
  • Unknown slug in the allowlist → warn and skip (degrade gracefully across

versions) but never expand availability.

  • Disallowed models shouldn't appear in the picker at all.
  • Surface the active constraint (e.g. in codex doctor) so users understand why

a model is unavailable.

Alternatives considered

  • Forcing a single default model — insufficient; users can switch.
  • Restrictive model_catalog_json — works mechanically but requires maintaining

full model descriptors (incl. system prompts) and re-syncing every upgrade.

  • Per-provider filtering — too coarse; a provider may expose many models.

Additional information

Searched existing open issues before filing; nearest neighbors but no duplicate:

  • #21594 — model_aliases mapping for gateway model names (naming/aliasing, not restriction).
  • #16248 — allow [otel] via cloud-managed defaults (establishes the managed-defaults pattern, but for telemetry, not models).
  • #24032 — global-policy model is ignored by the app (a default-model bug;

reinforces that a default isn't enforcement and that the model field needs
managed-layer support that actually works).

  • #19694 / #26308 — model_catalog_json picker/project-scope bugs (related to the workaround's fragility, not the feature itself).

Happy to refine the exact key name (allowed_models vs. e.g.model_allowlist / permitted_models) to match existing conventions.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗