The problem
Every prompt ran on the most expensive model, renames and git chores included. Switching by hand meant remembering to, and a fresh session meant losing the conversation.
What I did
- Wrote a hook that runs before Claude reads each prompt and scores its effort from 0 to 100 on keywords and structure. Under 20 is Haiku, up to 44 is Sonnet, up to 84 is Opus, and above that is Fable.
- Built three modes. Ask shows a picker with the recommendation first. Auto routes silently. Block rejects the prompt before the current model spends a token on it.
- Picking a different model hands the whole task to a subagent on that model, with a self-contained brief.
- Added inline tags (sm:skip, sm:haiku, sm:opus) and skips for approvals, slash commands, and short acknowledgments like "thanks".
- Taught it to ignore text the harness injects, like subagent reports and shell output, which kept opening the picker for messages nobody typed.
- Logged every decision to a file, so the routing can be audited and tuned.
Results
59 of those 66 prompts arrived in a session running Opus. Each Haiku or Sonnet recommendation was a chance to do the same work for less.
What I'd do differently
Score the work, not the wording. A keyword heuristic reads a short request that mentions git as a chore, even when it means building three pages. Next: let Haiku classify (the hook already supports it when an API key is set) and log which model I actually pick, so the thresholds learn from my overrides.
Artifacts
A hook, a small config file, a README, and the decision log. The picker above is a capture of what it shows.