code-review skill: forked children inherit the parent model with no routing, no cost gate on model-initiated invocation, user policy cannot reach them
Summary
The bundled code-review skill runs as a forked agent on the parent session's model and then dispatches its finder and verifier agents through the Agent tool with no model set. Every child inherits the parent model. In a session whose model is claude-fable-5-1, one model-initiated /code-review 223 high produced 10 fable agents (the fork plus 9 children) and consumed about 1.5M cache-creation tokens and 13.7M cache-read tokens in 13 minutes before I killed it, with no report produced.
Three separate problems combine here:
- Child agents are not model-routed. The skill prompt says "Run 8 independent finder angles via the Agent tool" and "run one verifier via the Agent tool" and never names a model. The fork's transcript shows 9
Agenttool calls, allsubagent_type: "general-purpose", all withmodelabsent. Mechanical finder and grep-style verification work ran on the most expensive tier. Related: #73323 asks for a model selector for this skill; this report shows that the default is the worst case, not a neutral one. - The model can self-invoke the skill, and there is no consent or cost gate. The skill is exposed in the model's skill listing like any other. In my session the assistant invoked it on its own in response to "do a review (no changes)"; I did not type
/code-review. The docs put the average cost at $15-25 per review (https://code.claude.com/docs/en/code-review.md#pricing) but nothing at invocation time surfaces that, and theSkilltool has nomodelparameter, so even a careful invocation cannot route it down. Related: #88003 (usage limits exhausted in 10 minutes), #90902 (fork chain token consumption). - User-level rules and hooks cannot reach the children. My
SessionStarthooks load an orchestration policy that says "never leavemodel=default; never run subagents on fable". Per the sub-agents docs a fork inherits the entire parent conversation, and the parent transcript confirms the policy was present. The fork still followed the skill prompt over the inherited policy.SubagentStartfired for the fork (I can see itsadditionalContextattachments) but no hook point lets a user reject anAgentcall whosemodelis unset or equals a given tier.
Steps to reproduce
- Set
"model": "claude-fable-5-1[1m]"(or any top-tier model) in~/.claude/settings.json. - Open a session on a repository with a large open PR (mine was 269 files).
- Ask, in plain words, for a review of the PR. Do not type
/code-review. - Observe the assistant invoke the
code-reviewskill as a fork ("forked execution, running in the background"). - Inspect the fork's transcript under the session's
tasks/directory: everyAgenttool_use input lacksmodel; every child transcript's assistant turns report the parent model.
Measured usage (from the JSONL transcripts, one row per assistant message id)
| Scope | Model | Cache-creation tokens | Cache-read tokens | Output tokens |
|---|---|---|---|---|
| code-review fork + 9 children | claude-fable-5-1 (all 10) | 1,533,907 | 13,651,479 | 11,939 |
| Same review done by 3 hand-routed agents | opus, opus, sonnet | 562,745 | 14,062,548 | 4,596 |
The fork tree ran 08:14 to 08:31 UTC and was stopped by hand before it reported. The three hand-routed agents finished and reported.
Expected behavior
- Finder and verifier agents spawned by bundled skills should carry an explicit
model, defaulting to a lower tier than the parent for mechanical angles, or honor a user-level setting for skill sub-agent model. - A model-initiated invocation of a skill that forks and fans out should require user confirmation, or at least print the documented cost band before running. A user-typed
/code-reviewcan stay as it is. - A hook point (for example
PreToolUseonAgentwith access toinput.model, or a settings key) should let a user block sub-agent dispatch on a named model tier, and it should apply inside forks. - The per-skill disable switch should be documented.
disableBundledSkills: trueis documented but disables every bundled skill. A per-skillskillOverrideskey appears to work (the binary recognizes it) but is not in the settings reference.
Environment
- Claude Code 2.1.267, macOS (darwin 24.6.0)
~/.claude/settings.json:"model": "claude-fable-5-1[1m]","effortLevel": "high","permissions.defaultMode": "auto"- Skill invoked with args
223 high
I have the fork and child transcripts and can share redacted excerpts on request.
🤖 Written by Claude Code on behalf of elaye