[BUG] context_window metrics not updated after /compact until next API interaction

Status Closed — not planned
Reported on v2.1.14
Maintainer reply None cached
Activity 11 comments · opened Jan 21, 2026 · closed Apr 29, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

After running /compact, the context_window object in the status line JSON retains pre-compaction values until the next API interaction. This affects any status line configuration that displays context usage.

What Should Happen?

After /compact completes, the context_window metrics should immediately reflect the new (reduced) context state.

Steps to Reproduce

  1. Have a conversation with some context built up
  2. Run /compact
  3. Observe: context_window.used_percentage still shows pre-compaction value
  4. Send any message
  5. Observe: value now reflects actual post-compaction state

Claude Model

Opus

Is this a regression?

I don't know

Claude Code Version

2.1.14 (Claude Code)

Platform

Anthropic API

Operating System

macOS

Terminal/Shell

Terminal.app (macOS)

Additional Information

Entire context_window object is stale after /compact, not just used_percentage. Manual calculation from cache_read_input_tokens + input_tokens shows the same stale behavior—confirming the issue is that the context_window object isn't refreshed after compaction until the next API round-trip.

View original on GitHub ↗

11 Comments

github-actions[bot] · 7 months ago

Found 3 possible duplicate issues:

  1. https://github.com/anthropics/claude-code/issues/17624
  2. https://github.com/anthropics/claude-code/issues/15008
  3. https://github.com/anthropics/claude-code/issues/14303

This issue will be automatically closed as a duplicate in 3 days.

  • If your issue is a duplicate, please close it and 👍 the existing issue instead
  • To prevent auto-closure, add a comment or 👎 this comment

🤖 Generated with Claude Code

villeodell · 7 months ago

As far as I can tell there is no duplicate issue for this that is current and open.

  1. This issue is a duplicate of #15008, but 15008 was closed by the submitter as a duplicate of #13765 and is now locked.
  2. 13765 original issue was about "/clear" not "/compact" -- the submitter of 15008 added a comment to 13765 to note that the same issue impacted "/compact" also
  3. 13765 was later closed as "completed" and is now locked.
  4. It appears the issue was fixed for "/clear" but the issue persists for "/compact"

For that reason, and because the other issues are closed and locked, this issue could serve to track the issue that still exists today for "/compact" as described or 15008 could be unlocked and reopened.

YoanWai · 7 months ago

Confirming this issue on Linux (WSL2) with a custom statusline hook.

My setup:

  • Custom statusLine command in settings.json that reads context_window.remaining_percentage from stdin
  • - The statusline script displays a visual progress bar of context usage

Observed behavior:
After running /compact or /clear, the context_window data passed to my statusline hook is stale. The context bar continues showing the old percentage until I send the next message.

Expected behavior:
The statusline hook should receive refreshed context_window data immediately after /compact or /clear completes.

This affects any custom statusline that displays context usage - the data Claude Code provides via stdin isn't updated after these commands.

NubeBuster · 6 months ago

/not-stale /pls-do-not-close-bot-overlord

NubeBuster · 6 months ago

/add-platform linux

JayBarratt · 5 months ago

Hitting the same issue — custom statusline shows stale context_window.used_percentage after /compact until the next user prompt.

Additional solution proposal (from #30783): A PostCompact hook event would cleanly solve this. Currently only PreCompact exists and fires before compaction with no context data. A PostCompact hook firing after compaction with the updated context_window object would let users trigger a statusline cache update (or any other post-compaction logic):

{
  "hook_event_name": "PostCompact",
  "trigger": "manual | auto",
  "context_window": {
    "used_percentage": 18,
    "used_tokens": 12000,
    "available_tokens": 54000
  }
}

Alternatively, simply triggering one additional statusline invocation after compaction completes (before waiting for the next prompt) would also fix it.

Closing #30783 as duplicate in favour of this issue.

NubeBuster · 5 months ago

Just checked, .jsonl file only contains a preTokens line and nothing else.

{
   "parentUuid":null,
   "logicalParentUuid":"",
   "isSidechain":false,
   "userType":"external",
   "cwd":"",
   "sessionId":"",
   "version":"2.1.68",
   "gitBranch":"main",
   "slug":"luminous-percolating-pretzel",
   "type":"system",
   "subtype":"compact_boundary",
   "content":"Conversation compacted",
   "isMeta":false,
   "timestamp":"2026-03-04T23:23:35.173Z",
   "uuid":"",
   "level":"info",
   "compactMetadata":{
      "trigger":"manual",
      "preTokens":24219
   }
}

This at best allows for carefully and error-pronely reconstructing the approximate context window size by summing known overhead values and one of the subsequent jsonl lines message.content's tokens.

TL;DR jsonl also doesn't contain the new context window size.

JayBarratt · 5 months ago

Update — behavior not observed in recent testing

Tested on Windows 10, Claude Code 2.1.63, Max plan.

I ran an A/B comparison: logged both used_percentage and a manual calculation from current_usage raw token counts (input + cache creation + cache read, divided by context window size) across 48 statusline renders, including a compaction boundary. Both values were identical in every entryused_percentage dropped correctly on the first post-/compact API call.

To verify yourself, add this to a statusline script to log both values side by side:

used_pct = ctx_window.get("used_percentage")
current = ctx_window.get("current_usage")
if current and max_tokens:
    calc = round((current["input_tokens"] + current["cache_creation_input_tokens"]
                  + current["cache_read_input_tokens"]) / max_tokens * 100)
    with open("statusline-debug.log", "a") as f:
        f.write(f"used_percentage={used_pct} | calculated={calc}\n")

The perceived "stale percentage" after /compact appears to be architectural: the statusline re-executes at turn boundaries (after each assistant message), and /compact doesn't seem to trigger one. The displayed value updates on the next message you send — typically seconds later.

This may indicate the original issue was addressed in a recent release, or that it only manifests under specific conditions I didn't reproduce.

@NubeBuster's point about missing postTokens in the JSONL compact_boundary entry remains valid and would be useful for any tooling that analyses transcripts directly.

SDpower · 5 months ago

I've done extensive analysis on this exact problem. Using ccusage_go (open-source Claude Code usage tracker), I found that Cache Read tokens consumed 97.7% of my session costs — API actual cost was $1.47, total billed cost was $64.98 (a 44x markup). Cache also degrades instruction following in long sessions, which I documented with per-turn JSONL analysis.
Full write-up with data, community issue references, and Claude Code's own self-analysis report:
https://blog.sd.idv.tw/en/posts/2026-03-25_claude-code-cache-trap/
Tool: https://github.com/SDpower/ccusage_go

github-actions[bot] · 4 months ago

Closing for now — inactive for too long. Please open a new issue if this is still relevant.

github-actions[bot] · 3 months ago

This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.