How do you restrict which AI models developers can use in coding agents?

An allowed-models policy reads the model a coding agent reports in its hooks and denies the action when the model isn't on an exact-match list. With Arcjet, one policy blocks the switch on Claude Code and prompts and tool calls on Codex and Cursor, and dry run shows which models developers use first. Copilot hooks carry no model, so pair the policy with vendor settings.

10 min read
In short: An allowed-models policy reads the model a coding agent reports in its hooks and denies the action when the model isn't on an exact-match list. With Arcjet, one policy blocks the switch on Claude Code and prompts and tool calls on Codex and Cursor, and dry run shows which models developers use first. Copilot hooks carry no model, so pair the policy with vendor settings.

How do you restrict which AI models developers can use in coding agents?

To restrict which models developers use in coding agents, set the model controls in each vendor's admin settings, then enforce an allowlist of exact model IDs from the agent's hooks. A hook policy reads the model that the agent reports and denies the action when that model isn't on the allowlist. Claude Code blocks the switch to a disallowed model, OpenAI Codex and Cursor block the prompt and every tool call while a disallowed model is selected, and GitHub Copilot hooks don't report a model at all.

Organizations restrict models for several reasons: data-handling terms that differ by model, a list of models that security has reviewed, or cost.

In practice, you enforce the allowlist with an Arcjet allowed-models policy. Arcjet reads the model from the hooks that Claude Code, Codex, and Cursor already fire, and denies the action before it runs, with no SDK and no code change. You write one policy for all three agents, publish it in dry run to see which models developers use, and set it live when the list is right. Each coding agent reports the model at a different point in a session, so this guide explains what the policy blocks on each one and which vendor settings to pair it with. For the broader set of controls, see coding agent security.

Where can a model restriction be enforced?

You can restrict a model in two places. The first is the vendor's own organization settings, such as a default model or a banned-model list. The second is a hook: a program or HTTP endpoint that the agent calls before it acts, which can refuse the action.

A hook can only act on the model if the agent includes it in the hook payload, and each agent includes it on different events:

  • Claude Code fires PreModelSwitch before the session changes model. The payload carries the target model as to_model. Claude Code doesn't send a model on prompt or tool-call events.
  • Codex sends model on UserPromptSubmit, PreToolUse, and PermissionRequest. It has no model-switch hook.
  • Cursor sends model_id, or else model, on beforeSubmitPrompt and preToolUse. It has no model-switch hook.
  • Copilot hook payloads have no model field.

What does a model allowlist block on each agent?

The following table shows what one allowed-models policy blocks on each agent, and how the hook is installed.

AgentBlocks the switchBlocks the next promptBlocks tool callsHook type
Claude Code

Yes, on PreModelSwitch. A denial keeps the current model.

No. The payload has no model.No. The payload has no model.HTTP entry
CodexNo. There is no switch hook.

Yes, on UserPromptSubmit

Yes, on PreToolUse and PermissionRequest

Command wrapper
CursorNo. There is no switch hook.

Yes, in the IDE, on beforeSubmitPrompt

Yes, on preToolUse

Command wrapper
GitHub CopilotNoNoNoNot covered. The payloads have no model field.

The difference matters for a session that opens on a disallowed model and never switches. On Codex and Cursor, Arcjet denies the next prompt and every tool call. Claude Code reports the model only at the switch, so pair the policy with Claude Code's organization default or banned-model setting for that case, as described in Which vendor settings do you pair with Arcjet?

What does an allowed-models policy look like?

In Arcjet, an allowed-models policy is written in Rego, the policy language of Open Policy Agent, and the Arcjet Console offers it as the coding-agent.model-allowlist starter policy. You write the list of model IDs into the policy and choose when it runs. The hook file doesn't name the policy, so publishing the policy is what turns it on, and a change to the list takes effect in real time.

The following rule denies any reported model that isn't in the set. The three IDs are placeholders, one per enforced vendor. Replace them with the IDs you allow before the rule goes live.

package arcjet.guard
import rego.v1
deny contains "disallowed-model" if {
input.values.model
not input.values.model in {"claude-sonnet-4-6", "claude-opus-4-6", "gpt-5.4"}
}

input.values.model is false when the input is absent or empty. That is why the rule doesn't fire on Claude Code and Copilot prompt and tool-call events, where the agent sends no model. On a Claude Code PreModelSwitch, the input is always present, so an ID outside the list matches. On Codex and Cursor, the rule matches whenever the reported ID is outside the list.

To get the coverage in the preceding table, attach the policy to all three Execute on options: Tool call, Prompt, and Model switch. Clearing Model switch leaves Claude Code unenforced. Clearing Tool call and Prompt leaves Codex and Cursor unenforced.

The denial reason sent to the agent is the rule ID disallowed-model and nothing else.

How should you write model IDs in an allowlist?

List canonical model IDs. Matching is exact after lowercasing, not a prefix and not a substring match. A rule that uses contains with a fragment misses IDs you meant to allow and hits unrelated IDs that happen to include the same letters.

Selector tokens need a deliberate decision:

  • On Cursor, auto, default, and inherit are real selector states and reach the policy as those tokens. A Cursor session on Auto is denied unless you list auto.
  • On Cursor, a blank model is the token unknown, which isn't on any list unless you add it.
  • On Codex, a missing or blank model is treated as absent, not as unknown, so the rule doesn't fire.

Adding auto to the list is a policy choice. The policy sees the token auto, not the model Cursor picks, so your list doesn't constrain what Auto selects.

Does a model allowlist apply to cloud agents?

Coverage of cloud and hosted sessions follows how each agent loads hooks:

  • Claude Code cloud sessions run the same managed HTTP hooks, so the switch block applies there.
  • Codex managed hooks from requirements.toml, MDM, or cloud-managed requirements are trusted and can't be disabled. The wrapper applies wherever those hooks run.
  • Cursor cloud agents run preToolUse and don't run beforeSubmitPrompt, so Arcjet refuses tool calls there. Cursor doesn't send the first prompt through a hook, because it was submitted before the VM existed. Enterprise Team hooks reach cloud agents; a user-level ~/.cursor/hooks.json doesn't.

Which vendor settings do you pair with Arcjet?

The Arcjet policy works alongside each vendor's admin controls and enforces your list wherever the agent reports the model at a point where a hook can act. Pair it with the following vendor settings:

  • Claude Code: Claude Code reports the model only on PreModelSwitch. Set the organization default model and banned-model setting to cover a session that starts on a disallowed model and never switches.
  • GitHub Copilot: Copilot hook payloads carry no model, so set the model restriction in GitHub's own Copilot administration settings.
  • Codex and Cursor: keep whatever model controls the vendor offers as the first layer. The Arcjet policy is the second layer, which refuses a prompt or tool call on a model that isn't on your list.

Personal accounts sidestep both layers, because a personal sign-in doesn't load your managed settings or your hooks. Refuse them with network and device controls, so that every remaining session runs under your policy. For the steps, see block personal AI accounts on work laptops.

Can a policy route developers to a cheaper model?

No. A hook policy allows or denies, and it doesn't rewrite the model or the request. Arcjet deliberately answers an allow with an empty response. In Claude Code, Codex, and Cursor, an explicit allow is a grant that skips the agent's own permission flow, and a Codex allow that carries updatedInput can rewrite the call.

To steer developers toward a lower-cost model, set it as the organization default in the vendor's settings and use the allowlist to refuse the models you don't want used. The denial names the rule, so a clear rule ID such as disallowed-model tells developers why the action stopped.

How do you roll out a model allowlist safely?

Every new rule starts in dry run, a mode in which Arcjet records what the rule would decide without denying anything. Publish the policy in dry run, let developers work, then read the would-be denials in the Activity view of the Arcjet Console. That shows which models people use, including selector tokens such as auto, before you set the rule live. Decisions also export to Datadog, Splunk, SentinelOne, Panther, and Amazon S3 (Enterprise plan), so you can alert on a disallowed model from your existing detection tooling.

Where does Arcjet fit in model governance?

With Arcjet, developers on Claude Code, Codex, and Cursor stay on the models you approved, and you see which models they use before anything is denied. The following capabilities apply:

  • One allowed-models policy for Claude Code, Codex, and Cursor, decided from the hooks the agents already fire.
  • Enforcement at each agent's own point: the switch on Claude Code, and the prompt and every tool call on Codex and Cursor.
  • Dry run that shows the models in use, including Cursor's auto, and list changes that take effect in real time.
  • Every decision in the Arcjet Console, with export to your detection tooling.

To get started, publish the coding-agent.model-allowlist starter policy in dry run with your model IDs, and attach it to Tool call, Prompt, and Model switch. For the full starter policy and the input contract, see coding agent policies. To install the hooks, see the guides for Claude Code, Codex, and Cursor.

Frequently asked questions

Can I block developers from using certain models in Claude Code?

Yes, at the switch. An Arcjet allowed-models policy on PreModelSwitch refuses a switch to a model outside your list and keeps the current model. Claude Code sends no model on prompt or tool-call events, so pair the policy with Claude Code's organization default or banned-model setting to cover a session that starts on a disallowed model and never switches.

Does a model allowlist work on GitHub Copilot?

Not through hooks. Copilot hook payloads have no model field, so the policy can't see the model. Use GitHub's own Copilot administration settings instead.

Why is Cursor Auto blocked by my model allowlist?

On Cursor, auto, default, and inherit are real selector states and reach the policy as those tokens. Matching is exact, so Auto is denied unless you list auto.

Can one policy route developers to a cheaper model?

No. A hook policy allows or denies; it doesn't rewrite the model. Set the lower-cost model as the default in the vendor's settings and use the allowlist to refuse the models you don't want used.

Should I match model IDs by prefix?

No. List canonical model IDs. Matching is exact after lowercasing, and a substring match both misses intended IDs and hits unrelated ones.

AI runtime security in your code

Protect your AI agent workflows with Arcjet

Start from the Arcjet allowed-models starter policy and publish it in dry run to see which models developers use.