context_window.used_percentage doesn't match internal context warning calculation
Description
The used_percentage and remaining_percentage fields added in v2.1.6 for status line input don't include system overhead (tool definitions, CLAUDE.md files, MCP server configs, system prompt). This causes a significant discrepancy between the reported percentage and Claude Code's internal "Context low" warning.
Steps to Reproduce
- Use Claude Code 2.1.6 with a custom status line that reads
context_window.used_percentage - Use the session until context gets high
- Compare
used_percentagevalue with Claude's "Context low (X% remaining)" warning
Expected Behavior
used_percentage should match the percentage used in Claude Code's internal warning, so users can accurately track context usage.
Actual Behavior
| Source | Value |
|--------|-------|
| context_window.used_percentage | 75% |
| Claude Code warning | "Context low (6% remaining)" = 94% used |
19% discrepancy - the system overhead is not included in used_percentage.
Debug Data
{
"total_input_tokens": 78446,
"total_output_tokens": 28311,
"context_window_size": 200000,
"current_usage": {
"input_tokens": 0,
"output_tokens": 115,
"cache_creation_input_tokens": 1793,
"cache_read_input_tokens": 147730
},
"used_percentage": 75,
"remaining_percentage": 25
}
current_usage total: 149,638 tokens = 74.8% ≈ matches used_percentage: 75
But Claude's warning says 6% remaining (94% used), meaning ~38,000 tokens of system overhead aren't accounted for.
Suggested Fix
Either:
- Include system overhead in
used_percentageto match internal warning calculation - Add a separate
system_tokensfield so status lines can calculate the true total - Add a
total_used_percentagefield that includes everything
Environment
- Claude Code version: 2.1.6
- OS: macOS
5 Comments
Could this be due to the Autocompact buffer? I.e. the
remainingreported is correct in terms of the total unused context (100 - 100 * used / 200k), but the warning is showing percent until auto-compact (100 - 100 * used / (200k - 33k)in my case), not until the context is completely "full"?<img width="499" height="219" alt="Image" src="https://github.com/user-attachments/assets/3bb76ab0-fbb7-455c-a7d6-48c77852dd43" />
If this is the case, the solution could be:
autocompact_buffertokens value, and/oravailable_percentagevsremaining_percentageI keep being bitten by that issue. Would be really nice to have clarity, and ideally a fix :)
Definitely not ideal. Keeps happening to me too. Would love a fix.
Root Cause Analysis: The Three-Source Discrepancy
I've reverse-engineered the context calculation from
cli.js(v2.1.7, verified through v2.1.91) and can confirm the exact mechanics behind the ~19% discrepancy reported here. It's actually larger than 19% in practice — I've measured up to 48 percentage points of divergence.The Three Calculations
| Source | What It Counts | Denominator | Includes System Overhead | Includes Output Tokens |
|--------|---------------|-------------|------------------------|----------------------|
| Statusline
used_percentage| Per-conversation input tokens | 200,000 | No (~38K excluded) | No ||
/contextcommand | Per-conversation input tokens | 200,000 | No | No || Internal warning/auto-compact | Input + output tokens | ~123,000 (200K - buffers) | Yes | Yes |
Source Code Evidence
Statusline calculation — INPUT only:
Warning/auto-compact calculation — INPUT + OUTPUT against a lower effective window:
Why the Gap Is ~48 Percentage Points
| Component | Tokens | % of 200K |
|-----------|--------|-----------|
| System overhead (prompt, tools, CLAUDE.md, MCP) | ~38,000 | 19% |
| Output token buffer | ~64,000 | 32% |
| Auto-compact reserve | ~13,000 | 6.5% |
| Total invisible to statusline | ~115,000 | ~48% |
In output-heavy sessions (code generation), the warning fires while the statusline shows ~52% used. The statusline is technically correct about input conversation tokens but meaningless for predicting when context will actually fill.
Proposed Fix
Expose in statusline JSON:
This would let statusline scripts display the same number the internal warning uses, eliminating the discrepancy entirely.
Cross-References
This consolidates findings from:
used_percentagegetEffectiveWindow()returns 200K instead of 1M on extended contextThe three-source divergence documented in this thread is the reason a measured number off the JSONL is more trustworthy than any single statusline figure — the transcript records actual per-turn input/output/cache usage, so you can compute "real" consumption directly instead of reconciling three formulas. If it's useful while this gets fixed, cozempic does exactly that read-only:
cozempic diagnose <session-id>(viauvx cozempic) prints measured token usage from the session file. It won't change CC's displayed %, but it gives you a ground-truth number to compare against.