/usage from Claude Code, on your Samsung Galaxy Watch 7 (or any Wear OS 3+
device). A glance-able utilization meter for your Claude Pro/Max subscription
that also predicts when you'll hit the cap and pokes you when you cross
a threshold.
On the watch
- Main app — 5-hour arc with reset countdown, 24-hour sparkline, burn-rate prediction ("→ 100% in 1h 47m"), weekly Sonnet & Opus bars, refresh button.
- Two Tiles — Claude Usage (5-hour primary) and Claude Weekly (Sonnet + Opus).
- Complications —
RANGED_VALUE,SHORT_TEXT, andLONG_TEXTvariants. - Ambient-mode rendering — drops to monochrome single percentage when the display dims.
- Threshold notifications — wrist-tap when you cross your configured warn/urgent percentages, plus a reset notification when fresh quota lands.
On the phone
- Dashboard — same 5-hour arc + sparkline + burn-rate + weekly view.
- Sign-in flow — Chrome Custom Tab → paste OAuth code → token automatically syncs to watch via the Wearable Data Layer.
- Clipboard auto-capture — when you return to the app, it offers to use the code you just copied.
- Settings — tunable warn/urgent thresholds for both windows, refresh interval (15/30/60/120 min), quiet hours, reset-notification toggle.
- Diagnostics — copy-to-clipboard troubleshooting report with token expiry, last error, history sample.
shared/ Kotlin library: OAuth client, /api/oauth/usage client, history,
burn-rate analysis, threshold-bucketing, settings model
mobile/ phone — OAuth + dashboard + settings + diagnostics + token push
wear/ watch — main screen, two Tiles, three Complication types, ambient
mode, threshold notifier, periodic refresh worker
After first pairing the watch operates standalone: it makes its own API calls
to api.anthropic.com, refreshes its own access tokens, persists history,
and posts its own notifications. The phone is only needed again if the refresh
token ever fails or you sign out.
Design docs:
- v0.1:
docs/superpowers/specs/2026-05-12-watch-usage-app-design.md - v0.2:
docs/superpowers/specs/2026-05-12-v0.2-power-user-design.md
./gradlew assembleDebug
# Outputs:
# mobile/build/outputs/apk/debug/mobile-debug.apk
# wear/build/outputs/apk/debug/wear-debug.apk./gradlew :shared:testDebugUnitTest # 23 JVM unit tests
./gradlew :mobile:lintDebug :wear:lintDebugPhone:
adb connect <phone-ip>:<port>
adb -s <phone-ip>:<port> install -r mobile/build/outputs/apk/debug/mobile-debug.apkWatch (Galaxy Watch 7, ADB over WiFi enabled in Developer options):
adb connect <watch-ip>:<port>
adb -s <watch-ip>:<port> install -r wear/build/outputs/apk/debug/wear-debug.apkBoth APKs share applicationId=com.skyline.claudeusage and are signed with
the standard Android debug key — required for Wearable Data Layer messages
to pass between them.
- Open Claude Usage on the phone, tap Sign in.
- A Chrome Custom Tab opens claude.ai's OAuth page. Log in with your Pro/Max account.
- Tap Authorize on the consent screen. The callback page displays a
code#statestring. Copy it. - Return to the phone app. It auto-detects the clipboard match and offers a one-tap "Use clipboard". Tap Finish sign-in.
- The phone exchanges the code for tokens and ships them to the watch via the Wearable Data Layer.
- Open Claude Usage on the watch — it fetches your usage within a few seconds. Long-press a watchface to add the Tile or Complication.
These are the values that work for third-party clients of the Claude Code
OAuth flow — verified across multiple OSS reimplementations and on the
authoritative reference at akashmohan.com/writings/claude-code-oauth.
Captured in KtorPairingApi.kt:
CLIENT_ID = 9d1c250a-e61b-44d9-88ed-5944d1962f5e
AUTHORIZE_URL = https://claude.ai/oauth/authorize
TOKEN_URL = https://console.anthropic.com/v1/oauth/token (JSON body)
MANUAL_REDIRECT_URI = https://console.anthropic.com/oauth/code/callback
SCOPES = org:create_api_key user:profile user:inference
Notable quirks of this flow versus standard OAuth 2.0:
- Authorize URL must include a
code=truesentinel query param. - Token exchange POSTs JSON (not form-encoded), and includes a
statefield in the body. - The returned authorization code on the callback page is formatted as
<code>#<state>— split on#and pass the right half asstatein token exchange. - Only the 3-scope set above is allow-listed for third-party clients. The
5-scope set Claude Code itself uses (with
user:file_upload,user:mcp_servers,user:sessions:claude_code) will get past the consent screen but fail with "Authorization failed: Invalid request format" when the server tries to issue the code.
Defaults are conservative for a Max subscriber:
| Setting | Default | Range |
|---|---|---|
| 5-hour warn | 80% | 50–98% |
| 5-hour urgent | 95% | warn+1 – 100% |
| Weekly warn | 80% | 50–98% |
| Weekly urgent | 95% | warn+1 – 100% |
| Notify on reset | on | on/off |
| Quiet hours | 22:00–07:00 | any 0–23 / any 0–23 |
| Refresh interval | 15 min | 15 / 30 / 60 / 120 min |
The RefreshUsageScheduler listens for changes and reschedules the WorkManager
periodic worker live; you don't have to restart the watch app after changing
refresh interval.
Two channels:
- usage_warnings —
IMPORTANCE_HIGH. Fires once per upward bucket crossing per window (none → warn → urgent → full). State is per-window and reset by the server'sresets_atadvance. - usage_resets —
IMPORTANCE_DEFAULT. Fires when a window'sresets_atadvances (i.e. fresh quota landed).
During quiet hours, threshold events are suppressed and not state-advanced — so they fire on the first refresh after quiet hours end.
Notifications respect POST_NOTIFICATIONS (API 33+); the wear app declares
the permission and silently skips posting if it's not granted.