Claude Code sends 33k tokens before reading the prompt; OpenCode se...
A one-line request such as rename getUser() to fetchUser() can arrive at the model as a 33,001-token prompt. In one observed setup, Claude Code contributed roughly 33,000 tokens of instructions, tool definitions, and environment context before the developer’s text; OpenCode contributed about 7,000. That 26,000-token difference is larger than many production prompts in their entirety.
Those numbers are not universal benchmarks. Client version, enabled tools, MCP servers, project instructions, and provider routing all change the payload. But the underlying problem is real: an agentic coding client is a prompt compiler, and the text you type is only one of its inputs.
What “before reading the prompt” actually means
The model does not literally process a hidden 33,000-token request and then open a second message containing your prompt. The client usually submits one ordered context containing some combination of:
- A system prompt defining behavior and constraints.
- Tool schemas for file access, search, shell commands, edits, and task tracking.
- Instructions from repository files.
- Environment metadata such as the working directory and platform.
- MCP server tools and their descriptions.
- Conversation history.
- Your new user message.
“Before” means these tokens appear earlier in that sequence. A simplified request might look like this:
{
"model": "sonnet-4.6",
"system": "You are a coding agent... [thousands of tokens]",
"tools": [
{
"name": "read_file",
"description": "Read a file from the workspace...",
"input_schema": {
"type": "object",
"properties": {
"path": { "type": "string" },
"start_line": { "type": "integer" },
"end_line": { "type": "integer" }
},
"required": ["path"]
}
}
],
"messages": [
{
"role": "user",
"content": "Rename getUser() to fetchUser()."
}
]
}
The model needs enough of this scaffolding to behave like a coding agent rather than a chat box. The problem is not that overhead exists. The engineering question is whether each token earns its place on every turn.
Where 33,000 tokens come from
A large system prompt alone is rarely the whole explanation. Agent overhead tends to accumulate across several layers.
| Source | Why it is included | Common failure mode |
|---|---|---|
| Core agent instructions | Defines workflow, safety rules, and editing behavior | Repeats similar rules in multiple sections |
| Tool schemas | Teaches the model how to call tools | Verbose descriptions and duplicated examples |
| MCP integrations | Exposes external services and resources | Every server publishes every tool on every turn |
| Repository instructions | Adds project-specific conventions | Large global files apply to unrelated tasks |
| Environment context | Identifies platform, paths, and capabilities | Static details are resent unnecessarily |
| Conversation history | Preserves task state | Raw tool output remains in context indefinitely |
| Sub-agent definitions | Enables specialized delegation | Definitions are loaded even when delegation is irrelevant |
Tool schemas are a particularly easy source of bloat. A client with 40 tools does not merely send 40 names. It may send descriptions, JSON Schema properties, nested enums, validation constraints, and usage guidance for each one.
MCP makes this worse when used indiscriminately. Connecting GitHub, a database, an issue tracker, browser automation, observability, and cloud infrastructure can add dozens or hundreds of tool definitions. Asking for a local TypeScript rename does not require the model to understand the full schema of create_incident, query_warehouse, and rotate_deployment.
In practice, repository instructions are the next common gotcha. Teams often copy documentation into an agent file because “more context helps.” A 6,000-token architecture guide then accompanies CSS edits, typo fixes, and dependency updates—even when none of it affects the task.
The cost is more than the first request
The obvious cost is input-token billing. Suppose two clients contribute 33,000 and 7,000 tokens respectively:
difference = 33,000 - 7,000 = 26,000 input tokens
At an illustrative uncached input price of $3 per million tokens, the difference is:
26,000 / 1,000,000 × $3 = $0.078 per request
Across 1,000 agent turns per day, that becomes $78 per day before output tokens. Substitute the actual input, cached-input, and cache-write prices for your selected model; they differ by provider and model.
Prompt caching can make a stable prefix substantially cheaper, but it does not make the overhead free. Four separate effects matter:
- Context capacity: Cached tokens still occupy the context window.
- Time to first token: Providers still need to identify or process the prefix, even when cache handling reduces work.
- Cache misses: Changing instructions, tool ordering, or schemas can invalidate the reusable prefix.
- Attention quality: Relevant task details compete with a larger body of instructions and history.
A 33,000-token prefix consumes 16.5% of a 200,000-token context window before source files or command output appear. On a 1-million-token model such as Fable 5, it consumes only 3.3%, but that does not eliminate billing or attention trade-offs. Larger windows reduce the capacity constraint; they do not justify sending irrelevant material.
Measure the request, not the text box
Do not estimate overhead from the visible prompt. Capture usage at the provider boundary.
The most reliable measurements come from server-reported usage fields. Anthropic-style, OpenAI-style, and Gemini-style APIs expose different response structures, so normalize them in your gateway:
{
"timestamp": "2026-03-12T10:15:00Z",
"client": "coding-agent-a",
"model": "sonnet-4.6",
"input_tokens": 33142,
"output_tokens": 418,
"cache_read_tokens": 29810,
"cache_write_tokens": 0,
"user_message_tokens": 23,
"tool_count": 47
}
Then calculate an operational approximation:
def request_overhead(input_tokens: int,
user_tokens: int,
injected_file_tokens: int = 0) -> int:
return max(0, input_tokens - user_tokens - injected_file_tokens)
sample = request_overhead(
input_tokens=33142,
user_tokens=23,
injected_file_tokens=0,
)
print(sample) # 33119
This is not a perfect semantic split. Some APIs count images, tool results, or cached content differently, and local tokenizers may disagree with provider accounting. Server usage is the billing authority.
For a useful comparison, run a controlled canary:
- Start a new session with no conversation history.
- Use the same model and provider.
- Disable optional MCP servers.
- Send the same tiny prompt, such as
Reply only with OK. - Record input tokens, cache fields, tool count, and latency.
- Enable integrations one at a time and repeat.
- Run a second warm request to separate cold cache writes from cache reads.
A shell-level summary over normalized JSON logs is enough to expose regressions:
jq -s '
group_by(.client) |
map({
client: .[0].client,
requests: length,
avg_input: (map(.input_tokens) | add / length),
avg_cache_read: (map(.cache_read_tokens // 0) | add / length),
avg_tools: (map(.tool_count) | add / length)
})
' usage.jsonl
Track percentiles as well as averages. A client may look efficient in fresh sessions while growing badly after 20 tool-heavy turns.
Reducing overhead without crippling the agent
The wrong optimization is deleting every instruction until the client becomes cheap but unreliable. Optimize relevance and lifecycle instead.
Load tools progressively
Start with filesystem search, file reading, editing, and shell execution. Add deployment, database, browser, or issue-tracker tools only when the task requires them.
If the API requires all tools up front, route tasks through profiles:
TOOL_PROFILES = {
"local_code": ["search", "read_file", "edit_file", "run_tests"],
"database": ["search", "read_file", "query_db", "inspect_schema"],
"release": ["search", "read_file", "run_tests", "create_release"],
}
This also reduces the chance that the model selects a plausible but inappropriate tool.
Make schemas compact, not ambiguous
Remove prose that restates JSON Schema, duplicated examples, and ornamental wording. Preserve details that affect correctness.
{
"name": "read_file",
"description": "Read a UTF-8 text file. Line numbers are 1-based.",
"input_schema": {
"type": "object",
"properties": {
"path": { "type": "string" },
"start": { "type": "integer", "minimum": 1 },
"end": { "type": "integer", "minimum": 1 }
},
"required": ["path"],
"additionalProperties": false
}
}
“Make descriptions shorter” has a limit. Removing the fact that lines are 1-based may save a few tokens and create repeated failed calls.
Scope project instructions
Keep global instructions short: build commands, critical conventions, and non-negotiable constraints. Put Python, frontend, infrastructure, and release guidance in directory-specific files loaded only when relevant.
Prefer:
Run: npm test
Format: npm run lint:fix
Never edit generated files under src/generated/
Frontend-specific guidance: apps/web/AGENTS.md
over embedding the entire engineering handbook.
Compact history deliberately
Retain decisions, changed files, failing tests, and unresolved questions. Drop repetitive directory listings and successful command output. Summaries must be treated as lossy state: preserve exact error messages or code fragments when the next step depends on them.
Applying this to Claude, GPT, and Gemini APIs
The same design applies whether an agent targets Sonnet 4.6, Haiku 4.5, GPT-5.5, Gemini 3, or another model. Provider syntax changes; context economics do not.
At the platform layer, log:
- Model and provider route.
- Total, cached, and output tokens.
- Tool-schema token estimate or tool count.
- Instruction-set version.
- Session turn number.
- Time to first token and total latency.
- Task outcome, such as tests passing.
This makes multi-model routing more meaningful. A cheaper model can still produce an expensive request if the client wraps every turn in a huge prefix. Conversely, a larger model may be cost-effective when prompt caching is stable and it completes the task in fewer turns.
If you use AI Prime Tech for lower-cost Claude, GPT, or Gemini API access, preserve this telemetry across routes. Lower unit pricing helps, but reducing 26,000 unnecessary tokens is a structural saving that applies to every provider.
Practical takeaways
- Treat coding agents as prompt compilers, not thin chat interfaces.
- Interpret 33,000 versus 7,000 tokens as a configuration snapshot, not a permanent universal ranking.
- Measure fresh sessions, warm-cache turns, and long-running sessions separately.
- Disable unrelated MCP servers and load specialized tools on demand.
- Keep global project instructions small and scope detailed guidance by directory.
- Compact history without discarding exact state needed for the next action.
- Use server-reported token usage for billing analysis.
- Evaluate cost per completed task, not merely cost per token or per request.
- Re-run overhead canaries whenever client versions, tools, or instruction files change.
The goal is not the smallest possible prompt. It is the smallest prompt that still gives the model the tools, constraints, and state required to finish the task correctly.
One API key for Claude Opus 4.8, Sonnet 4.6, Haiku 4.5, Fable 5, plus GPT & Gemini — up to 80% off official pricing, pay-as-you-go.
Get Your API Key →