claudeers.
// Developer Tools

claude-usage-mac

Claude Code usage in the macOS menu bar and as a desktop widget

Actively maintained
100/100
last commit 9 days ago
last release 10 days ago
releases 19
open issues 0

Install with your AI

Paste into Claude Code, Cursor, or any agent — it reads the repo and wires the tool into your project.

Install and set up claude-usage-mac (release-binary project) into my current project.
Found on https://claudeers.com/claude-usage-mac
Repo: https://github.com/saeedkolivand/claude-usage-mac
Homepage/docs: https://claude-usage-mac.iamsaeed.dev/
Detected install method: release-binary → inspect the README
Category: devtools. Platforms: cli, api, desktop.
Read the repo's README for exact setup and env vars, then install it and wire it into my project.

Claudeers Health Verdict:
active; community-verified: false. Confirm the source before running anything.
// or install directly (release-binary)

Grab the latest release asset from GitHub.

# download a build from https://github.com/saeedkolivand/claude-usage-mac/releases
// or clone
git clone https://github.com/saeedkolivand/claude-usage-mac

// compatibility

Platformscli, api, desktop
Operating systems
AI compatibilityclaude
License
Pricingopen-source
LanguageSwift

claude-usage-mac

Claude Code usage in the macOS menu bar and as a desktop widget — session and weekly limit percentages, token counts, and estimated cost.

A native port of claude-usage-streamdeck-plugin for people who don't own a Stream Deck.

Claude Usage: the menu bar popover beside the medium and small widgets

Status: built, not yet run on real hardware. Everything compiles, tests pass, and the UI is reviewed through rendered snapshots — but the project is developed on Windows, so nobody has launched it on a Mac yet. See Unverified before trusting it.

Install

Requires macOS 14 or later.

brew tap saeedkolivand/tap
brew trust --cask saeedkolivand/tap/claude-usage
brew install --cask claude-usage

The trust step is required. Since Homebrew 6.0, third-party taps must be explicitly trusted before Homebrew will evaluate their Ruby — a response to a compromised tap being used to ship malware. --cask <tap>/<cask> trusts only this one cask; brew trust saeedkolivand/tap would trust everything in the tap, now and in future.

Or download the DMG from Releases, or build from source with brew install xcodegen && ./build.sh.

The widget shows up in the widget gallery once the app has run at least once.

Upgrading from 0.2 or earlier? Remove any placed widget and drag out a fresh one. Widgets became configurable in 0.3 and macOS cannot migrate a widget across that change — it refuses the timeline request rather than rendering. Widgets configured under 0.3.0 or 0.3.1 need their profile picked again for the same reason.

Builds are ad-hoc signed, not notarized, so macOS quarantines them. The cask clears that for you; if you install the DMG by hand, run:

xattr -dr com.apple.quarantine "/Applications/Claude Usage.app"

The cask is in a personal tap rather than homebrew/cask because that repo drops casks failing Gatekeeper checks from 2026-09-01, and --no-quarantine is being removed.

Small widgetMedium widget
Small — the 5-hour window, and when it resets.Medium — both limits, plus today and this week.
Large widgetProject-scoped widget
Large — adds a 14-day chart.Project-scoped — one directory's tokens and cost. No gauges: limits are account-level.

The menu bar popover

Every widget carries its own configuration, so you can place one per account or one per project, side by side.

What it reads

Two sources, both already on your machine. Nothing is sent anywhere.

SourceGives
api.anthropic.com/api/oauth/usage, using the OAuth token Claude Code already stored5-hour and 7-day limit utilization, and when each resets
~/.claude/projects/**/*.jsonltoday / this week / current session token counts and estimated cost

The token is read from <config dir>/.credentials.json, falling back to the login Keychain. We never log in, never write credentials, and never transmit anything except the one authenticated GET above.

Claude Code names that Keychain item after the config dir it was authenticated from: Claude Code-credentials for the default ~/.claude, and Claude Code-credentials-<first 8 hex of sha256(config dir)> for anything relocated with CLAUDE_CONFIG_DIR. Each service name is tried pinned to account claude-code-user first and unpinned second, because the account name differs between Claude Code versions.

An expired credential never hides a live one behind it: a leftover .credentials.json, or a dead Keychain item sharing a service name with a current one, is remembered but stepped over, and only reported if every other candidate misses.

Claude Code only refreshes the config dir it is actually running in, so a profile you have stopped using parks on a dead token — and, until it is refreshed, on whatever numbers it last managed to fetch. Because the usage endpoint is account-scoped rather than config-dir-scoped, such a profile shows the rings of another profile signed in to the same account (same email and organization) if one is present. Failing that it says "Token expired — use Claude Code in this profile to refresh", which is the only thing that actually refreshes it.

A profile with no token at all keeps saying so rather than borrowing: that is also what a denied Keychain prompt looks like, and it is worth fixing rather than hiding.

macOS asks once per item for permission to read it. "Always Allow" stops it asking again.

Profiles

A profile is a Claude Code config folder — one logged-in account. Relocating it with CLAUDE_CONFIG_DIR is the only way Claude Code supports more than one, so that's what discovery looks for: ~/.claude, anything beside it whose name starts with .claude, and folders you add in Settings. A folder counts when it contains a projects directory.

Pick the menu bar's profile in Settings; each widget picks its own. Every profile keeps its own cache and its own history file, so one account can never show another's numbers.

macOS caveat. The Keychain item's name is hashed from the literal CLAUDE_CONFIG_DIR string you exported — Claude Code does no path resolution, so ~/.claude-work, $HOME/.claude-work and /Users/you/.claude-work/ are three different items. We try the plausible spellings; if yours is unusual the profile reports no-token. Settings shows the name we look for, next to the folder, so you can check it against:

security dump-keychain | grep -o '"svce"<blob>="Claude Code[^"]*"' | sort -u

Tokens and cost still work either way, since those come from transcripts on disk.

Architecture

Sources/
  UsageCore/     data layer, no UI — shared by the app, the widget, and the CLI
  SharedViews/   the ring gauge and palette, shared by the app and the widget
  MenuBarApp/    MenuBarExtra, the 60s poller, settings
  Widget/        AppIntent configuration and the widget families
  UsageCLI/      prints the snapshot; the CI smoke test

swift test covers UsageCore with no Xcode involved. The app and widget bundle is built by Xcode via XcodeGen, since SPM can't express an app that embeds an extension. Both build systems compile Sources/UsageCore directly — there's no framework target to embed and sign.

Getting data to the widget is the fiddly part, and worth writing down:

  • The widget extension must be sandboxed. macOS never registers an unsandboxed app extension, so it silently never appears in the widget gallery. That rules out reading ~/.claude from the widget.
  • App Groups are the textbook answer and don't work here. They're a provisioning-profile capability, so with ad-hoc signing and no team containerURL(forSecurityApplicationGroupIdentifier:) returns nil.
  • The host app isn't sandboxed, so it writes directly into the widget's own container at ~/Library/Containers/…widget/Data/Library/Application Support/. Inside the sandbox the widget reads exactly that as its Application Support — no entitlement, no App Group, no paid account.

The host only writes there once macOS has created the container; materializing one by hand leaves it without its container metadata, which can stop the extension launching at all. So a freshly added widget shows a placeholder until the next poll, at most 60 seconds.

Developing without a Mac

Swift doesn't build on Windows, so CI is the compiler and the display:

gh run download <run-id> -n snapshots -D snapshots

Tests/SnapshotTests renders every view — widget families, project scope, the menu popover — across light and dark and every data state, and CI uploads the PNGs. The gallery images above come from the same pipeline, so they can't drift from the UI; they are the UI, with a backdrop and a shadow.

Unverified

What the snapshot loop cannot prove, and needs a pass on real hardware:

  • The widget loads and appears in the widget gallery. It didn't at first — the extension shipped unsandboxed and macOS never registered it. build.sh now reports registration; if it says nothing is registered, killall chronod forces a rescan.
  • The Keychain consent prompt behaves, and the token actually reads.
  • "Open at login" sticks — SMAppService needs a properly signed app.
  • The popover's Refresh / Settings / Quit buttons. ImageRenderer draws interactive controls as unavailable, so they show as prohibition badges in every snapshot. Layout around them is real; the buttons themselves aren't.
  • The Settings window. Form with .formStyle(.grouped) is NSTableView-backed and renders empty detached, so there are deliberately no settings snapshots rather than blank ones posing as coverage.

Try the data layer

Runs on any Mac with a Swift toolchain, no Xcode project needed:

swift run usage-cli              # human-readable summary
swift run usage-cli --profiles   # list discovered profiles
swift run usage-cli --json       # exactly what the widget will render
swift run usage-cli --write      # write the snapshot files to disk

Cost accuracy

Costs are computed from token counts, because current Claude Code transcripts no longer record a costUSD field. Cache writes are billed by TTL — 1.25x input for the 5-minute cache and 2x for the 1-hour cache — and Claude Code writes almost exclusively 1-hour entries. Collapsing both into the 5-minute rate (which the Stream Deck plugin did before v1.7) understates the real figure substantially.

On Pro/Max plans this is notional equivalent API spend, not money you were charged. Rates live in Sources/UsageCore/Pricing.swift; edit them when Anthropic changes pricing.

Scanning is incremental — per-file byte offsets, so a 60s poll re-reads only what was appended rather than the multiple gigabytes an active ~/.claude/projects accumulates.

History and projects

Daily totals are kept in ~/Library/Application Support/ClaudeUsage/history.json. They have to be recorded rather than recomputed: the scanner only reads the last 7 days of transcripts, and Claude Code prunes them after about a month. On first launch a one-off backfill reads the whole archive so the chart starts populated instead of filling in over a week.

Project names come from each entry's cwd. The directory name under ~/.claude/projects is a slug that flattens /, \ and _ all to -, so it can't be reversed into a real name.

Releasing

git tag v0.3.0 && git push origin v0.3.0

That builds, stamps the version, makes the DMG, publishes a release, and updates the cask in saeedkolivand/homebrew-tap. The tap update needs a TAP_TOKEN repository secret — a fine-grained PAT with Contents: read/write on homebrew-tap. Without it the release still publishes and the step is skipped.

License

MIT

// faq

What is claude-usage-mac?

Claude Code usage in the macOS menu bar and as a desktop widget. It is open-source on GitHub.

Is claude-usage-mac free to use?

claude-usage-mac is open-source, so it is free to use.

What category does claude-usage-mac belong to?

claude-usage-mac is listed under devtools in the Claudeers registry of Claude-compatible tools.

4 views
13 stars
unclaimed
updated 15 days ago

// embed badge

claude-usage-mac on Claudeers
[![Claudeers](https://claudeers.com/api/badge/claude-usage-mac.svg)](https://claudeers.com/claude-usage-mac)

// retro hit counter

claude-usage-mac hit counter
[![Hits](https://claudeers.com/api/counter/claude-usage-mac.svg)](https://claudeers.com/claude-usage-mac)

// reviews

// guestbook

0/500

// related in Developer Tools

🔓

The agent harness performance optimization system. Skills, instincts, memory, security, and research-first development for Claude Code, Codex, Opencode, Curs…

// devtoolsaffaan-m/JavaScript240,305MIT[ claude ]
🔓

Use Garry Tan's exact Claude Code setup: 23 opinionated tools that serve as CEO, Designer, Eng Manager, Release Manager, Doc Engineer, and QA

// devtoolsgarrytan/TypeScript128,278MIT[ claude ]
🔓

AI coding assistant skill (Claude Code, Codex, OpenCode, Cursor, Gemini CLI, and more). Turn any folder of code, SQL schemas, R scripts, shell scripts, docs,…

// devtoolssafishamsi/Python109,277MIT[ claude ]
🔓

Makes your AI agent think like the laziest senior dev in the room. The best code is the code you never wrote.

// devtoolsDietrichGebert/JavaScript104,762MIT[ claude ]
→ see how claude-usage-mac connects across the ecosystem