Skip to content

Latest commit

 

History

12 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Claude Usage icon — a tachometer with Claude-style rays

Claude Usage — macOS Desktop Widget

A native WidgetKit desktop widget showing your claude.ai plan usage and today's token spend, straight on your Mac desktop.

Unofficial project. Not affiliated with or endorsed by Anthropic. It reads the credentials your local Claude Code installation already maintains and talks only to api.anthropic.com (your plan usage) and status.claude.com (Claude's public service status).

Leia em português.

What it shows

Small and medium widgets on the desktop showing session and weekly usage bars, reset countdowns and today's token cost Menu bar panel with session and weekly gauges, reset countdowns, today's token cost and Refresh/Quit buttons, opened from a speedometer icon showing 20% in the menu bar

  • Session (5h) and weekly plan limits — the same percentages /usage shows in Claude Code, with live-updating reset countdowns.
  • Per-model weekly limits — Opus, Sonnet, Fable, whatever your plan scopes. Rows come from the weekly_scoped entries of the response's limits array, which carry the model's display name, with the top-level seven_day_<model> keys as a fallback for plans that populate those instead. Neither is a hardcoded model list, so a model your subscription gains later shows up without a code change.
  • Claude service status — polls status.claude.com and reports degraded performance, outages and maintenance. The menu bar icon turns orange (degraded/maintenance) or red (outage), the widget gets a status badge, and the panel names the open incident and the affected components — click it to open the status page.
  • Optional alert — a native notification when Claude's status changes level (and when it recovers). Toggle it in the menu bar panel; it only fires on real transitions, never on the first reading.
  • Today — tokens and estimated cost (USD), computed locally from Claude Code's JSONL transcripts in ~/.claude/projects.
  • A ⚠️ stale badge when data is older than 20 minutes (app not running, network down, token expired).
  • Menu bar too: the agent app shows a speedometer with the current session % in the menu bar; click it for a panel with every gauge, reset countdowns, today's spend, the service status and a refresh button.
  • Localized: English, Português (BR), Español, Français, Deutsch, 日本語, 简体中文 — follows your system language (translations live in Shared/Localizable.xcstrings; PRs adding languages are welcome).

How it works

ClaudeUsage.app (LSUIElement agent, non-sandboxed, login item)   ClaudeUsageWidget.appex (sandboxed)
  every ~5 min (NSBackgroundActivityScheduler):                    TimelineProvider:
  1. read Claude Code's OAuth token from the login Keychain          reads snapshot.json from the
  2. GET https://api.anthropic.com/api/oauth/usage        ──────▶    App Group container and renders
  3. GET https://status.claude.com/api/v2/summary.json     App       systemSmall / systemMedium views
  4. scan today's JSONL transcripts (dedup + pricing)     Group
  5. write snapshot.json atomically                     container
  6. notify if the service status changed level
  7. WidgetCenter reload (only when something changed)

Steps 2 and 3 fail independently: a status-page outage never blocks your usage numbers, and an expired token never hides the service status. Whichever one fails keeps its last known values and goes stale on its own.

The widget extension is sandboxed (WidgetKit requires it), so the containing app does all the work and the widget only renders a cached snapshot.

Security notes

  • The OAuth access token never leaves your machine except to api.anthropic.com (the official usage endpoint).
  • The refresh token is never used — refreshing would rotate it and log Claude Code out. The app only re-reads whatever token Claude Code maintains.
  • The status request to status.claude.com is unauthenticated and carries nothing about you — no token, no account, no usage data. It's the same public JSON the status page itself renders.
  • Nothing else is collected, stored, or transmitted.

Requirements

  • macOS 15+ (built and tested on macOS 26)
  • Full Xcode (from the App Store) with any Apple ID added in Xcode → Settings → Accounts (a free Personal Team is enough)
  • XcodeGen: brew install xcodegen
  • Claude Code installed and logged in (it is the source of both the token and the transcripts)

Install

git clone https://github.com/ohenriquet/claude-usage-widget.git
cd claude-usage-widget
./build.sh        # detects your Team ID, generates the project, builds, signs, installs to /Applications

On first launch macOS asks for Keychain access → click Always Allow. Then right-click the desktop → Edit Widgets → search for "Claude" and drag the small or medium widget out.

build.sh options: TEAM_ID=XXXXXXXXXX ./build.sh to set the signing team explicitly.

Troubleshooting

  • Widget missing from the gallery — make sure exactly one copy of the app exists (in /Applications), launch it once, then killall NotificationCenter chronod. Last resort: log out/in.
  • Keychain prompt reappears — normal when Claude Code recreates its credentials item (some token refreshes/logins). One click fixes it.
  • Numbers differ slightly from ccusage — token dedup keeps the entry with the highest output_tokens per message.id + requestId; <synthetic> entries are skipped; per-line costUSD is preferred when present.
  • Persistent 429 — the fetch sends a claude-code User-Agent and polls every 5 minutes; if you still hit it, the widget keeps showing the last good snapshot with the stale badge.
  • No status notifications — macOS asks for permission on first launch; if you dismissed it, enable Claude Usage under System Settings → Notifications. The checkbox in the panel only controls whether the app posts them.
  • No per-model rows at all — your plan's usage response has no weekly_scoped limits and no populated seven_day_<model> buckets. Note the seven_day_* keys come back null on at least some plans even when the model is in use, which is why limits is read first.
  • Testing the status alert — the colored menu bar icon is hard to see on a good day, so you can force a level: defaults write com.henrique.claudeusage debugStatusLevel major (levels: operational, maintenance, minor, major, critical), then defaults delete com.henrique.claudeusage debugStatusLevel to go back. The override skips the network call and labels the incident as locally forced, so it can't be mistaken for a real one.
  • Status says "Status unavailable" — the app hasn't reached status.claude.com yet (first run, no network, or the status page itself is down). Usage numbers are unaffected.

Regenerating the icon

The icon (a sports-car tachometer with Claude-style rays) is a single SVG:

brew install librsvg
cd Assets && mkdir -p AppIcon.iconset
# render each size from icon.svg, then:
iconutil -c icns AppIcon.iconset -o ../App/AppIcon.icns

License

MIT

About

macOS desktop widget (WidgetKit) showing your claude.ai plan usage and today's token spend

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages