Statusline JSON: expose /context's conceptual token count (Messages-sum), not just API-billed used_percentage
Preflight Checklist
- [x] I have searched existing requests and this feature hasn't been requested yet
- [x] This is a single feature request (not multiple features)
Problem Statement
After /compact, the context_window.used_percentage field in the statusline JSON and the "Free space" row in /context disagree
by ~14 percentage points for roughly the prompt-cache TTL (~5 minutes). Third-party statuslines that render free space based
on the documented formula cannot match what /context shows, because the underlying conceptual-token number isn't exposed.
Please add a field to context_window (or context_window.current_usage) that reflects the conceptual post-compact token count —
the same number /context uses to compute its "Free space" row from the category breakdown (System + Tools + MCP + Memory +
Messages + …).
Why the current fields are insufficient
The documented formula for used_percentage is:
used_percentage = (input_tokens + cache_creation_input_tokens + cache_read_input_tokens) / context_window_size
This tracks API billing. After /compact, cache_read_input_tokens still contains the pre-compact prefix (~25 k tokens on a 200
k window) until the prompt cache ages out or subsequent calls overwrite it. So used_percentage is inflated relative to the
conversation's actual conceptual size.
/context itself computes "Free space" from the category breakdown sum, not from used_percentage. You can see this in a
post-compact session: the /context header percentage and the per-category sum don't match each other. For example, in one of
my sessions:
- /context header: 96.6 k used (48 %) — from used_percentage
- /context category sum: 72.8 k (System 6.2 k + Tools 8 k + Memory 0.994 k + Skills 2.9 k + Messages 54.7 k)
- "Free space: 94.2 k (47.1 %)" — derived from the category sum
- Gap: 23.8 k tokens of stale prompt-cache prefix
A statusline built on the documented contract will render "35 % free" while /context reports "49 % free" — a 14 pp gap that
looks like a bug to users but is actually faithful to the JSON.
What I've already ruled out
- total_input_tokens is not a reliable proxy. In a compacted session it happened to match Messages (53 292 vs 54 700, 1.03×),
but on a fresh session it was 1.59× the Messages number (89 140 vs 141 800). It's tracking something else.
- The discrepancy isn't a rounding error — it's systematically ~14 pp on a 200 k window until the cache turns over.
- This isn't fixable in the statusline binary; the field simply isn't in the JSON.
Proposed Solution
Add one of:
- context_window.conceptual_used_tokens — same number /context's category-sum uses. Third-party statuslines can compute
free_pct = 100 − conceptual_used_tokens / context_window_size × 100 − autocompact_pct and match /context exactly.
- context_window.conceptual_used_percentage — pre-computed, equivalent.
- context_window.breakdown — the full category map ({system, tools, mcp, memory, messages, …}) that /context renders. Bonus:
lets statuslines surface category-specific warnings ("Tools section is eating 40 % of your window").
Option 3 is the richest; option 1 is the smallest change and solves the reported bug.
Repro
- Run a Claude Code session until it has meaningful content (~50 % used).
- Run /compact.
- Within ~5 minutes, compare the statusline's rendered free space against /context's "Free space" row.
- Expected: they agree. Actual: statusline is ~14 pp lower.
Context
I maintain a native C statusline (ShayanNasiri/claude-modern-status-bar) that implements the documented contract precisely. The formula is correct, the rendering is correct, the JSON input is faithful to the docs — but the number doesn't match /context because the JSON itself doesn't carry the conceptual count. This would fix it for every third-party statusline, not just mine.
Alternative Solutions
_No response_
Priority
Medium - Would be very helpful
Feature Category
Configuration and settings
Use Case Example
_No response_
Additional Context
_No response_
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗