TL;DR
Agent(model:opus)endenysolo bloquea cuando Claude pide Opus para un subagente. Si quieres que ninguno corra en Opus, fija su modelo conCLAUDE_CODE_SUBAGENT_MODELyCLAUDE_CODE_SUBAGENT_MODEL_FORCE=1, y deja la regla para lo que sí frena.
Desde la v2.1.178, las reglas deny y ask pueden mirar un parámetro de la herramienta con la sintaxis Tool(param:valor). El ejemplo de la documentación es Agent(model:opus), y la lectura obvia es "mis subagentes ya no gastan Opus". Lo probé en un repo con la regla puesta y no es así: frena una de las tres vías por las que un subagente acaba en Opus.
{
"permissions": {
"deny": ["Agent(model:opus)"]
}
}
Las tres vías, probadas
Con esa regla en .claude/settings.json, lancé una sesión con claude -p por cada caso y miré en qué modelo corrió el subagente:
| Cómo llega el subagente a Opus | ¿Lo frena la regla? | Lo que pasó |
|---|---|---|
Claude pasa model: "opus" al lanzarlo |
Sí | No llegó a arrancar |
Su definición en .claude/agents/ dice model: opus |
No | Corrió en claude-opus-5-5 |
| No lleva modelo y tu sesión principal está en Opus | No | Heredó claude-opus-5-5 |
En el primer caso, Claude recibe esto, y en mi prueba no reintentó:
Permission to use Agent with model:opus has been denied.
Los otros dos pasan porque la regla compara el parámetro que Claude envía en la llamada, y en ninguno de los dos Claude envía model. La documentación lo dice así: un parámetro que no se envía nunca casa con la regla, ni siquiera con Agent(model:*). Y el tercer caso es el habitual: si trabajas con Opus, cada subagente sin modelo propio corre en Opus.
Si no quieres ningún subagente en Opus
Fija el modelo en el bloque env de tu settings.json:
{
"env": {
"CLAUDE_CODE_SUBAGENT_MODEL": "sonnet",
"CLAUDE_CODE_SUBAGENT_MODEL_FORCE": "1"
}
}
Con las dos variables, Claude Code ignora el model de las definiciones y Claude no puede pasar uno al lanzar el subagente. Lo comprobé con haiku: el mismo subagente con model: opus en su definición corrió en claude-haiku-5-5. Sin FORCE, la variable solo es un valor por defecto y pierde ante los otros dos; el orden completo está en effort por modelo. Quedan fuera los forks y las skills con model: inherit, que siguen en el modelo de tu sesión.
Para qué sí sirve la regla
Para dejar que tus definiciones elijan modelo y que Claude no suba a Opus por su cuenta. Con ask en lugar de deny, en vez de bloquearlo te pregunta cada vez:
{
"permissions": {
"ask": ["Agent(model:opus)"]
}
}
Tres detalles de la sintaxis:
- Compara el texto literal.
Agent(model:opus)casa con el aliasopus, no con un ID completo comoclaude-opus-5-5.Agent(model:*opus*)cubre los dos. - Un parámetro por regla. Para
modeleisolation, dos reglas. - Solo para
denyyask. Una reglaallowno acepta parámetros, porque permitir un valor no hace segura la llamada entera.
La misma sintaxis sirve para otros parámetros de primer nivel, como Agent(isolation:worktree) o Bash(run_in_background:true). No vale para el campo principal de cada herramienta, como el command de Bash: para eso siguen las reglas de siempre, como Bash(rm *). Si una regla de las tuyas no frena lo que esperabas, arranca con --verbose y verás los parámetros exactos de cada llamada.
Documentación oficial: Match by input parameter · Choose a model
Requisitos
- Claude Code v2.1.178 o posterior para la regla, y v2.1.257 o posterior para
CLAUDE_CODE_SUBAGENT_MODEL_FORCE. Probado en la v2.1.293 el 13 de octubre de 2026.