We put Claude Code and OpenCode on the same model, the same machine, and the same tasks, then examined everything sent and received.
Claude Code is far hungrier:
When we asked both harnesses for a one-line reply, Claude Code used roughly 33,000 tokens of system prompt, tool schemas, and injected scaffolding before the prompt even arrived. OpenCode used about 7,000.
Claude Code is far more cache inefficient:
OpenCode’s request prefix was byte-identical in every run we captured; it paid to cache its payload once per session and read it back for pennies.
Claude Code on the other hand re-wrote tens of thousands of prompt-cache tokens mid-session, run after run, and on the same task wrote up to 54x more cache tokens than OpenCode.
Cache writes of course are billed at a premium, which accounted for the usage dashboard climbing when using Claude Code.
Config further bloats the prompt:
A production repository’s 72KB instruction (AGENTS.md or CLAUDE.md) file adds another (avg) 20,000 tokens to every single request. Five modest MCP servers add 5,000 to 7,000 more. By the time a real working setup sends its first request, it is 75,000 to 85,000 tokens deep before the user has typed a word.
Subagents add to the cost:
A small task that cost 121,000 tokens done directly cost 513,000 tokens when fanned out to two subagents, because every subagent has its own bootstrap cost, and the parent then consumes its transcript.
We found one result in favour of Claude Code:
On a multi-step task Claude Code’s whole-task total came out lower than OpenCode’s, because it batches tool calls into fewer requests while OpenCode re-pays its smaller baseline turn after turn. The meter starts higher; how the session unfolds decides who spends more. That advantage held on the first model we tested; re-run on a newer one, the same task took twice the requests and cost roughly 298,000 tokens against OpenCode’s 133,000.
Every finding above was cross-checked on a second model family. The pattern held, with one nuance we cover below.
The rest of this post shows how we measured all of this at the API boundary, where the tokens go, and what prompt caching does and does not save you.
Why measure this at all
Every token of harness payload is a token of working context you cannot spend on your task.
If you operate agentic AI in production, particularly under the EU AI Act where Article 12 expects you to log and understand your system’s behaviour, “what does my agent actually send” is a question you should be able to answer with data.
Method
We spliced a logging proxy between each harness and the model endpoint.
harness (Claude Code / OpenCode) → logging proxy (captures request payloads + response usage) → model endpoint
The proxy records two things per request. The first is the exact JSON payload the harness emitted, meaning the system blocks, tool schemas, and messages. The second is the usage block the API returned, covering input tokens, cache writes, cache reads, and output tokens.
The payload capture is ground truth for what the harness sends. The usage block is ground truth for what was metered.
We tested under these conditions.
Harnesses. Claude Code 2.1.207 and OpenCode 1.17.18, both pinned to claude-sonnet-4 – 5, July 2026. A reduced matrix (the floor, the cache task, and the multi-step task) was later re-run pinned to claude-fable-5; where the model changed the result, we say so inline.
Baseline isolation. Fresh config directories with no MCP servers, no user settings, and no memory; an empty workspace with no instruction files; permissions bypassed. Multiplier lanes then add one variable at a time.
Tasks. T1 says “Reply with exactly: OK” and isolates fixed overhead (three runs per harness). T2 reads a seeded file and summarises it. T3 is a write-run-test-fix loop against FizzBuzz plus a checker script.
Quality check. A separate ten-lane benchmark, five runs per harness against a seeded, hash-verified test suite, scored pass rates alongside token cost; reported in the quality section.
Zero-tools variant. Claude Code with –tools “” and OpenCode with “tools”: {“*”: false}, separating system prompt from tool schema weight.
One full disclosure note before the numbers:
Our traffic passes through Meridian, a local gateway that bridges the Claude Code SDK to a standard Anthropic endpoint so a Claude Max subscription can drive third-party tools. It wraps every request in the SDK’s own envelope, a constant we measured at roughly 6,200 tokens on the Sonnet path and 3,500 on the Fable path with bare calibration requests and subtracted from every metered figure below.
Payload-level figures come from the captured request bodies, which the gateway cannot affect, and are exact.
Character-to-token conversion for component estimates uses each harness’s own measured ratio of 4.1 to 4.4 characters per token, derived from cold-cache anchors where the metered write equals the full payload, rather than a generic heuristic.
Part I. The floor
The fixed overhead of saying OK
The task was 22 characters. Here is what each harness sent with it on its first request.
Component
Claude Code
OpenCode
System prompt
27,344 chars, 3 blocks
9,324 chars, 1 block
Tool schemas
27 tools, 99,778 chars
10 tools, 20,856 chars
First-message scaffolding
7,997 chars of <system-reminder> blocks
none
The actual prompt
22 chars
22 chars
First-turn payload (calibrated)
~32,800 tokens
~6,900 tokens
OpenCode’s request is close to minimal. There is one system block that opens with “You are OpenCode, the best coding agent on the planet”, plus ten classic coding tools, plus the user’s prompt as the only content.
Claude Code’s request is a platform bootstrap. The 27 tools include the coding core plus an entire background-agent and orchestration suite, from CronCreate and Monitor to the Task family, worktree management, and push notifications.
Before the user-entered prompt, its first message carries three injected reminder blocks; a catalogue of agent types for delegation, a catalogue of available skills, and user context.
Tool schemas are the dominant term for both. Roughly 24,000 of Claude Code’s ~33,000 tokens are tool definitions, versus roughly 4,800 of OpenCode’s ~6,900.
Zero tools, pure harness
Stripping the tools isolates the system prompt itself. Claude Code’s weighs in at 26,891 chars, about 6.5k tokens. OpenCode’s is 8,811 chars, about 2.0k tokens.
Both harnesses trim their prompt slightly when tools are disabled. Even with no tools at all, Claude Code’s instruction set is over three times the size of OpenCode’s; the residual is behavioural doctrine, meaning tone rules, safety guidance, task-management instructions, and environment description.
A one-tool task
T2 asked each harness to read a file and summarise it. Both produced correct summaries.
Claude Code took 6 HTTP requests and roughly 199,000 cumulative metered input tokens. OpenCode took 4 requests and roughly 41,000, plus one Haiku side call for session titling.
Most of those tokens are cache reads billed at a tenth of the input price. Three things scale with payload regardless; the first-turn cache write, the per-turn read, and context-window consumption, which no cache discount reduces.
A 33k-token baseline means every turn starts a sixth of the way into a 200k window before any code enters the conversation.
A multi-step task, where the gap closes
T3, the write-run-test-fix loop, inverted the expectation set by the baselines.
Metric
Claude Code
OpenCode
Model requests
3
9 (+1 title call)
Tool-calling style
parallel batch in one round trip
one tool call per turn
Cumulative metered input
~121,000 tokens
~132,000 tokens
Claude Code batched the entire job, two file writes and two script executions, into a single parallel tool round trip. OpenCode made exactly one tool call per turn and took nine.
Because the baseline is re-sent on every request, request count multiplies baseline. OpenCode paid its ~7k baseline nine times, Claude Code paid its ~33k three times, and the totals converged.
Whole-task input roughly equals baseline times request count, plus conversation growth. A large-baseline harness that batches aggressively and a small-baseline harness that serialises can land in the same place.
Two structural details emerged from the payloads:
Claude Code injects an additional <system-reminder> block as the conversation progresses, three on the first turn and four by the first tool round trip, so its scaffolding grows with turn count.
OpenCode’s per-turn marginal payload, roughly 400 to 2,200 chars per turn, is pure conversation content.
Does a newer model change the picture?
We re-ran the floor on Claude Fable 5 to check whether the gap was a Sonnet artefact, and it shrank (which we didn’t expect).
Claude Code’s system prompt is model-conditional. It sent 27,787 chars of instructions to Sonnet but only 10,526 to Fable, with tool schemas also trimmed from 99,778 to 82,283 chars. Same 27 tools, much less doctrine.
OpenCode’s payload was byte-identical across both models.
The floor gap on Fable comes out at roughly 3.3x by payload against 4.7x on Sonnet. Still far hungrier, but the ratio is model-dependent.
The multi-step convergence did not survive the change either:
On Fable, Claude Code took six requests instead of three, including an 85,686-token mid-session cache re-write, and landed at roughly 298,000 tokens against OpenCode’s 133,000.
Therefore the batching advantage is model behaviour, not a harness constant.
These lanes also produced OpenCode’s only mid-session cache write in the entire study, a single event of roughly 6,000 tokens; everything else it sent stayed byte-stable.
One served-model note belongs here:
Under Fable we received responses alternately as claude-fable-5 and claude-opus-4 – 8, consistent with those tiers sharing infrastructure.
The Fable lanes were smaller samples, two runs for the floor and cache tasks and one for the multi-step task, so treat them as directional confirmation rather than a second full study.
Part II. The multipliers
The floor (above) explains a session that starts lean and stays short.