When Claude Code is billed through an API, it is tempting to estimate spend from the visible conversation transcript: count the main thread and each subagent turn, then total their tokens. That misses calls Claude Code makes outside the transcript.
I reconciled provider billing for an extended multi-agent coding run with local transcripts deduplicated by message.id and each session's cost-state records. The transcript total was materially lower than the provider total. The missing calls had a consistent shape: very large cache reads followed by tiny outputs. Three recurring sources stood out: auto-mode permission checks, background subagent progress summaries, and away recaps.
The measurements below come from one workload and are rounded to relative figures. They are useful for finding cost drivers, not for predicting every account's bill. Context size, cache hits, provider pricing, and agent activity all matter.
| Call type | In the transcript? | Relative impact observed |
|---|---|---|
| Main-thread and subagent conversations | Yes | Most of the visible spend |
| Background subagent progress summaries | No | The largest hidden item, around 16–20% of Opus spend in this workload |
| Auto-mode permission classifier | No | A small share of total spend with a cheaper model; several percent when compared with leaving it on Sonnet |
| Away recap | No | Small in this sample, but grows with context length and the number of recaps |
| Compaction and small Haiku tasks | No | Additional costs that transcript-only accounting misses |
1. Route auto-mode permission checks to a cheaper model
In auto mode, Claude Code asks a classifier to assess some potentially risky tool calls, especially Bash commands. The classifier uses the Sonnet model slot, configured through ANTHROPIC_DEFAULT_SONNET_MODEL. That makes the slot a useful place to route this high-volume, short-output task to a less expensive compatible model.
In the measured setup, the Sonnet slot used DeepSeek V4.1 Flash through a gateway that exposed both Claude and DeepSeek models under the same ANTHROPIC_BASE_URL. Claude Code accepts one base URL, so a gateway must provide both services through that endpoint for this arrangement to work.
export ANTHROPIC_DEFAULT_SONNET_MODEL='DeepSeek-V4.1-Flash-1017[1m]'
export ANTHROPIC_DEFAULT_SONNET_MODEL_SUPPORTED_CAPABILITIES=effort,thinking,adaptive_thinking,interleaved_thinking
The model identifier above was the one accepted by the gateway used in this measurement; model names vary by gateway. The second variable declares request capabilities. When Claude Code encounters an unrecognized model name through a first-party-style ANTHROPIC_BASE_URL, it may assume support for options such as adaptive thinking and effort. Keep the capability list aligned with the model actually behind the name: sending an unsupported option can make the gateway reject a request with HTTP 400.
Using DeepSeek Flash made the classifier workload roughly an order of magnitude cheaper than pricing it as Sonnet. In this workload, the difference was several percent of the overall bill. That comparison is an estimate: model tokenizers differ, and the cache-hit rate may change when the model changes.
This substitution has a safety trade-off. The auto-mode classifier is the only gate in this path. A less capable classifier may be more likely to allow a risky command, so evaluate that risk before changing the model.
The Haiku slot, configured with ANTHROPIC_DEFAULT_HAIKU_MODEL, handles other short tasks such as naming sessions and background agents, labeling tool activity, and classifying background-session status. These calls are also billed even though they do not appear in the transcript; in the measured run, the status classifier's calls were not recorded in cost-state either. Routing these tasks to a cheaper compatible model can reduce that recurring overhead as well.
2. Stop background subagent progress summaries
A background subagent started with the Agent tool can display a live status line in the agent panel. Claude Code generates that line by periodically asking the subagent's model for a short progress summary. In the version examined, a timer ran about every 30 seconds. If the transcript had changed, Claude Code forked the subagent's full context, appended a brief summary request, and made another model call. These requests were tagged querySource: "agent_summary" and skipTranscript: true, so transcript-based usage tools did not count them.
Subagent contexts in this workload often contained hundreds of thousands of tokens. Each summary reread a large cached context to produce only a few words. The resulting summary calls accounted for about 16–20% of Opus spend and added roughly 30% on top of subagent conversation costs. Per hour, their cache reads were about half to four-fifths of the subagents' own cache reads.
The codebase also contained a cheaper short summary mode that first condensed the conversation into a small note and then used a smaller model. That mode depended on a remotely delivered Anthropic feature flag. With a third-party gateway and CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1, the flag was unavailable in the setup examined, leaving the default full mode.
In the inspected version, Claude Code did not expose a supported setting to turn summaries off. CLAUDE_CODE_AGENT_PROGRESS_SUMMARIES enabled the feature; setting it to 0 did not disable it. The implementation tied summary scheduling to the fork-subagent switch. Setting that switch to 0 prevented the summary timer from being created:
{ "env": { "CLAUDE_CODE_FORK_SUBAGENT": "0" } }
This is a workaround, not a stable product setting. It also disables fork-type subagents, which inherit the main conversation's context. In the test, the agent panel kept the initial task description instead of updating its progress line. If your workflow depends on fork-type subagents, this switch changes their behavior too.
I verified the behavior with debug logging in Claude Code 2.1.310: a background subagent produced AgentSummary fork log entries with the switch enabled and none with it set to 0; the subagent transcripts showed the same work in both cases. GitHub issues #86879 and #105981 describe similar behavior across versions 2.1.309–2.1.312. The implementation depends on an internal condition in obfuscated code and can change in any release. Recheck it after upgrading. A debug session can be inspected with:
claude --debug-file /tmp/as.log
# Start and finish a background subagent, then check whether a summary fork occurred.
grep -c "AgentSummary\] Forking" /tmp/as.log
A result of 0 means no summary fork was logged in that session. The source analysis reports that Claude Code 2.1.311 fixed a cache-miss path that could resend a summary context at full input price. Verify the behavior in the release you use rather than relying on this version-specific observation.
3. Disable away recaps
When you return to a terminal after being away, Claude Code can show a short recap of the current goal and next step. This is another off-transcript call: it forks the main thread's context and asks the model for a brief summary, tagged querySource: "away_summary". It uses the main model, not Haiku. Reusing the main thread's prompt cache can be cheaper than sending the context to a smaller model with a cold cache.
Away recaps were a small cost in this workload, but their price grows with the main thread's context and with how often recaps are triggered. If the recap is not useful in your workflow, turn it off in /config or set awaySummaryEnabled in ~/.claude/settings.json:
{ "awaySummaryEnabled": false }
Keep context and cache behavior in view
Two ordinary practices help with the same underlying cost driver: the amount of context each call has to read. First, set a shorter auto-compaction window, for example, around 300,000–400,000 tokens through /config or autoCompactWindow. Compaction itself costs money, but a shorter context can reduce the cost of many later calls in a long session.
Second, avoid long idle gaps when prompt-cache reuse matters. In API-key mode, the default cache lifetime is five minutes. After it expires, a later call may have to write the full context again at the uncached input rate. Rewriting a large context at the uncached input rate can cost materially more than one recap that reuses the cache.
Takeaway
The three changes address different call paths: use a cheaper compatible model for auto-mode classification, disable background progress summaries if their feature trade-offs are acceptable, and turn off away recaps if they add little value. In the measured workload, they reduced estimated spend by roughly 20–30% relative to using Sonnet for the classifier, with progress summaries accounting for most of the savings.
The largest item was easy to miss because it never entered the transcript. Comparing provider billing with transcript totals and Claude Code's cost-state records exposed it. The summary workaround is fragile, and changing the classifier has a safety cost; both should be rechecked against the exact Claude Code version and workflow in use.
Top comments (0)