Skip to content

feat: add AI Quota tab showing Claude & Codex usage#1306

Open
meloer101 wants to merge 3 commits into
TheBoredTeam:devfrom
meloer101:fix/ai-quota-auth-backoff
Open

feat: add AI Quota tab showing Claude & Codex usage#1306
meloer101 wants to merge 3 commits into
TheBoredTeam:devfrom
meloer101:fix/ai-quota-auth-backoff

Conversation

@meloer101

Copy link
Copy Markdown

Summary

  • Auth failure backoff: When Claude token expires (401), back off 15 minutes instead of retrying every 2 minutes until rate-limited (429)
  • Rate limit handling: Parse Retry-After header on 429 responses, default 30-min backoff
  • XPC-first credential flow: Try XPC helper before Keychain fallback to avoid macOS password prompts on unsigned builds
  • Preserve last successful data: Don't overwrite working quota data with transient errors
  • UI improvements: Show "Updated X ago" timestamp, use floor() for percentage display

Problem

When the Claude OAuth access token expires, the app was:

  1. Fetching with expired token → 401
  2. Retrying every 2 minutes with the same bad token
  3. Eventually getting rate-limited (429)
  4. Only then backing off (30 min)

Now it detects the 401 immediately and backs off with a clear "Token expired. Re-login with CLI." message.

Test plan

  • Verify Claude quota displays correctly with valid token
  • Verify expired token shows "Token expired" message and backs off
  • Verify rate-limited state shows retry countdown
  • Verify Codex quota unaffected
  • Verify "Updated X ago" timestamp appears on quota cards

🤖 Generated with Claude Code

meloer101 and others added 2 commits June 5, 2026 14:23
Display real-time usage percentages for Claude (Anthropic) and Codex
(ChatGPT) accounts in a new dedicated tab within the notch. Reads
OAuth credentials via XPC helper (Keychain + file fallback) and
queries the official usage APIs. Includes per-tier progress bars,
reset countdowns, and auto-refresh every 5 minutes (only when enabled).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When the Claude access token expires (401), the app was retrying every
2 minutes with the same bad token until it got rate-limited (429). Now
it backs off on auth failures too (15 min) and shows a clear message.

Other improvements:
- Try XPC helper before Keychain fallback (avoids password prompts)
- Preserve last successful quota on transient errors
- Show "Updated X ago" timestamp on quota cards
- Handle 429 with Retry-After header support
- Use floor() for utilization percentage display
- Reduce polling interval from 5 min to 2 min

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

✅ This PR now targets dev.

dev is the expected target branch for fork PRs, so no further action is needed.

- Remove unused `isTransient` property from AIQuotaRequestError
- Update test script to cover new auth failure backoff and blockMessage API

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@meloer101 meloer101 changed the base branch from main to dev June 6, 2026 08:20
@meloer101 meloer101 changed the title fix: stop hammering API with expired tokens in AI Quota feat: add AI Quota tab showing Claude & Codex usage Jun 6, 2026
@Ein-Tim

Ein-Tim commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

I don't understand what this PR does, the description make it seem like a bug fix (while the title talks about a feature), but this can't be as there is no feature relating to Claude Code in the app right now.

@meloer101

Copy link
Copy Markdown
Author

Hi @Ein-Tim, sorry for the confusing description!

This PR adds a brand new AI Quota tab to boring.notch — it's a completely new feature, not a bug fix. The branch name and original description were misleading, apologies for that.

What this PR adds

A new AI Quota view accessible from the notch that shows real-time usage for:

  • Claude (via Anthropic's OAuth API) — displays 5h and 7d usage windows with progress bars, reset countdown, and last-updated timestamp
  • Codex (via OpenAI's usage API) — same display format

The feature reads credentials from the local Claude Code CLI keychain and Codex CLI config, so it works out of the box if the user has either tool installed.

The "fix" commits

The fix: commit in the branch addresses a bug discovered during development: when the Claude access token expires (401), the original code would retry every 2 minutes with the same dead token until it got rate-limited (429). The fix adds a proper backoff policy for both auth failures (15 min) and rate limits (30 min / Retry-After header).

Happy to update the PR description or split into separate PRs if that's easier to review. Let me know!

@meloer101

Copy link
Copy Markdown
Author

Also wanted to mention — this is actually my first ever PR on GitHub, so I'm still learning the process! I just noticed myself that the branch is named fix/ when it should really be feat/. I wasn't paying close enough attention when setting it up. Thanks for taking the time to look at it and leave a comment, really appreciate it! 🙏

@meloer101

Copy link
Copy Markdown
Author

One known issue I should flag: before the quota data loads successfully, the app prompts for the macOS keychain password multiple times. This happens because the app falls back to reading the Claude credentials directly from the system keychain (via SecItemCopyMatching), which triggers the macOS authorization dialog on unsigned/locally-signed builds.

We have an XPC helper that tries to read credentials from the filesystem first to avoid this, but it currently falls back to the keychain path too often. We haven't been able to fully resolve this yet and would appreciate any guidance from someone more familiar with the project's XPC/keychain setup. Happy to iterate on this if you have suggestions!

@Ein-Tim

Ein-Tim commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

Ah, I see. Don't worry about that. This PR then (at least partly) duplicates the work done in #970. Please take a look at #970, also in regards to the discussion whether this should be a core feature or rather an extension one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants