I Refuse To Pay Opus Prices: My 14-Cent Claude Code Setup
How I run Claude Code on Sonnet 4.6 with a 1M context window, two cheap subagents, and a Stop hook that stops me shipping broken code, all for about a coffee a day.
I have a spreadsheet. It tracks how much I spend per feature shipped. Yes, I am that guy. The day I saw an Opus session bill me $4 to rename some props, something in me snapped, and I went looking for a cheaper way to live.
This is that cheaper way. Claude Code, Sonnet 4.6, the 1M context window, two subagents, two hooks, and a handful of rules that mostly exist to stop the model from spending my money. My last 30 days averaged about 14 cents a task. I am not going to pretend that number is scientific, but it is what my own invoices say, and I trust my invoices more than benchmarks.
Pin the cheap model and mean it
The single most expensive mistake I made early on was letting the model drift up to Opus for routine stuff. So now I pin Sonnet in settings.json and treat Opus like a fire extinguisher: behind glass, break only in emergencies.
{
"model": "claude-sonnet-4-6",
"env": {
"MAX_THINKING_TOKENS": "4000"
},
"permissions": {
"allow": [
"Read",
"Edit",
"Bash(npm run *)",
"Bash(git status)",
"Bash(git diff *)"
],
"deny": [
"Bash(rm -rf *)",
"Read(.env)",
"Read(.env.*)"
]
},
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{ "type": "command", "command": "npx eslint --fix \"$CLAUDE_FILE_PATHS\" || true" }
]
}
],
"Stop": [
{
"hooks": [
{ "type": "command", "command": "npm test --silent" }
]
}
]
}
}Two things people miss here. First, MAX_THINKING_TOKENS is a budget cap on extended thinking. Sonnet loves to think; I love to not pay for it, so I keep it modest. Second, the eslint hook ends in || true so a lint failure never aborts the edit. The Stop hook is the one I actually care about, and it is allowed to fail loudly.
The Stop hook that saved my reputation
Here is the thing about being cheap: you ship fast, and fast means sloppy if nothing catches you. My Stop hook runs the test suite the moment the model thinks it is done. If tests fail, the session does not get to quietly wrap up and tell me everything is great. I have caught maybe a dozen would-be-embarrassing pushes this way.
Two subagents, no more
Everyone wants a 7-agent orchestra. I ran the math. Every extra subagent is another context window getting filled and billed. I keep exactly two: an implementer that writes the code, and a reviewer that reads the diff and complains. The reviewer runs on Sonnet too, because a second cheap opinion beats one expensive one.
---
name: reviewer
description: Reviews a diff for bugs and obvious cost waste. Use after any non-trivial edit.
tools: Read, Bash(git diff *)
model: claude-sonnet-4-6
---
You review code changes. Be blunt and short.
Check, in this order:
1. Does it actually do what was asked? Quote the line if not.
2. Any null/undefined or off-by-one that tests would miss.
3. Did it add a dependency when an existing util would do? Flag it.
4. Did it refactor things nobody asked it to touch? Tell it to revert.
Do NOT rewrite the code yourself. List findings as a numbered
list. If the diff is fine, say "LGTM" and stop. Do not pad.That clamp catch is a real one I had this month. A reviewer that costs me maybe two cents a run found a query that would have hammered the database in production. Cheapest insurance I own.
MCP: just filesystem and github
I see people wire up eight MCP servers and then wonder why their context is full before they type a word. Every server loads its tool definitions into the window, and the window is the thing you pay for. I run two. Filesystem so the model can see beyond the working tree, github so it can read issues and open PRs without me copy-pasting.
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "."]
},
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_TOKEN}"
}
}
}
}- Use
/contextoften. If MCP tools are eating more than ~10% of the window before you start, kill a server. - Summarize old turns instead of letting them ride. A long session is a slow bleed.
- Never paste a giant log into chat. Save it to a file and let filesystem read the part it needs.
- Escalate to Opus only when Sonnet has failed the same task twice. Impatience is not an emergency.
What it actually costs
Here is a slice of my own log. These are not lab numbers, they are tasks I ran on real client repos. Take them as a vibe, not a benchmark.
| Task | Model | Cost | Notes |
|---|---|---|---|
| Add a CRUD endpoint + tests | Sonnet 4.6 | $0.11 | Stop hook caught a flaky test once |
| Refactor a 600-line component | Sonnet 4.6 | $0.19 | 1M context meant no re-explaining |
| Debug a gnarly race condition | Opus 4.8 | $0.73 | The one time I broke the glass |
| Write a migration + rollback | Sonnet 4.6 | $0.14 | Reviewer flagged a missing index |
26:11That video is where a lot of my context-discipline habits came from. Worth the half hour even if you ignore the fancy stuff and just take the CLAUDE.md and context tips.
Stuff I keep open in a tab
disler/claude-code-hooks-masteryWhere I stole half my hook ideas. Covers every lifecycle event with real, copyable examples.disler/claude-code-hooks-mastery4.1khesreallyhim/awesome-claude-codeThe curated list. When I want a subagent or slash command I do not feel like writing, I check here first.hesreallyhim/awesome-claude-code9.8kAnd the official docs on subagents are genuinely good, not the usual marketing fluff: code.claude.com/docs/en/sub-agents. Read it before you build agent number three you do not need.
The whole thing, basically
Pin Sonnet. Give it a 1M window so it stops asking dumb questions about your own repo. Two subagents, two hooks, a deny list so it cannot read your secrets or nuke your disk. Let the Stop hook be the adult in the room. That is the entire build. It is boring on purpose, and boring is what lets me leave it running while I make lunch.
If you want to copy mine, the install is one line. Drop the settings, the .mcp.json, and the two agent files into your repo and you are running.
npx setuproll add claude-code-budget-sonnet