Ai

Saving Tokens in Claude Code — Measured

Contents

Claude Code burns through tokens faster than you’d expect. There are plenty of tips like “keep CLAUDE.md short” or “use /clear often”, but I wanted to know how much they actually matter, so I measured them.

The one thing to understand

Every time Claude Code sends a request, it resends all of this:

  1. System prompt + tool descriptions (always there)
  2. CLAUDE.md (always there)
  3. The conversation so far, files read, command output (piles up)

A single task usually takes 5–10 requests. So saving tokens comes down to shrinking what’s always there and what piles up.

Repeated parts are cached at about 1/10 the price. That’s cheaper, not free. And once the context fills up, auto-compaction kicks in and earlier details get blurred.

Setup

  • A small Python project: 20 files, one planted bug, a 3,000-line log (270 KB)
  • claude -p "..." --output-format json prints token counts and cost as JSON. That’s the measurement
  • Sonnet 5 unless noted
  • Bug-fix runs were repeated 3 times and the median is shown. Everything else ran once, so expect some noise

1. 28K tokens before you do anything

Just “hi”:

SetupInput tokens
Default27,900
No tools (--tools "")9,100
Read-only tools (--tools "Read,Grep,Glob")12,100

Tool descriptions alone are 19K tokens, sent even for a greeting.

Type /context in a session to see what’s taking up space. It’s the first command to try.

1
2
3
4
5
6
| Category                | Tokens |
|-------------------------|--------|
| System prompt           | 8.7k   |
| System tools            | 13.2k  |
| Memory files            | 18.6k  |   <- CLAUDE.md
| Skills                  | 2.1k   |

For scripted read-only jobs (summaries, reviews), pass only the tools you need with --tools.

2. Keep CLAUDE.md short

Same bug fix, two CLAUDE.md files:

  • Short: 4 lines. The test command and two rules
  • Long: 274 lines. A full “handbook” of style rules, review rules, release steps
Short CLAUDE.mdLong CLAUDE.md
Base tokens per request28,20046,700
Bug fix cost (median)$0.117$0.218
ResultFixedFixed

1.9x the cost for the same result. The long file added 18.5K tokens to every request.

Put in:

  • Commands Claude can’t guess (test, build, deploy)
  • Rules specific to this project (only where it differs from the norm)
  • Places not to touch

Leave out:

  • Anything the code already shows
  • Generic advice (“write clean code”)
  • File-by-file descriptions

Move long, occasionally needed procedures into a skill (.claude/skills/<name>/SKILL.md). As the /context output shows, skills only load a one- or two-line description until they’re needed. Twelve skills totaled 2.1K.

3. Filter logs before handing them over

“Tell me what the error is and why” on the same log, three ways:

MethodInput tokensCost
cat app.log | claude -p "..." (whole file)162,000$0.573
grep ERROR app.log | claude -p "..."30,500$0.047
Give the file path and let it search90,600$0.064

All three gave the same answer: the payment gateway didn’t respond within 2 seconds, and with zero retries the charge failed immediately.

Passing the whole file costs 12x more. Giving just the path is fairly cheap because Claude greps on its own. The worst habit is pasting logs or file contents into the chat, which is the same as the first row.

4. /clear after reading something big

Two cases.

Four small questions in one session

Context per request went from 30K to 32K. Barely moved. Cost was about the same as four fresh sessions ($0.102 vs $0.106), thanks to caching.

Read the whole log, then ask one README question in the same session

Context per request
Same session173,800
Fresh session30,200

A one-line README question drags 170K tokens of log along with it. 5.8x.

So: chaining small tasks is fine; after reading something large or switching topics, /clear. Caches expire after a while, and then those 170K tokens are sent at full price.

If you need to keep the thread, give /compact instructions:

1
/compact keep only the decisions made and the list of changed files

5. Model and effort

Same bug fix, 3 runs per setting. All succeeded.

ModelCostTimeRequests
Haiku 4.5$0.05420.5s9
Sonnet 5$0.11721.3s9
Opus 5.5 low$0.09613.8s6
Opus 5.5 medium (default)$0.1689.6s4
Opus 5.5 high$0.1699.3s4
Opus 5.5 max$0.24158.1s12
  • Haiku was enough for this bug, and cheapest
  • Opus costs more but doesn’t wander; done in 4 requests
  • Max was just slow. 6x longer, same result. Max on an easy task is waste

Opus low coming out cheaper than medium is mostly a difference in cache-write cost, not effort itself.

To switch:

1
2
/model haiku      # change model
/effort low       # low, medium, high, xhigh, max

A reasonable default: Sonnet or Opus medium day to day, Haiku for simple repetitive work, and raise effort only when you’re actually stuck.

6. Keep MCP tool search on

I attached a fake MCP server with 40 tools:

Setup“hi” input tokens
No MCP27,900
40 MCP tools, tool search on (default)28,500
40 MCP tools, tool search off52,800

Current versions don’t preload MCP tool descriptions; they look them up when needed. Only +600 tokens. With ENABLE_TOOL_SEARCH=false you pay +25K tokens on every request.

  • Keep Claude Code up to date
  • Remove any setting that turns tool search off
  • Disable unused servers with /mcp disable <server>
  • If there’s a CLI (gh, aws), prefer it over an MCP server

7. Subagents don’t save money

“Open every module file and summarize it”, done directly vs delegated to a subagent:

DirectSubagent
Main context at the end47,20031,800
Total cost$0.158$0.197

The main conversation stayed cleaner, but total cost went up. A subagent starts with its own system prompt.

Use them to protect the main context during long tasks (“find where this is used”), not to cut the bill.

8. Harness setup

Not measured, but worth doing.

One test command

For these tests I made a single ./test.sh and listed it in CLAUDE.md. Claude fixes, runs, and fixes again on its own. A clear way to verify means less wandering.

Allowlist common commands

.claude/settings.json:

1
2
3
4
5
6
{
  "permissions": {
    "allow": ["Bash(./test.sh)", "Bash(git diff:*)", "Bash(npm run lint)"],
    "deny": ["Read(./.env)", "Read(./secrets/**)"]
  }
}

No more clicking approve every time. The tests here ran with --allowedTools "Bash(./test.sh)", opening only the test command. --dangerously-skip-permissions is convenient but risky.

Formatting via hooks

Run the formatter automatically after every edit, so you don’t spend tokens asking Claude to fix formatting:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          { "type": "command", "command": "jq -r '.tool_input.file_path' | xargs npx prettier --write" }
        ]
      }
    ]
  }
}

Start big tasks in plan mode

Cycle with Shift+Tab until you reach plan mode. You get a plan before any code is touched. Finding out the direction was wrong after everything’s written is where tokens really go.

Stop early

  • Esc once: stop the current action
  • Esc twice: rewind to an earlier point

If it starts opening unrelated files, stopping right away is the cheapest fix.

Check spend

  • /usage: cost of the current session
  • /context: what’s in the context
  • In scripts, --max-budget-usd 1 sets a hard cap

Summary

Do thisMeasured
Short CLAUDE.md, long procedures as skills1.9x cost difference
Pass paths or grep output, not whole files12x difference
/clear after big reads or topic changes5.8x context difference
Haiku for easy work, save max for hard problemsHaiku was 1/3 of Opus medium
Keep MCP tool search on+25K per request when off
Subagents protect main contextTotal cost +25%
Run /context onceShows where tokens go

One thing that didn’t matter: vague vs specific prompts, in this small project. With only one failing test, a vague prompt found it just as fast ($0.111 vs $0.115). Bigger repos may differ, and naming a file path never hurts.

The biggest wins were trimming CLAUDE.md and not pasting logs. I should probably go look at this blog’s own CLAUDE.md next.