Cut Claude Code costs 50-90% — automatic model routing, input filtering, and output reduction via Claude Code hooks.
Claude Code defaults to Opus for everything. Most prompts don't need it — "list files," "explain this function," even simple bug fixes run fine on Haiku or Sonnet at a fraction of the cost.
Costwise is a Claude Code plugin that optimizes costs across three layers:
| Layer | What | How |
|---|---|---|
| Routing | Sends each prompt to the cheapest model that can handle it | UserPromptSubmit hook classifies prompt → switches model |
| RTK | Filters CLI output before it enters context (60-90% input token savings) | PreToolUse hook on Bash commands |
| Ponytail | Reduces output verbosity without losing correctness | SessionStart hook injects concise-output rules |
No proxy server, no infrastructure. Just hooks.
You type a prompt
│
├─ Costwise routes to haiku/sonnet/opus based on complexity
├─ RTK filters tool output before it hits context
└─ Ponytail keeps responses short
│
▼
Same workflow, lower bill
cd the_next_big_thing
pip install -e .The plugin lives at plugins/costwise/. Claude Code discovers it automatically when the repo is your working directory. To verify:
costwise doctor
# +-- Costwise Doctor ---------------------------------+
# | + Config (defaults) |
# | + Tracking DB (N records at ~/.local/share/...) |
# | + Plugin (costwise plugin v2.0.0 hook-based) |
# | + RTK (N commands tracked) |
# | + Ponytail (mode: full) |
# | 5/5 checks passed |
# +----------------------------------------------------+Routing is automatic. Every prompt gets classified and routed:
"list files in src"→ Haiku (SIMPLE)"fix the auth bug in login"→ Sonnet (MEDIUM)"redesign the authentication architecture across all microservices"→ Opus (COMPLEX)
Prefix a prompt with ~ to bypass routing and keep the current model.
costwise gain
# ╭─ Costwise Gain ──────────────────────────────────────╮
# │ Requests: 166 │
# │ Cost: $4.52 │
# │ Saved: $3.90 (46.3%) │
# │ Ponytail: 7 reqs @ full (est. ~40% output savings) │
# │ Period: 2026-07-01 – 2026-08-05 │
# ╰──────────────────────────────────────────────────────╯Or inside Claude Code: /costwise-gain
The UserPromptSubmit hook fires on every prompt:
prompt in (stdin JSON)
│
├─ bypass? (starts with ~) → exit 0, no routing
│
├─ fingerprint (SHA-256 + normalize)
│
├─ retry detection
│ └─ query SQLite: same session, similar content in last 5 min?
│ └─ if previous request was downgraded → flag as retry
│
├─ classify_prompt(text, ponytail_mode, is_retry)
│ ├─ intent detection (refactor/debug/fix/generate/explain/chat/...)
│ ├─ error severity (critical 1.0 / runtime 0.6 / warning 0.3)
│ ├─ complexity keywords (architecture, redesign, migration plan...)
│ ├─ code blocks, multi-file scope, prompt length
│ └─ ponytail bias (full: -0.03, ultra: -0.06)
│
├─ score → tier
│ < 0.10 → SIMPLE (haiku)
│ < 0.30 → MEDIUM (sonnet)
│ ≥ 0.30 → COMPLEX (opus)
│
├─ retry bump: if was false-downgrade, restore original tier
│
├─ budget check (SQLite: hourly + session spend)
│ ├─ under limit → allow
│ ├─ near limit → warn (stderr)
│ ├─ over + auto_downgrade → force lower tier
│ └─ over → block
│
├─ same model already? → exit 0
│
├─ write ~/.claude/settings.json (model + effortLevel)
├─ record decision to SQLite
└─ exit 2 (prompt re-sent with new model)
Sub-agent routing works via the PreToolUse hook — when Claude spawns an Agent or Task, the hook classifies the sub-agent's prompt and injects the appropriate model.
| Signal | Weight | What it detects |
|---|---|---|
intent |
0.30 | Task type: chat=0, explain=0.15, fix=0.6, debug=0.7, refactor=0.8 |
retry |
0.15 | Retry keywords or flagged by detector |
error_severity |
0.14 | Graduated: warning=0.3, runtime=0.6, critical=1.0 |
code |
0.11 | Code blocks in prompt |
complexity_kw |
0.10 | Architecture, redesign, migration plan, tradeoff... |
multi_file |
0.09 | References multiple file paths |
length |
0.06 | Prompt length (short=simple, long=complex) |
error_kw |
0.05 | Error-related keywords |
Ponytail bias reduces the score when output reduction is active (cheaper models are more viable when output costs are already cut).
Costwise learns from its mistakes:
- Retry detection — if you retry a prompt that was downgraded, that's a false downgrade
- Tier bump — retried prompts get routed to at least the original tier
- Threshold tuning — the classifier auto-adjusts thresholds to keep false-downgrade rate under 3%
- Bounded — max 5 nudges/hour, min 20 requests before any tuning, weights bounded to prevent collapse
Set spend limits in costwise.toml:
[costwise.budget]
max_hourly_usd = 5.0
max_session_usd = 20.0
auto_downgrade = true # downgrade tier when over budget (vs. block)
warning_threshold_pct = 80 # warn at 80% of limitBudget is tracked per-request in SQLite using estimated costs ($0.007/simple, $0.06/medium, $0.175/complex).
Costwise looks for config in order:
./costwise.toml~/.config/costwise/costwise.toml- Built-in defaults (works out of the box)
[costwise.routing]
mode = "auto" # "auto" (switch model) or "advisory" (log only)
[costwise.routing.models]
simple = "claude-haiku-4-5"
medium = "claude-sonnet-4-6"
complex = "claude-opus-4-6"
[costwise.budget]
max_hourly_usd = 5.0
max_session_usd = 20.0
[costwise.tracking]
db_path = "~/.local/share/costwise/costwise.db"
retention_days = 90
[costwise.feedback]
auto_tune = true
similarity_threshold = 0.7 # Jaccard threshold for retry detection| Command | Description |
|---|---|
costwise gain |
Savings summary (routing + RTK + Ponytail) |
costwise gain --json-output |
Machine-readable savings data |
costwise doctor |
Health checks (config, DB, plugin, RTK, Ponytail) |
the_next_big_thing/
├── src/costwise/ # Python package
│ ├── core/ # Classifier, signals, models, pricing, budget
│ ├── feedback/ # Retry detector, fingerprinting, auto-tuner
│ ├── tracking/ # SQLite store (routing decisions, retries, budget)
│ ├── integrations/ # RTK + Ponytail readers
│ ├── config/ # TOML loader + Pydantic schema
│ └── cli/ # gain, doctor commands
│
├── plugins/costwise/ # Claude Code plugin
│ ├── .claude-plugin/plugin.json # Plugin manifest
│ ├── hooks/
│ │ ├── hooks.json # Hook registration
│ │ ├── session_start.py # Emit routing rules + init
│ │ ├── user_prompt.py # Classify → route → track
│ │ ├── pre_tool_use.py # Route sub-agent spawns
│ │ └── hookio.py # Hook I/O utilities
│ └── skills/costwise/gain.md # /costwise-gain skill
│
└── tests/ # Test suite
| Model | Tier | Input $/MTok | Output $/MTok |
|---|---|---|---|
| claude-opus-4-7 | COMPLEX | $5.00 | $25.00 |
| claude-opus-4-6 | COMPLEX | $5.00 | $25.00 |
| claude-sonnet-4-6 | MEDIUM | $3.00 | $15.00 |
| claude-haiku-4-5 | SIMPLE | $1.00 | $5.00 |
Haiku output tokens are 5x cheaper than Opus. Routing simple prompts to Haiku saves $20/MTok on output alone.
Model routing approach inspired by claude-model-router-hook by @tzachbon.