I built a local hook that solves a problem I kept seeing: using Opus for everything (git commits, file renames, etc.) when Haiku/Sonnet work identically at 75-90% less cost.
The Problem
After analyzing weeks of my own prompts:
-
~60-70% were standard feature work Sonnet handles fine
-
Big chunks were pure git/formatting tasks Haiku handles identically
-
Only ~10-15% genuinely needed Opus
We all know we should switch models. But when you’re in flow, you don’t want to think about the dropdown.
What It Does
Model Matchmaker is a local hook that runs before each prompt:
-
Classifies the task via keyword matching (git ops, feature work, architecture)
-
Blocks if you’re overpaying (Opus for git commit → recommends Haiku)
-
Blocks if you’re underpowered (Sonnet for architecture → recommends Opus)
-
Lets everything else through
-
! prefix bypasses it completely
Why Local + Why Not a Proxy
Local means:
-
No network calls, no proxy, no attack surface
-
No API costs for blocked requests
-
Fail-open: if it hangs (2-second timeout), Cursor proceeds normally
Compared to Cursor’s Auto mode:
-
Auto is server-side, doesn’t include Haiku or Opus, doesn’t show which model it picked
-
This is client-side, nudges in both directions (down when overpaying, up when underpowered)
Compared to OpenRouter/auto:
-
OpenRouter optimizes server-side routing (you still pay per token)
-
This blocks requests client-side (no API call = $0)
-
They’re complementary—you could use both
Results
Cost savings: 50-70% reduction (cloud API users)
Speed improvement: 60% of requests route to faster models (Haiku responds 3-5x faster than Opus)
Accuracy: 12/12 real test prompts classified correctly after tuning
The unexpected benefit: when simple tasks return in 3-5 seconds instead of 15-20, your entire workflow feels snappier.
Tech Stack
-
Pure bash + python3 (JSON parsing)
-
No dependencies (python3 pre-installed on macOS/Linux)
-
3 files, 2-minute setup
-
Logs every decision to ~/.cursor/hooks/model-advisor.log (20-char prompt snippet only, for privacy)
Try It
Would love feedback from other Cursor users—does your prompt breakdown look similar? Any patterns I’m missing?