CLAUDE LABJP
RELEASE — Claude Code v2.1.246 shipped on August 26, adding a startup warning for Bash allow rules that put a wildcard ahead of the subcommandPERMISSIONS — /permissions now has an Auto mode tab, so you can see in one place what runs automatically and where Claude still stops to askMEMORY — Unbounded memory growth in long interactive sessions is fixed: subagent tool results are released once they scroll out of the recent display windowMCP — In headless and remote sessions, a tool call interrupted by an incoming message is now reported as an explicit interrupted error instead of completing with no outputRUNNER — claude self-hosted-runner gains --proxy-authorization-command and --proxy-authorization-file for egress proxies that issue a fresh auth header on every connectionLIMITS — The 50% weekly limit increase runs through August 31 for Pro, Max, Team, and seat-billed Enterprise accounts, which leaves four daysRELEASE — Claude Code v2.1.246 shipped on August 26, adding a startup warning for Bash allow rules that put a wildcard ahead of the subcommandPERMISSIONS — /permissions now has an Auto mode tab, so you can see in one place what runs automatically and where Claude still stops to askMEMORY — Unbounded memory growth in long interactive sessions is fixed: subagent tool results are released once they scroll out of the recent display windowMCP — In headless and remote sessions, a tool call interrupted by an incoming message is now reported as an explicit interrupted error instead of completing with no outputRUNNER — claude self-hosted-runner gains --proxy-authorization-command and --proxy-authorization-file for egress proxies that issue a fresh auth header on every connectionLIMITS — The 50% weekly limit increase runs through August 31 for Pro, Max, Team, and seat-billed Enterprise accounts, which leaves four days
Articles/API & SDK
API & SDK/2026-07-13Advanced

When Extended Thinking Flattened My Accuracy but Doubled the Bill — Field Notes on Measuring the Marginal Utility of Thinking Tokens

You pinned budget_tokens high 'to be safe,' accuracy barely moved, and the bill kept climbing. These field notes show how to ledger real thinking-token usage by p50/p95/hit-rate and measure how much accuracy each extra 1,000 thinking tokens actually buys.

claude8extended-thinking7budget-tokenscost-optimization30observability21

Premium Article

One morning, a nightly ticket-classification job on an app I run as an indie developer was pushing my bill to nearly double the prior month. Tracing it back, the cause was a change I had made almost absent-mindedly: while moving to Opus 4.8, I pinned budget_tokens at 32,000 "to leave headroom." Accuracy had barely moved. I was paying for deeper reasoning that never reached the answer — most of the money spent on thinking was landing nowhere.

These are the field notes from getting that budget back down to a defensible number. The whole thing rests on one idea: budget is neither "safer when larger" nor "cheaper when smaller." Once you measure how much accuracy one more step of budget actually buys, the number you should pay for is nearly self-selecting.

budget_tokens is a ceiling, not a fixed cost

Clear up the common misreading first. budget_tokens caps the tokens the model may spend on internal reasoning; it does not spend that amount every call. Easy inputs wrap up in a few hundred tokens, and only hard tasks push toward the ceiling.

SettingThe misreadingActual behavior
budget=32,000Every call is billed for 32,000Only reaches deep on hard tasks; plain inputs stop in the hundreds
budget=4,000Always cheapMay truncate reasoning on hard tasks and return a shallow answer

Raising the budget hands the model room to think deeply when it hits a hard task. Miss that, and "the bill scares me, so cut everything" turns a model that could have solved the problem into one that can't. And going the other way — "the bill scares me, so make it big," which is exactly what I did — wastes the headroom on easy tasks and compounds quietly on the hard ones. Either fixed value misses without measurement.

from anthropic import Anthropic
 
client = Anthropic()
 
resp = client.messages.create(
    model="claude-opus-4-8",
    max_tokens=8000,
    thinking={"type": "enabled", "budget_tokens": 10000},  # ceiling for reasoning
    messages=[{"role": "user", "content": "Optimize this SQL: ..."}],
)
 
# Always record how many thinking tokens were actually spent
usage = resp.usage
print(usage.thinking_tokens, usage.output_tokens)

response.usage.thinking_tokens is the real spend. Whether you log it on every request is what separates later tuning that is measurement from tuning that is guesswork.

Ledger the thinking tokens first

Before touching the budget, ledger production usage. Averages hide the long tail, so keep three things: p50, p95, and hit-rate — the share of requests where thinking_tokens reached at least 95% of the budget. A high hit-rate hints that reasoning is being cut off.

import json, time, statistics
from pathlib import Path
 
LEDGER = Path("thinking_ledger.jsonl")
 
def call_and_log(client, *, model, budget, messages, task_type):
    resp = client.messages.create(
        model=model, max_tokens=8000,
        thinking={"type": "enabled", "budget_tokens": budget},
        messages=messages,
    )
    u = resp.usage
    rec = {
        "ts": time.time(), "task_type": task_type, "budget": budget,
        "thinking_tokens": u.thinking_tokens,
        "output_tokens": u.output_tokens,
        "hit": u.thinking_tokens >= budget * 0.95,  # pinned to the ceiling?
    }
    with LEDGER.open("a") as f:
        f.write(json.dumps(rec) + "\n")
    return resp
 
 
def summarize(task_type):
    rows = [json.loads(l) for l in LEDGER.read_text().splitlines()]
    rows = [r for r in rows if r["task_type"] == task_type]
    tt = sorted(r["thinking_tokens"] for r in rows)
    if not tt:
        return None
    p50 = statistics.median(tt)
    p95 = tt[min(len(tt) - 1, int(len(tt) * 0.95))]
    hit_rate = sum(r["hit"] for r in rows) / len(rows)
    return {"n": len(rows), "p50": p50, "p95": p95,
            "max": tt[-1], "hit_rate": round(hit_rate, 3)}
 
# e.g. {"n": 214, "p50": 1180, "p95": 5200, "max": 9900, "hit_rate": 0.02}

Past 100 records or so, the shape per task type emerges. Finding budget=32,000 on classification while p95 sits at 5,200 is a common sight. The other 26,800 is just headroom you may never touch, and plain inputs are not billed for it. The real problem is the case where hard tasks do reach deep and that depth still doesn't move the answer. That is what we measure next.

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
Instrumentation code that ledgers real thinking-token spend by p50/p95 and budget hit-rate, so you set budget from data instead of gut feel
An eval harness that measures the accuracy gained per 1,000 extra thinking tokens as marginal utility
A rule for telling under-budget apart from an overloaded task when the hit-rate is high but accuracy stalls
Secure payment via Stripe · Cancel anytime

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Claude Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $15 for lifetime access
View Membership →

Related Articles

API & SDK2026-07-19
When Prompt Caching Was On but the Bill Didn't Move — Field Notes on Instrumenting cache_read to Close the Hit-Rate Gap
You added cache_control but your Claude API bill barely changed. Before guessing at fixes, record cache_read and cache_creation on every request and split the hit-rate gap into three causes: non-deterministic prefixes, TTL expiry, and sub-threshold blocks.
API & SDK2026-06-23
When Claude API Prompt Caching Quietly Stops Hitting in Production — Field Notes on TTL and Measured Savings
Prompt caching works beautifully the day you ship it, then quietly stops hitting in production. The five things that break the prefix, how to choose between 5-minute and 1-hour TTL, and how to measure real savings from usage instead of guessing.
API & SDK2026-05-05
The Real Cost of Claude API Extended Thinking in Production — ROI Data by Task Type
Three months of measured cost, quality, and speed data for Extended Thinking across five task categories. Learn exactly when extended thinking is worth it—and when it's not.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →