---
title: "Model allowlist, lock the team to the models you actually pay for | Recipe — StudioMeyer Academy"
description: "Use availableModels to restrict which models a session can pick, and enforceAvailableModels in managed settings so project or user config can't widen it. Stops surprise Opus bills and keeps a team on an approved set."
canonical: "https://studiomeyer.academy/en/recipes/11.6-model-allowlist"
language: en
markdown_versions: ["https://studiomeyer.academy/en/recipes/11.6-model-allowlist.md"]
publisher: "StudioMeyer Academy, https://studiomeyer.academy (llms.txt: https://studiomeyer.academy/llms.txt)"
---

[← Alle Recipes](https://studiomeyer.academy/recipes)

Phase 11 · Operator Skills Library·6 steps

# Model allowlist, lock the team to the models you actually pay for

Use availableModels to restrict which models a session can pick, and enforceAvailableModels in managed settings so project or user config can't widen it. Stops surprise Opus bills and keeps a team on an approved set.

6 steps0%

Du liest ohne Account. Mit [Login](https://studiomeyer.academy/login?next=/recipes/11.6-model-allowlist) speichern wir Step-Fortschritt + Notes.

# Model allowlist

By default any session can pick any model your plan exposes. For a solo driver that is fine. For a team, or for an unattended agent that runs on a schedule, it is a cost trap. One config that quietly defaults to Opus and your daily spend doubles without anyone noticing.

The fix is the `availableModels` allowlist. You declare the exact set of model IDs a session is allowed to use, and everything outside that list disappears from the `/model` picker. As of June 2026 there is also `enforceAvailableModels`, a managed setting that closes the loophole where a project or user config could widen the list again.

### Step 1: Decide what the team is allowed to run

Write down the models you actually want in play before you touch any config. A typical cost-aware set looks like this:

- `claude-sonnet-5` for the daily driver, most work
- `claude-haiku-4-5` for cheap, high-volume tasks
- `claude-opus-5` only if you genuinely need it, and you accept the bill

If you do not need Opus for a given seat or a given scheduled agent, leave it off the list entirely. The point of an allowlist is that the expensive option is not one fat-finger away.

### Step 2: Add availableModels to settings

Edit `~/.claude/settings.json` (user scope) or `.claude/settings.json` (project scope) and add an `availableModels` array with the exact model IDs:

```json
{
  "availableModels": [
    "claude-sonnet-5",
    "claude-haiku-4-5"
  ]
}
```

After this the allowlist is active everywhere a model can be named. The `/model` picker only shows Sonnet and Haiku, an off-list `--model` or `ANTHROPIC_MODEL` is rejected, subagents and skills inherit the list, and since v2.1.176 `/fast` refuses to toggle when that would switch to an off-list Opus. The one thing plain `availableModels` leaves alone is the Default option itself, which keeps resolving to the account default until you add `enforceAvailableModels` in Step 4.

### Step 3: Use version-specific IDs when you mean it

If you pin a version-specific ID like `claude-opus-5`, the allowlist matches that exact entry. A June 2026 fix made sure version-specific IDs no longer accidentally hide the matching `/model` entries. So you can safely write the precise ID rather than a family alias when you want to pin a single version.

This matters for reproducibility. An unattended agent that ran fine yesterday should not silently jump to a newer model after an update. Pin the exact ID and you know what runs.

### Step 4: Enforce it from managed settings

User and project settings are easy to override. If you run a real team, put the allowlist in managed settings and turn on `enforceAvailableModels`:

```json
{
  "availableModels": [
    "claude-sonnet-5",
    "claude-haiku-4-5"
  ],
  "enforceAvailableModels": true
}
```

With `enforceAvailableModels` enabled, the allowlist also constrains the Default model. A Default that would resolve to a disallowed model now falls back to the first allowed model. And critically, user or project settings can no longer widen a managed `availableModels` list. The team gets the set you approved and cannot quietly add Opus back.

### Step 5: Check it took effect

Open a session in the scope you configured and run `/model`. You should see only the models on your list. Then check the aliases: with Opus off the list, `/fast` refuses an off-list switch with a message like "is not in your organization's allowed models", and an off-list `--model claude-opus-5` is rejected. The Default option keeps resolving to the account default until you turn on `enforceAvailableModels` in Step 4.

If you used managed settings, try to override `availableModels` from a project `.claude/settings.json` and confirm it does not widen the list. If the managed enforcement is working, your local addition is ignored.

### Step 6: Wire it into your scheduled agents

This is where the allowlist pays for itself. Any background or scheduled agent inherits the settings of its scope. Put a tight allowlist on the directory your unattended agents run in, drop Opus, and a runaway loop costs Haiku money instead of Opus money. Combine this with `/usage` to watch the per-model breakdown over the last 24 hours and you have a clean, boring cost floor.

## Source

`availableModels`, `enforceAvailableModels`, the Default fallback behavior, and the version-specific ID fixes are documented in the official Claude Code changelog, June 2026: https://code.claude.com/docs/en/changelog

[← CLAUDE.md management, automate](https://studiomeyer.academy/recipes/11.5-claude-md-management) [Dedicated agents, full MCP sco →](https://studiomeyer.academy/recipes/12.1-dedicated-agents)

Phase 11

Production rituals: sm-deploy, ssh-batch, email-safe-test, prisma-safety

[Alle Phasen →](https://studiomeyer.academy/recipes)

## Sitemap

Public pages of this site as Markdown: [sitemap](https://studiomeyer.academy/sitemap.md). Curated entry point: [llms.txt](https://studiomeyer.academy/llms.txt), full text: [llms-full.txt](https://studiomeyer.academy/llms-full.txt).
