[FEATURE] Expose a session's context window and cost to local tools when the session has no status line (VS Code extension, SDK)
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
I'm building a menu-bar monitor for macOS to track my Claude Code sessions: which ones are waiting on my input, how full each context is, and what each has cost so far. Terminal sessions already provide all of that through documented integration points. The statusLine command receives context_window.context_window_size, context_window.total_input_tokens and cost.total_cost_usd on each render, and the hooks tell me when a session wants attention. That architecture fits: it runs locally, it is opt-in, and no credential is involved anywhere.
Sessions launched through the VS Code extension lack all of it. The extension executes the CLI headless (--output-format stream-json --input-format stream-json, CLAUDE_CODE_ENTRYPOINT=claude-vscode), so there is no terminal UI and the status line never renders. The metrics are present: the result events flowing through the pipe contain total_cost_usd and modelUsage[<model>].contextWindow. They remain trapped in the channel linking the extension to its binary.
Searching for another on-device source yields nothing:
~/.claude/sessions/<pid>.jsonrecords the session along with itscwdandentrypoint, plus (for a terminal session) astatusthat refreshes as the session works. It omits the window, the token count and the cost. Extension-hosted sessions never populatestatusthere at all.- The JSONL transcript embeds per-message
usage, so a tool can sum tokens and approximate the cost from a rate table; it does not record which window the session runs in. Once the token count exceeds 200K the window must be 1M; under that threshold a 200K session and a 1M session are indistinguishable on disk, and a guess misreports usage fivefold in either direction. - Hook inputs carry none of these fields; the documentation and the changelog both confirm it.
- The cross-session messaging socket functions solely as an inbox for delivering prompts to a session (an auth frame followed by a
usermessage). It has no query frame, so extracting anything through it means injecting a prompt into the user's live conversation. - The model cannot self-report them: the window is a runtime setting it is never told, and the cost derives from API usage fields it never sees.
Consequently a monitor today shows "window unknown, cost estimated" for every extension-hosted session, whatever the user has configured.
Proposed Solution
Write the figures into ~/.claude/sessions/<pid>.json. The file already exists, is rewritten on state changes, and is the logical destination; append contextWindowSize, contextTokens (the same total_input_tokens the status line gets) and totalCostUSD, refreshed whenever status is. Extension-hosted sessions ought to keep status current there as well. Usage figures only, nothing sensitive, and every local tool that already reads the file benefits at once.
It is one write the process already performs, and it removes the need for any tool to interpret transcripts or guess windows.
Alternative Solutions
Either of these would also close it, at a higher cost:
- Run the
statusLinecommand from the extension. Even with nowhere to display the output, invoking the user's configured command with the same payload the TUI sends would make the existing extension point cover every host. Gate it on the setting being present. - Add a read-only
statusframe to the peer messaging protocol, answered with the same payload the status line receives. Heavier, and it turns the inbox into a query surface; included for completeness.
Current workaround: past 200K tokens the monitor deduces a 1M window from the token count and marks it as deduced; the cost stays an estimate from a rate table over the transcript.
Priority
Medium - Would be very helpful
Feature Category
Developer tools/SDK
Use Case Example
- I open a long session from the VS Code extension and a few terminal sessions alongside it.
- The monitor shows each terminal session's context percentage and Claude Code's own cost figure, read from the status-line payload.
- For the extension session it can only show a token count with "window unknown" and a tilde cost, although the extension's own UI displays both.
- With the session file carrying the figures, every session reads the same way, from one documented file, with no guessing.
Additional Context
- Claude Code 2.1.263, macOS 26, VS Code extension
anthropic.claude-code-2.1.263-darwin-arm64. - Reproduce: launch a session via the extension, then look for its id under any
statusLinecapture and inside~/.claude/sessions/<pid>.json; the disk stays silent on the window and the cost while the extension's own UI displays both. - I also maintain claude-statusline, a two-line status line for Claude Code with context and rate-limit bars. Its users on the VS Code extension see nothing, since the command never runs there. The session-file proposal serves monitors; running the command from the extension would serve status-line tools like it. Either helps, both would be ideal.
- Related: #77829 asks for the configured
statusLineto be rendered in the extension panel; if that ran the command with the TUI payload it would also cover this (my first alternative). On 2.1.263 my configured command did not run for an extension-hosted session (a day-long session, 840K tokens, wrote no capture), so I'm not treating it as covered. #11008 asks for the same figures on the hook side; this is the on-disk counterpart, for tools that observe sessions without hooking into them.
3 Comments
You can pull context-window numbers from the project JSONL and skip the status line. One warning: don't date or order sessions by file mtime; one sync rewrites them all. On one machine, 21 sessions, 15 rows moved once I read the last timestamp in each log. Own tooling.
Thanks; the mtime point is real and I've fixed it. One addition for anyone else doing the same: don't take the last line's timestamp, since several record types carry none (
mode,bridge-session,last-prompt,file-history-snapshot) and the final line is usually one of those; take the newest stamp across all lines.The first half doesn't hold, though. The JSONL has token counts, not the window size; I grepped recent transcripts for
context_window,window_sizeandcontext_limitand there's nothing there.usagetells you what a turn spent, never whether the session runs at 200K or 1M, so atokens > 200Kheuristic can only promote a session after it crosses 200K; below that a 1M session still reads ~5× too high. Which is what this request is about.You're right on the window size: the JSONL records usage, not the limit. I should have said usage, not window. You're also right that the last line may not have a timestamp. My script uses the newest timestamped assistant record, but doesn't check other record types. Thanks for fixing the mtime issue.