I stopped my Claude Code subagents from running on Fable instead of Sonnet A developer discovered that Claude Code subagents pinned to run on the cheaper Sonnet model were silently falling back to the session model, Fable, due to a frontmatter pin bug, causing unexpected cost increases. The pin in the agent's frontmatter is rank 3 of 4 in model resolution precedence, and across several releases it has dropped out, leaving no error or warning. The recommended workaround is to pass the model explicitly on the dispatch, which is rank 2 and has never been the layer that breaks. I run Claude Code with a big session model, Fable or Opus 5, plus a small zoo of subagents doing the boring parts. Gateway agents, formatters, checkers. The kind of mechanical stuff you pin to a small model once, in the agent’s frontmatter, and then never think about again. At some point the token consumption stopped matching my gut feeling of what I’d actually been doing that week. Nothing was broken. Nothing errored. Everything worked. It just cost more than it should have. So I decided to take a deeper look at how Claude Code actually picks the model for a subagent. It turned out the pin I’d been trusting sits in the one layer you shouldn’t trust. Disclaimer:This is what I run on my own machine, on my own projects. Hooks can block your own dispatches, that’s the whole point of this one, so if you wire it up wrong you’ll be staring at a blocked Task call and wondering why. Also, precedence behaviour in Claude Code changes between releases. Verify against the version you’re on. Before the complaining starts, let me be clear about one thing: subagents are good. This post is not an argument against them, it’s an argument for pinning them properly. The reason to use one isn’t that it’s a smaller model. It’s that it runs in its own context window . It goes off, does something loud and messy, and hands back a short answer. The noise never lands in your main session. You get the three lines that matter instead of the four megabytes they came from. Which means the ideal subagent job looks like this: fetch a lot, filter, return a little . And that job needs a model that is obedient, not brilliant. Something like Sonnet does it all day. Running it on Fable or Opus 5 is paying frontier prices for grep with good manners. My list of agents that should never touch a frontier model: Pinning one looks like this, in .claude/agents/cloudwatch-digger.md : --- name: cloudwatch-digger description: Queries CloudWatch Logs and returns only the relevant lines model: sonnet tools: Bash, Read --- One line. model: sonnet . That’s the whole pin, and that’s exactly why it hurts when it silently stops working. The agents you bother to pin are, by definition, the ones you dispatch most often and look at least. Claude Code resolves which model a subagent runs on in this order: | rank | layer | how you set it | |---|---|---| | 1 | environment variable | shell / launch config | | 2 | per-invocation parameter | model on the dispatch itself | | 3 | agent frontmatter | model: in .claude/agents/