A macOS desktop widget that shows your Claude Code usage as a GitHub-style contribution grid with real-time rate limit bars.
git clone https://github.com/emmettarmstrong/usage-widget.git
cd usage-widget
make installThis builds the app and copies it to /Applications. Launch UsageWidget.app — the contribution grid works immediately if you use Claude Code.
- Contribution grid — 16-week heatmap of daily message activity (Mon-Fri), colored by intensity
- Rate limit bars — Vertical bars showing 5-hour and 7-day API utilization, filled from bottom
- Live updates — Stats refresh every 30s from local logs, API data every 60s
- Hover tooltips — Hover any cell to see day, date, and message count; hover a bar to see utilization % and reset time
- Today indicator — Current day cell has a white border
- Future days — Remaining weekdays in the current week show as dimmed cells
- Desktop overlay — Floats above the desktop, draggable, persists position across launches
- Menu bar icon — Refresh data or quit from the menu bar
- macOS 15.0+ (Sequoia)
- Xcode 16.0+ (with command line tools)
- An active Claude Code installation (
~/.claude/directory)
The contribution grid reads from two local sources — no API key or login needed:
~/.claude/stats-cache.json— Historical daily message counts, generated by Claude Code automatically~/.claude/projects/*/*.jsonl— Live session transcript files, scanned for today's activity
If you use Claude Code, these files already exist.
The rate limit bars fetch data from the Anthropic API using your Claude Code OAuth token. This token is stored in the macOS Keychain by Claude Code when you log in — the widget reads it automatically.
- Keychain service:
Claude Code-credentials - The widget reads the token via
/usr/bin/securityCLI (no Apple Developer account needed) - If the token isn't found (e.g. you haven't logged into Claude Code), the bars simply won't appear
Your plan tier (Free, Pro, Max, Max 5x, Max 20x) is read from ~/.claude/.credentials.json and displayed on hover.
The app ships with the bundle ID com.emmett.UsageWidget. If you want your own (e.g. for Keychain isolation or multiple installs), change it in one command:
make setup BUNDLE_ID=com.yourname.UsageWidgetThis updates all 3 locations where the bundle ID appears (project.pbxproj Debug + Release configs, and the entitlements file).
make build # Build Release .app to build/Build/Products/Release/
make install # Build + copy to /Applications
make uninstall # Remove from /Applications
make clean # Remove build/ directoryThe Makefile uses ad-hoc code signing (CODE_SIGN_IDENTITY="-"), so no Apple Developer account is required. The app uses the /usr/bin/security CLI to read the Keychain, which works without entitlements-based code signing.
Add UsageWidget.app to System Settings > General > Login Items to start it automatically.
If you're using Claude Code to set up this widget, paste this prompt:
Clone and install the Claude Code Usage Widget. Read the CLAUDE.md for build commands and project structure. Run
make installto build and install to /Applications, then launch the app. If my bundle ID needs to change, usemake setup BUNDLE_ID=com.myname.UsageWidgetfirst.
The widget is entirely hover-driven — no labels clutter the display.
| Element | What it shows | On hover |
|---|---|---|
| Grid cell | Daily activity intensity | Day name, date, message count |
| White-bordered cell | Today | Same as above |
| Dimmed cells | Future days this week | Day name, date |
| Left bar | 5-hour rolling utilization | Percentage + time until reset |
| Right bar | 7-day rolling utilization | Percentage + time until reset |
| Color | Messages |
|---|---|
| Dark (#1D1816) | 0 |
| Dim (#4A2A1A) | 1-50 |
| Medium (#8B4A25) | 51-300 |
| Bright (#C15F3C) | 301-1000 |
| Brightest (#DA7756) | 1000+ |
| Color | Utilization |
|---|---|
| Orange (#DA7756) | 0-49% |
| Yellow (#E8A84C) | 50-74% |
| Deep orange (#E07030) | 75-89% |
| Red (#CC3333) | 90%+ |
The bars require a valid OAuth token in the macOS Keychain. This is set automatically when you log into Claude Code.
- Make sure you're logged into Claude Code (
claudein terminal — if it opens, you're logged in) - Check the Keychain has the credential:
security find-generic-password -s "Claude Code-credentials" 2>&1 | head -5 - If nothing shows up, log out and back in to Claude Code
- The widget refreshes local stats every 30 seconds and API data every 60 seconds
- If the grid shows stale data, click the menu bar icon (chart icon) and select Refresh
- If the app appears frozen after sleep, quit and relaunch — App Nap prevention is built in but macOS can still suspend in rare cases
- "No such module": Make sure you're building the
UsageWidgetscheme, not a test target - Code signing errors: The Makefile uses ad-hoc signing. If building in Xcode directly, set signing to "Sign to Run Locally" in Build Settings
- Deployment target: Requires macOS 15.0+ (Sequoia). Check your macOS version with
sw_vers
The first time the app reads from the Keychain, macOS may show a permission dialog. Click Allow (or Always Allow to suppress future prompts).
UsageWidget/
├── App/
│ ├── AppDelegate.swift # Window panel, menu bar, position persistence
│ └── UsageWidgetApp.swift # App entry point
├── Models/
│ ├── ContributionDay.swift # Day data model + intensity levels
│ └── StatsCache.swift # JSON decode for stats-cache.json
├── ViewModels/
│ └── StatsViewModel.swift # Data loading, grid building, API polling
├── Views/
│ ├── ContentView.swift # Root layout (grid + bars)
│ ├── ContributionGraphView.swift # Grid of cells
│ ├── ContributionCellView.swift # Individual cell with hover
│ └── UsageLimitBarView.swift # Vertical rate limit bars
└── Utilities/
├── FileWatcher.swift # DispatchSource file monitor
├── LiveStatsComputer.swift # Parses JSONL conversation logs
└── UsageAPIClient.swift # Anthropic API usage endpoint
