Architecture

April 14, 2026 · View on GitHub

System Overview

┌─────────────────────────────────────────────────────┐
│                    Menu Bar Icon                     │
│              (NSStatusItem + Popover)                │
└──────────────────────┬──────────────────────────────┘

┌──────────────────────▼──────────────────────────────┐
│                  UsageManager                        │
│  - Discovers available providers                     │
│  - Manages refresh timer                             │
│  - Publishes combined state for UI                   │
└──┬──────────┬──────────┬──────────┬─────────────────┘
   │          │          │          │
┌──▼───┐  ┌──▼───┐  ┌──▼────┐  ┌──▼──────────┐
│Claude│  │Codex │  │Cursor │  │Antigravity  │
│      │  │      │  │       │  │             │
│OAuth │  │OAuth │  │SQLite │  │Process Probe│
│ API  │  │ API  │  │+ RPC  │  │ + Local RPC │
└──────┘  └──────┘  └───────┘  └─────────────┘

Project Structure

MyUsage/
├── MyUsageApp.swift              # @main, NSStatusItem setup
├── Models/
│   ├── ProviderKind.swift        # Enum: .claude, .codex, .cursor, .antigravity
│   └── UsageSnapshot.swift       # Unified usage data model
├── Providers/
│   ├── UsageProvider.swift       # Protocol all providers conform to
│   ├── ClaudeProvider.swift      # Claude Code: OAuth API
│   ├── CodexProvider.swift       # Codex: OAuth API
│   ├── CursorProvider.swift      # Cursor: SQLite + Connect RPC
│   └── AntigravityProvider.swift # Antigravity: process probe + local RPC
├── Services/
│   ├── UsageManager.swift        # Orchestrator: auto-detect, timer, state
│   ├── KeychainHelper.swift      # Security.framework Keychain reader
│   └── TokenRefresher.swift      # Shared OAuth refresh logic
├── Views/
│   ├── MenuBarIcon.swift         # NSStatusItem + popover host
│   ├── UsagePopover.swift        # Main popover container
│   ├── ProviderCard.swift        # Individual provider card
│   ├── ProviderDetailView.swift  # Expanded detail view
│   └── SettingsView.swift        # Preferences window
├── Utilities/
│   ├── ProcessHelper.swift       # Shell command wrappers (ps, lsof)
│   └── SQLiteHelper.swift        # C SQLite3 API wrapper
├── Resources/
│   └── Assets.xcassets           # App icon, provider icons
└── Tests/
    └── MyUsageTests/
        ├── ClaudeProviderTests.swift
        ├── CodexProviderTests.swift
        ├── CursorProviderTests.swift
        ├── AntigravityProviderTests.swift
        └── TokenRefresherTests.swift

Provider Data Sources

Claude Code

ItemDetail
Credential~/.claude/.credentials.json → Keychain Claude Code-credentials
Token typeOAuth JWT (short-lived, auto-refresh)
RefreshPOST https://platform.claude.com/v1/oauth/token
Client ID9d1c250a-e61b-44d9-88ed-5944d1962f5e
Usage APIGET https://api.anthropic.com/api/oauth/usage
HeadersAuthorization: Bearer <token>, anthropic-beta: oauth-2025-04-20

Response fields:

  • five_hour.utilization — % used in 5h rolling window
  • five_hour.resets_at — ISO 8601
  • seven_day.utilization — % used in 7-day window
  • seven_day_opus — separate Opus weekly limit (optional)
  • extra_usage — monthly overage credits in cents (optional)

Billing model: Rolling windows (5h + 7d simultaneous), hitting either throttles.


Codex

ItemDetail
Credential~/.codex/auth.json → Keychain Codex Auth
Token typeOAuth JWT (refresh when last_refresh > 8 days)
RefreshPOST https://auth.openai.com/oauth/token (form-encoded)
Client IDapp_EMoamEEZ73f0CkXaXp7hrann
Usage APIGET https://chatgpt.com/backend-api/wham/usage
HeadersAuthorization: Bearer <token>

Response fields:

  • rate_limit.primary_window.used_percent — 5h window %
  • rate_limit.secondary_window.used_percent — 7-day window %
  • credits.balance — remaining dollars
  • credits.has_credits / credits.unlimited
  • code_review_rate_limit — separate weekly code review limit
  • plan_type — "plus", etc.

Billing model: Rolling windows (5h + 7d) + optional purchased credits.


Cursor

ItemDetail
CredentialSQLite ~/Library/Application Support/Cursor/User/globalStorage/state.vscdb
KeyscursorAuth/accessToken, cursorAuth/refreshToken, cursorAuth/cachedEmail, cursorAuth/stripeMembershipType
Token typeJWT (short-lived, refresh before each request if expired)
RefreshPOST https://api2.cursor.sh/oauth/token
Client IDKbZUR41cY7W6zRSdpSUJ7I7mLYBKOCmB
Usage API (primary)POST https://api2.cursor.sh/aiserver.v1.DashboardService/GetCurrentPeriodUsage
Plan APIPOST https://api2.cursor.sh/aiserver.v1.DashboardService/GetPlanInfo
HeadersAuthorization: Bearer <token>, Connect-Protocol-Version: 1, Content-Type: application/json
Fallback APIGET https://cursor.com/api/usage?user=<userId> with Cookie: WorkosCursorSessionToken=<token>

Response fields (GetCurrentPeriodUsage):

  • planUsage.totalPercentUsed, autoPercentUsed, apiPercentUsed
  • planUsage.totalSpend / limit / remaining (cents)
  • billingCycleStart / billingCycleEnd (unix ms string)
  • spendLimitUsage — on-demand budget (individual/pooled)

GetPlanInfo response:

  • planInfo.planName, includedAmountCents, price, billingCycleEnd

Billing model: Monthly billing cycle with included budget (cents) + on-demand.


Antigravity

ItemDetail
Discoveryps -ax → find language_server_macos.*antigravity, extract --csrf_token
Portlsof -nP -iTCP -sTCP:LISTEN -p <pid> → probe each port
ProbePOST https://127.0.0.1:<port>/.../GetUnleashData → first 200 OK
Usage APIPOST https://127.0.0.1:<port>/exa.language_server_pb.LanguageServerService/GetUserStatus
FallbackPOST .../GetCommandModelConfigs
Headersx-codeium-csrf-token: <token>, Connect-Protocol-Version: 1
SQLite fallback~/Library/Application Support/Antigravity/User/globalStorage/state.vscdbantigravityAuthStatus

Response fields:

  • userStatus.planStatus.planInfo.planName — "Free" / "Pro" / "Teams" / "Ultra"
  • userStatus.cascadeModelConfigData.clientModelConfigs[]
    • .label — "Gemini 3 Pro (High)", "Claude Sonnet 4.5", etc.
    • .quotaInfo.remainingFraction — 0.0–1.0
    • .quotaInfo.resetTime — ISO 8601

Billing model: Per-model quota with 5h rolling window, fraction-based.

Token Refresh Summary

ProviderTriggerEndpointAuth
Claude5m before expiry or 401/403platform.claude.com/v1/oauth/tokenrefresh_token + client_id
Codexlast_refresh > 8 days or 401/403auth.openai.com/oauth/tokenrefresh_token + client_id (form-encoded)
CursorJWT expired or 401api2.cursor.sh/oauth/tokenrefresh_token + client_id
AntigravityN/A (CSRF from process)N/ACSRF token from CLI args