brew trust fixcik/tap # once, Homebrew asks this for third-party taps
brew install fixcik/tap/ccmetrOr grab the build from Releases, unzip and drag ccmetr.app to /Applications. Going that route the build is ad-hoc signed, so Gatekeeper blocks the first launch — right-click → Open → Open, or:
xattr -dr com.apple.quarantine /Applications/ccmetr.appOn first launch macOS asks whether ccmetr may read the Claude token from your login keychain. You can say no — see below. Updates arrive through Sparkle.
| Keychain | Claude CLI | |
|---|---|---|
| What it does | reads the token Claude Code stored, calls the usage endpoint directly | runs claude -p "/usage" and reads its answer |
| Access to secrets | needs the keychain prompt once | none at all |
| Cost per refresh | one HTTP request | ~5 s and ~0.5 GB peak while claude runs |
| Refresh interval | 3 min | 10 min |
| Per-model limits | yes | only what /usage prints |
The CLI path is the default, because the keychain one cannot stay quiet — see below. It costs no quota either (/usage performs no inference — measured at 0 input and 0 output tokens), but every refresh spawns a real claude process that takes a few seconds and half a gigabyte of memory while it lives; the memory is released as soon as it exits.
Pick the keychain path if you'd rather have cheap refreshes, per-model numbers and don't mind re-approving access now and then.
You can switch at any time under Data source in the gear menu.
The app exists to read one number, so it touches as little as possible:
- It reads a single keychain item —
Claude Code-credentials, the one Claude Code itself creates — and never writes to the keychain. On the CLI path it reads nothing at all. - The token goes to exactly one address:
https://api.anthropic.com/api/oauth/usage. It is never logged, never written to disk, and re-read from the keychain before each request rather than kept around. - History stays on your Mac:
~/Library/Application Support/ccmetr/history.jsonholds percentages and timestamps, nothing else. Settings live in standard user defaults. - No telemetry, no analytics, no account, no crash reporting. Sparkle contacts GitHub to check for updates and system profiling is explicitly disabled.
- The usage endpoint is undocumented. It may change or disappear without notice, which is also why polling is kept at 3 minutes.
Every release is built by the workflow in this repository — the logs, the archive and its SHA-256 are public.
Two separate reasons, and only one of them is ours.
The keychain item belongs to Claude Code. Its OAuth token lives about eight hours, and every time Claude Code refreshes it — including right after your Mac wakes up — it rewrites the item along with its access control list. Dumping the ACL shows exactly one trusted application afterwards: Claude Code itself. Whatever you approved is gone, so the prompt comes back roughly once per token lifetime. Nothing in ccmetr can prevent that; the item isn't ours to fix. That is why the CLI path is the default.
Signatures. macOS binds "Always Allow" to the app's designated requirement. An ad-hoc build has no stable identity, so its requirement is the hash of that exact binary — rebuild and the system sees a stranger. Releases are signed with one certificate, making the requirement identifier "com.ccmetr.app" and certificate leaf = H"…", which survives updates. Building locally, run ./scripts/signing-cert.sh once and pass CCMETR_SIGN_IDENTITY, otherwise every rebuild asks again.
- It calls the same endpoint Claude Code's own
/usageuses. That endpoint rate-limits hard and buckets requests byUser-Agent— withoutclaude-code/<version>you land in a punishing bucket and stay on429for a long while, so ccmetr sends the header and detects your installed version automatically. A429puts it into backoff instead of an error state; the last known numbers stay on screen. - The API returns no history, so the 7-day chart is built from samples the app collects itself. A fresh install starts with an empty chart.
- Interval, launch at login, what to show in the bar and a below-10% alert live in the gear menu.
macOS 14+ and a Swift 6 toolchain; Xcode isn't needed.
./scripts/build-app.sh # → build/ccmetr.app
./scripts/make-assets.sh # regenerates every image in docs/Images aren't drawn by hand — the app renders them from its own UI (--export-hero, --export-popover, --export-bar-preview, --export-icon).
To ship updates: generate a Sparkle key pair once with ./scripts/sparkle-keys.sh, commit sparkle-public-key.txt, put the private key into the SPARKLE_PRIVATE_KEY secret. Create a signing certificate with ./scripts/signing-cert.sh and put it into MACOS_CERT_P12 / MACOS_CERT_PASSWORD so published builds keep one identity. Then push a v* tag — the release workflow builds, signs and publishes the appcast.

