One prompt. It builds a thing that watches how much Claude you've used and texts you before you run out, not after.
If it says the token is dead: open Terminal, run claude login, and tell it to try again. That's the one thing it can't fix on its own.
Build me a Claude usage watchdog on this Mac. I'm running Cowork locally, Claude Code is installed, and I'm logged in. Work in ~/claude-budget (create it). Do all shell work yourself and verify each piece by running it before you tell me it works.
PART 1 — the meter reader (usage-probe.sh)
There IS a programmatic read of my usage percentages; don't build around the assumption that there isn't. The CLI's /usage screen calls GET https://api.anthropic.com/api/oauth/usage with headers "Authorization: Bearer <token>" and "anthropic-beta: oauth-2025-04-20". The token is the Claude Code OAuth credential in my login keychain: service "Claude Code-credentials", account = my macOS short username (confirm with: security find-generic-password -s "Claude Code-credentials" | grep acct). The keychain value is JSON with claudeAiOauth.accessToken, .refreshToken and .expiresAt (ms).
Write a script that reads it and prints ONE parseable line, e.g.:
session=30%(resets Sat-19:29) weekly=34%(resets Fri-23:59) weekly_fable=18%
From the payload: five_hour = the 5-hour rolling window, seven_day = the weekly cap (this is the one that matters), limits[] entries with kind "weekly_scoped" = per-model weekly caps, extra_usage = overage dollars vs monthly cap (only print it if is_enabled is true). Support a --json flag that dumps the raw payload.
Make it self-heal an expired token: if the access token is expired or the API returns 401/403, POST {"grant_type":"refresh_token","refresh_token":<rt>,"client_id":"9d1c250a-e61b-44d9-88ed-5944d1962f5e"} to https://platform.claude.com/v1/oauth/token, then write the new credential back into the SAME keychain service+account with `security add-generic-password -U` after backing up the old value to a 0600 file. Exit codes: 0 ok, 2 no token, 3 network, 4 auth dead (means I need to run `claude login` in Terminal).
Hard rule, no exceptions: never print, log, echo, or transmit the token itself. Not in output, not in a debug line, not in a file you show me.
This costs zero usage — it's a metadata read, not a model call.
PART 2 — the log
Each run, append "<ISO timestamp> <that line>" to ~/claude-budget/.usage-log, and read the previous line so you can compare against it. One line per run, so there's a trend and not just a snapshot.
PART 3 — the burn breakdown
Use ccusage, but invoke it correctly. A bare `ccusage daily` only reads ~/.claude and is therefore blind to Cowork and desktop chat, which is where most of the burn actually is. ccusage reads $CLAUDE_CONFIG_DIR, which takes a COMMA-SEPARATED list of roots. So:
cfg="$HOME/.claude"; base="$HOME/Library/Application Support/Claude/local-agent-mode-sessions"
for d in "$base"/*/*/*/.claude; do cfg="$cfg,$d"; done
CLAUDE_CONFIG_DIR="$cfg" npx -y ccusage@latest daily --since $(date -v-7d +%Y%m%d) --json
Compare today and yesterday against the trailing 7-day average of totalTokens. Also: `ccusage session --since` is a trap — it picks which sessions to show by date but reports each one's FULL LIFETIME cost, which overstates a single day by ~2.5x. Don't use it for per-day numbers.
PART 4 — when to speak
Silence is the correct output. On a normal run, post nothing, write nothing but the log line, and exit. Alert me ONLY if:
- session >= 80%, or it jumped >= 30 points since the last check
- weekly >= 80% at any time, or >= 60% with more than a day left before it resets
- extra usage (if enabled at all) >= 80% of the monthly cap, or grew >= $15 since last check
- today's burn is more than 2x the trailing 7-day average
Alerts go to me as an iMessage, and they have to be short enough to read on a phone. Never send a bare percentage — always pair it with the reset time, because a number with no deadline is useless. "Weekly 82%, resets tonight" and "weekly 82%, resets Friday" are completely different situations. Lead with the number plus when it resets, then the single most useful thing I could do about it.
Then set it up as a scheduled task that runs twice a day, around 9am and 6pm.
PART 5 — what NOT to build
Do not build a pace or projection layer — no "at this rate you'll cross 100% by Monday", no burst-rate detection, no hysteresis state file. Thresholds only. If I want the trend version later I'll ask for it.
Never disable or pause anything to save usage. This alerts; it does not act. If a reading looks bad, tell me and change nothing.
Finally: check whether extra usage is enabled on my account (extra_usage.is_enabled in the payload) and tell me. If it's false there's no overage cushion, which means hitting 100% weekly is a hard stop until reset, not a slide into billing — and that makes every threshold above more expensive to miss.