Skip to content

Fix Claude usage scrape: tmux window too small, and new trust prompt defaults to "No" - #254

Open
herlocke wants to merge 1 commit into
marcus:mainfrom
herlocke:fix/tmux-usage-scrape
Open

herlocke wants to merge 1 commit into
marcus:mainfrom
herlocke:fix/tmux-usage-scrape

Conversation

@herlocke

Copy link
Copy Markdown

Summary

nightshift reads Claude's usage percentage by starting claude in a hidden tmux session, typing /usage, and reading the screen. With current Claude Code, every one of these reads timed out. As a result, budget snapshots only ever used local token counts, and calibration never got any data. This PR fixes the two causes: the tmux window was too small to show the usage figure, and a changed trust prompt defaulted to "No, exit".

The two bugs

1. The tmux pane stayed at 80×24 (internal/tmux/tmux.go)

Start ran tmux new-session -d and then resize-pane -x 120 -y 40. A pane can't grow bigger than its window, and a detached session's window defaults to 80×24, so the resize did nothing. At 80×24, /usage is cut off before the "Current week (all models)" line that the scraper waits for, so WaitForPattern timed out.

The fix passes the size to new-session with -x/-y, so the window is created at 120×40.

2. The folder-trust prompt changed (internal/tmux/scraper.go)

When claude starts in a folder it hasn't seen before, it asks whether to trust that folder. Claude Code v2.1.273 changed this prompt to "Quick safety check … one you trust?", with the cursor starting on "No, exit". nightshift only recognised the old wording ("Do you trust") and pressed Enter, which picked whatever option was selected.

The fix:

  • claudeTrustPromptKeys recognises both wordings and works out where the cursor is relative to the "Yes" option.
  • acceptClaudeTrustPrompt moves the cursor to "Yes". It then reads the screen again and presses Enter only once "Yes" is actually selected. It never presses Enter while "No" is selected.

Why it checks the screen before pressing Enter. My first version sent Down then Enter straight away. It passed the unit tests but failed in real use. Keys sent right after the prompt appears are sometimes dropped. When Down was dropped and Enter wasn't, Claude exited. A fixed delay could still lose that race, so the code checks that "Yes" is selected first.

Something to consider

nightshift already accepted the trust prompt automatically, and this PR keeps that behaviour. It means every folder nightshift scrapes from ends up marked as trusted in ~/.claude.json. Running the scrape from one dedicated folder would avoid that. I left it for a separate change.

Testing

  • New table-driven tests in internal/tmux/tmux_test.go cover:
    • the new-session arguments. This test fails on the old code.
    • reading the prompt: old and new wording, colour codes in the output, and the cursor above or below "Yes"
    • accepting the prompt when a keypress is dropped, when the cursor never moves, and when there's no "Yes" option
  • go test ./..., go vet and gofmt are clean.
  • Manual check: nightshift budget snapshot -p claude succeeded in an already-trusted project and in three new untrusted folders. The unpatched binary timed out in every case.
  • Two weeks of real use: I've run this build as my scheduled daemon since 2026-09-16.
    • Before the fix (2026-09-15), 0 of 28 Claude usage snapshots got a reading.
    • From 2026-09-17 to 2026-09-30, 579 of 581 did.

🤖 Generated with Claude Code

Two bugs made every Claude usage scrape time out, leaving snapshots
local-only so budget calibration never ran:

- Session size was applied with resize-pane after a detached
  new-session. A lone pane cannot grow past its window (80x24), so
  /usage rendered cut off and "Current week" never appeared. Pass
  -x/-y to new-session instead.
- The trust prompt now reads "Quick safety check ... one you trust"
  with the cursor on "No, exit", so the "Do you trust" match missed it
  and Enter would exit. Detect both wordings, move the cursor to "Yes",
  and re-read the pane before confirming, since keys sent right after
  the prompt renders can be dropped. Never confirm while "No" is
  selected.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant