A
Claude Code logoClaude CodeBudget daily driver for web apps

Claude Code Budget Sonnet 1M

Marek Sliwka@dimextatic
87.0Overall score

Sonnet 4.6's 1M context handles big repos at a fraction of Opus cost, and the lean two-subagent setup avoids token bloat. Great default for solo devs who want strong results without burning credits.

87.0Score
942Votes
5Components
5hUpdated

Install this build

Export
terminal
npx setuproll add claude-code-budget-sonnet

Components

Model

  • Claude Sonnet 4.6

MCP servers

  • filesystem
  • github

Subagents

  • implementer
  • reviewer

Hooks

  • PostToolUse: eslint --fix
  • Stop: run tests

Rules

  • Use Sonnet for everything, escalate to Opus only on stuck
  • Keep context lean, summarize old turns
  • No speculative refactors
Setup

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.

dimextatic8 min read

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.

The whole thesis in one line
Sonnet 4.6 is good enough for ~90% of web work, and the 1M context means you almost never pay the dumb tax of re-explaining your repo. Escalate to Opus only when Sonnet is genuinely stuck, not when you are impatient.

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.

.claude/settings.json
{
  "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.

zsh - claude code
$claude
> add pagination to the /orders list endpoint
* Reading src/routes/orders.ts ...
* Edited src/routes/orders.ts (+22 -3)
* Edited src/routes/orders.test.ts (+18 -0)
[PostToolUse] eslint --fix ... clean
[Stop] running npm test --silent
Tests: 41 passed, 0 failed (3.2s)
Done. Pagination added with a default limit of 25.
session cost: $0.11
$
A hook is not the model
The reason I trust hooks more than rules: a hook runs whether or not the model remembers it. Rules live in a prompt and prompts get forgotten under context pressure. Code does not get tired.

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.

.claude/agents/reviewer.md
---
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.
reviewer subagent - transcript
You
Review the diff for the orders pagination change.
Agent
1. Does what was asked, pagination works. 2. limit is not clamped, ?limit=99999 will scan the whole table. Add a max. 3. No new deps, good. 4. You also reformatted orders.ts imports nobody asked for. Revert that, it bloats the diff.
You
Fix the clamp, revert the import churn.
Agent
Done. Diff is now +9 -1. LGTM.
The reviewer earning its keep. It caught a refactor I never asked for.

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.

.mcp.json
{
  "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 /context often. 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.

TaskModelCostNotes
Add a CRUD endpoint + testsSonnet 4.6$0.11Stop hook caught a flaky test once
Refactor a 600-line componentSonnet 4.6$0.191M context meant no re-explaining
Debug a gnarly race conditionOpus 4.8$0.73The one time I broke the glass
Write a migration + rollbackSonnet 4.6$0.14Reviewer flagged a missing index
On the Opus row
I am not anti-Opus. That 73-cent debug would have cost me two hours otherwise. The point is not 'never Opus', it is 'Opus on purpose, not by accident'.
Claude Code Best Practices - The Ultimate Guide (23K Stars)26:11
Claude Code Best Practices - The Ultimate Guide (23K Stars)· IndyDevDan

That 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.8k

And 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.

terminal
npx setuproll add claude-code-budget-sonnet

0 Reviews

Your rating
Sign in to post

Loading discussion...