|
| 1 | +# TokenMeter |
| 2 | + |
| 3 | +macOS menu bar app for tracking Claude Code usage, rate limits, and costs. Native SwiftUI, no Electron/Tauri. |
| 4 | + |
| 5 | +## Build |
| 6 | + |
| 7 | +```bash |
| 8 | +cd TokenMeter |
| 9 | +swift build -c release |
| 10 | +``` |
| 11 | + |
| 12 | +Binary output: `TokenMeter/.build/release/TokenMeter` |
| 13 | + |
| 14 | +## Architecture |
| 15 | + |
| 16 | +- **SwiftUI MenuBarExtra** — macOS 14+, `LSUIElement` (no dock icon) |
| 17 | +- **Swift Package Manager** — single executable target, no Xcode project |
| 18 | +- **Concurrency** — `@MainActor` view model, `actor` for services, `async let` for parallel fetches |
| 19 | + |
| 20 | +### Key Components |
| 21 | + |
| 22 | +| File | Role | |
| 23 | +|------|------| |
| 24 | +| `TokenMeterApp.swift` | App entry, `MenuBarExtra` with popover | |
| 25 | +| `UsageViewModel.swift` | `@MainActor ObservableObject` — state, timer, caching, notifications | |
| 26 | +| `Services/NativeUsageParser.swift` | Parses `~/.claude/projects/**/*.jsonl` — costs, tokens, hourly data | |
| 27 | +| `Services/UsageAPIService.swift` | Reads OAuth token from macOS Keychain, calls `api.anthropic.com/api/oauth/usage` | |
| 28 | +| `Services/UpdateChecker.swift` | Checks GitHub releases for updates | |
| 29 | +| `Models/UsageSummary.swift` | All data models: `DailyUsage`, `HourlyUsage`, `RateLimitInfo`, `ClaudePlan` | |
| 30 | +| `Views/` | SwiftUI views — dashboard, rate limits, heatmap, charts, settings | |
| 31 | + |
| 32 | +### Data Sources |
| 33 | + |
| 34 | +1. **Anthropic API** (`UsageAPIService`) — real rate limit utilization % and reset times |
| 35 | + - Reads OAuth token from Keychain (`kSecAttrService: "Claude Code-credentials"`) |
| 36 | + - `GET https://api.anthropic.com/api/oauth/usage` with `Authorization: Bearer <token>` |
| 37 | + - Also reads `rateLimitTier` from credential blob for plan auto-detection |
| 38 | + |
| 39 | +2. **Local JSONL** (`NativeUsageParser`) — costs, model breakdowns, token counts, hourly activity |
| 40 | + - Scans `~/.claude/projects/` and `~/.config/claude/projects/` |
| 41 | + - Deduplicates by `requestId`, filters `<synthetic>` entries |
| 42 | + - Embedded pricing: Opus 4.5 ($5/$25), Sonnet ($3/$15), Haiku ($1/$5) per MTok |
| 43 | + |
| 44 | +### Patterns |
| 45 | + |
| 46 | +- API + local data fetched concurrently via `async let` in `refresh()` |
| 47 | +- API data preferred for rate limits; local data used as fallback |
| 48 | +- `UserDefaults` for caching summary + settings |
| 49 | +- `UNUserNotificationCenter` for rate limit alerts (80% threshold, 1hr throttle) |
| 50 | +- Timer-based auto-refresh (default 5 min) |
| 51 | + |
| 52 | +## Release |
| 53 | + |
| 54 | +Push a version tag to trigger automated release: |
| 55 | +```bash |
| 56 | +git tag v0.x.0 |
| 57 | +git push origin v0.x.0 |
| 58 | +``` |
| 59 | + |
| 60 | +GitHub Actions builds, ad-hoc signs, creates release zip, and updates Homebrew cask. |
| 61 | + |
| 62 | +## Install |
| 63 | + |
| 64 | +```bash |
| 65 | +brew install Priyans-hu/tap/tokenmeter |
| 66 | +``` |
0 commit comments