AI-usage lives in your macOS menu bar and shows the current session (5h) and
weekly (7d) Claude limit utilization, plus when each window resets — using
the same official data source as Claude Code's /usage, with no log scraping.
menu bar: ◔ 27% / 18%
└ session% / weekly%, with a colored gauge for the session
dropdown: Session (5h) 27% resets 23:09
Weekly (7d) 18% resets Jun 4
─────────────
Quit
- Session + weekly utilization with reset times, read straight from the
official OAuth usage endpoint (the one
/usageuses). - Colored session gauge in the bar — a small pie tinted green → red by level.
- Refreshes the moment it matters: on each conversation turn (watches
~/.claude/projects), when you open the menu, at each limit reset boundary, and on a 60s heartbeat. - Automatic token refresh — refreshes the OAuth token via its refresh-token when it expires and writes it back, so it keeps working even after Claude Code has been idle.
- Native & light — pure AppKit via
objc2, no Electron/web runtime. Real memory footprint ~17 MB (the AppKit baseline), stable, ~0% idle CPU. - Launch at login, no Dock icon (menu bar agent).
- Extensible — a single
Providertrait is the extension point for future sources (Anthropic API usage, Codex, …).
- macOS 11+ (Apple Silicon or Intel)
- Rust ≥ 1.85 (dependencies use edition 2024)
- Logged in to Claude Code (the app reads its OAuth token from the Keychain)
git clone <your-fork-url> AI-usage && cd AI-usage
scripts/setup-signing.sh # optional, once — see "Code signing" below
scripts/install.sh # build, sign, install to /Applications, start at loginFind AI-usage in Finder → Applications (or Launchpad / Spotlight). On first launch macOS prompts once for Keychain access — choose Always Allow.
Uninstall with scripts/uninstall.sh.
cargo run # the status item appears in the menu bar
cargo test # unit tests (parsing + refresh scheduling)
cargo build --release- Token — read from the macOS Keychain generic-password item
Claude Code-credentials(claudeAiOauth.accessToken/refreshToken/expiresAt), re-read each poll and refreshed on expiry. - Usage —
GET https://api.anthropic.com/api/oauth/usagewithAuthorization: Bearer <token>andanthropic-beta: oauth-2025-04-20, returningfive_hour(session) andseven_day(weekly) utilization + reset times. - Refresh —
POST https://platform.claude.com/v1/oauth/token(grant_type=refresh_token) when the token is near expiry or returns 401.
A worker thread does all I/O and writes a shared AppState; the main thread
only reads it (AppKit must be touched on the main thread only).
api.anthropic.com returns 403 on direct access in some regions and must be
reached through an HTTP proxy. AI-usage uses the first http:// proxy from
HTTPS_PROXY / HTTP_PROXY, then falls back to the macOS system proxy
(scutil --proxy) so a login-launched app works without shell env. install.sh
also bakes the resolved proxy into the LaunchAgent. (ALL_PROXY / socks5 is
ignored.)
setup-signing.sh creates a self-signed code-signing identity in your login
keychain so install.sh can sign the bundle with a stable identity. That
keeps the Keychain "Always Allow" grant from being revoked every rebuild. It is
self-signed (not Apple-notarized) — fine because the app is launched directly,
not distributed. Skip it and install.sh falls back to ad-hoc signing.
src/
main.rs NSApplication (accessory) bootstrap + run loop
menubar.rs status item + dropdown; redraws from state
gauge.rs session % pie as a colored NSImage (green→red ramp)
poller.rs worker thread: triggers → fetch → Arc<Mutex<AppState>>
watch.rs notify watcher on ~/.claude/projects (refresh per turn)
token.rs OAuth access-token cache + refresh-token rotation
keychain.rs read/write the Claude OAuth credentials in the Keychain
provider/
mod.rs Provider trait + UsageWindow / UsageSnapshot / FetchError
claude.rs ClaudeProvider: keychain → HTTP GET → parse
packaging/ Info.plist + AppIcon.icns
scripts/ install / uninstall / signing / icon generation
Implement Provider::fetch() -> Result<UsageSnapshot, FetchError> in
provider/<name>.rs, normalize into UsageWindow { label, utilization, resets_at }, and wire it in main.rs. The UI and poller are provider-agnostic.
- Opus / Sonnet weekly breakdown +
extra_usagedisplay - Anthropic API usage / Codex providers
- Notarized/signed release builds
- Memory: Activity Monitor may show ~50 MB RSS, but most of that is shared macOS framework pages; the app's real private footprint is ~17 MB and stable.
- The OAuth token is read from the Keychain at runtime only — never logged or persisted by this app.
MIT — see LICENSE.