DEV Community

The 33k-token preamble is a bet. Here's how to check if it's paying off.

The 33k-token preamble is a bet. Here's how to check if it's paying off.

Somebody put a logging proxy between two coding agents and the model, asked each of them to reply with the single word "OK," and watched what went over the wire. Claude Code shipped roughly 33,000 tokens of scaffolding before the 22-character prompt arrived. OpenCode shipped about 7,000. The Systima writeup has the full teardown, and the number is doing exactly what a good gotcha number does: making everyone feel smart for using the leaner tool.

Resist that. The interesting question isn't "why is Claude Code so bloated." It's "what does that context buy, and is it worth the price for your task." Because a 33k preamble isn't waste by definition. It's a wager: that spending tokens up front on capability makes the model better enough, per turn, to earn them back. OpenCode is refusing that wager. Whether refusing is smart depends entirely on the game you're playing.

Where the tokens actually go

First, kill the idea that this is all fluffy system-prompt prose. It isn't. Per the source's payload capture on Sonnet 4.5:

  • Claude Code's system prompt: ~27,000 characters across three blocks.
  • Its tool schemas: 27 tools, ~99,778 characters.
  • First-message scaffolding: ~8,000 characters of injected reminder blocks.

OpenCode, same task:

  • System prompt: ~9,300 characters, one block.
  • Tool schemas: 10 tools, ~20,856 characters.
  • Scaffolding: none.

Look at where the mass is. Roughly 24,000 of Claude Code's ~33,000 first-turn tokens are tool definitions. The system prompt with tools stripped is about 6.5k tokens; OpenCode's stripped prompt is about 2k. So the "33k vs 7k" headline is mostly a story about tool surface area, not verbosity.

And those tools aren't ten variations on read_file. The source notes Claude Code ships the coding core plus an orchestration suite - cron jobs, monitoring, a Task family for delegating to subagents, worktree management, push notifications. That's not a coding assistant. That's a platform bootstrap that happens to also edit code. The injected reminder blocks confirm it: a catalogue of agent types to delegate to, a catalogue of skills, and user context. Claude Code is loading a runtime. OpenCode is loading an editor with a mouth.

That reframes the whole comparison. Nobody is confused about whether 27 tools cost more than 10. The question is whether you'll use the extra 17.

The bet, stated plainly

Every token of harness payload is a token you can't spend on actual code, and it rides along on every turn - re-sent or re-read from cache each time. That's the cost side, and it's real.

The capability side is the wager. A tool schema in context is the model's entire menu of what it's allowed to do. Give it a Task tool and a directory of subagent types, and it can plan a fan-out on its own. Don't, and it can't - no amount of clever prompting conjures a capability whose interface isn't in context.

The 33k is Claude Code betting that a model which knows it can delegate, monitor, and manage worktrees produces better trajectories on the tasks that need those moves. The source found evidence the bet sometimes pays and sometimes torches your budget:

  • On a multi-step task, Claude Code's whole-task total came in lower than OpenCode's. It batches tool calls into fewer requests; OpenCode re-pays its smaller baseline turn after turn after turn. The meter starts higher but the session ends cheaper.
  • Fan the same small task out to two subagents and it went from ~121,000 tokens done directly to ~513,000 - because each subagent pays its own bootstrap and then the parent eats the transcript.

Same capability. One case it saved money, one case it quadrupled the bill. That's not a contradiction. That's what a bet looks like.

The part that actually decides it: cache

Here's the finding that should change how you read the headline. The floor number tells you almost nothing about steady-state cost, because these agents cache differently, and one does it far better.

Per the source, OpenCode sent a request prefix that came back byte-for-byte identical on every captured run. An unchanging prefix means the prompt cache lands every turn - you pay full freight once, then read it back cheap.

Claude Code did the opposite: it rewrote tens of thousands of cached tokens partway through a session, and on one task its cache-write volume ran to roughly 54x what OpenCode racked up. Cache writes carry a premium over reads, which is exactly why the usage dashboard keeps ticking up.

So the real axis isn't 33k vs 7k. It's cache stability. A big preamble that's byte-stable is a rounding error after turn one. A smaller preamble that mutates every turn bleeds you slowly. The floor measures the wrong thing; the cache write rate measures the thing that shows up on the invoice.

A framework you can run tomorrow

Stop arguing about baseline tokens. Measure three numbers for any agent you're evaluating, and you'll know whether its context budget is a bet worth taking on your workload.

  1. Fixed overhead (the floor). Splice a logging proxy between the harness and the endpoint. The cleanest anchor is a trivial task - ask it to reply with one word - and capture the request body. This is a real proxy dependent on your setup, not something I ran, but the shape is a few dozen lines:
from mitmproxy import http
import json

def request(flow: http.HTTPFlow) -> None:
    if "/messages" not in flow.request.path:
        return
    body = json.loads(flow.request.get_text())
    sys_chars = sum(len(b.get("text", "")) for b in body.get("system", []))
    tool_chars = len(json.dumps(body.get("tools", [])))
    print(f"system={sys_chars}c tools={tool_chars}c "
          f"n_tools={len(body.get('tools', []))}")

def response(flow: http.HTTPFlow) -> None:
    if "/messages" not in flow.request.path:
        return
    usage = json.loads(flow.response.get_text()).get("usage", {})
    print(f"in={usage.get('input_tokens')} "
          f"cw={usage.get('cache_creation_input_tokens')} "
          f"cr={usage.get('cache_read_input_tokens')}")

Payload-level counts are exact and no gateway can distort them; that's your ground truth for what's sent.

  1. Cache write rate. Run a multi-turn task and watch cache_creation_input_tokens per turn. If it's ~0 after the first turn, the prefix is stable and the floor is a one-time cost. If it keeps climbing, the preamble is mutating and your steady-state cost is far higher than the floor implies. This is the number that actually predicts the bill.

  2. Whole-task total, not per-turn. A leaner baseline that re-pays every turn can lose to a fat baseline that batches. Only the end-to-end token count for a representative task tells you who's cheaper. And the answer flips by task, so use tasks that look like your work - not FizzBuzz.

Then judge the bet. Is your workload single-shot Q&A over a file? Then a 33k orchestration bootstrap is pure tax; the leaner agent wins and it isn't close. Is it long, multi-step refactors where planning and delegation actually fire? Then the capability those tokens buy may earn out - if the cache is stable enough that you only pay for it once.

The takeaway

"4.7x more tokens" is a fact about a menu, not a verdict about a meal. The heavy preamble is capability the model can reach for, priced up front; the light one is a refusal to pay for options you might not use. Neither is right in the abstract. What makes it decidable is three measurements - floor, cache write rate, whole-task total - and the discipline to run them on tasks shaped like yours.

The gotcha number tells you who starts the turn heavier. Your proxy tells you who's actually cheaper. Those are not the same agent, and you can't guess which is which. Measure it.

Comments

No comments yet. Start the discussion.