Skip to content

feat: add Claude usage widget#951

Open
ManaphatDev wants to merge 1 commit into
amnweb:mainfrom
ManaphatDev:feat/claude-usage-widget
Open

feat: add Claude usage widget#951
ManaphatDev wants to merge 1 commit into
amnweb:mainfrom
ManaphatDev:feat/claude-usage-widget

Conversation

@ManaphatDev
Copy link
Copy Markdown

Adds a widget showing Claude Code subscription usage (5-hour and 7-day limits) on the bar, with a popup card of progress bars and reset countdowns. Reads the existing Claude Code OAuth token from ~/.claude/.credentials.json and caches results in app_data_path with a TTL (429-safe). Includes a docs page and regenerated schema.json.

@amnweb
Copy link
Copy Markdown
Owner

amnweb commented Jun 5, 2026

  1. schema.json is an auto generated file and it is not allowed to be changed.

  2. Separate the service from the widget. Create something like claude_api.py in /src/core/widgets/services/claude_usage/ and use this file to share data between multiple widgets. Example:

       +-----------------------+
       |       Claude API      |
       +-----------+-----------+
                   |
     +-------------+-------------+
     |             |             |
+----+-----+ +-----+----+ +-----+----+
| Widget 1 | | Widget 2 | | Widget 3 | 
+----------+ +----------+ +----------+
  1. You do not need to use a hardcoded SVG for the icon in the label. This is not the standard way YASB works, as you can easily link an image in a label using an <img> tag. So:
icon_size: 14
icon_color: "#D97757"

you probably do not need this.

  1. Since this PR was submitted by AI and everything looks wrong, try prompting it first to understand the codebase and how the widget service works. Even better if you can understand it properly so you can fix everything they made.

  2. Use menu: instead of card: for the popup.

@ManaphatDev
Copy link
Copy Markdown
Author

ManaphatDev commented Jun 6, 2026

Thanks for the detailed review I went back through the widget/service architecture properly this time and pushed the changes. Addressed point by point:

  1. schema.json reverted to upstream, so it's no longer part of this PR.

  2. Service / widget split moved all the data fetching into a shared service at src/core/widgets/services/claude_usage/claude_api.py. ClaudeUsageService is a reference-counted singleton keyed by (update_interval, cache_ttl) that owns the timer + worker thread and emits a data_ready signal, so multiple widgets share a single poller and a single on-disk cache following the server_monitor service pattern. The widget is now just a view that subscribes to the signal.

  3. Icon - dropped the hardcoded SVG along with the icon_size / icon_color options. The {logo} token now links a bundled src/assets/images/claude.png via an tag, and users can of course drop in any Nerd Font glyph or their own instead.

  4. Fair point. I studied how the existing widgets/services actually work this time (used server_monitor for the service and github for the menu) instead of trusting the generated code, and reworked it from there. Hopefully this pass lines up much better with how YASB is structured happy to adjust anything that still looks off.

  5. menu instead of card renamed throughout: the config block is menu:, the callback is toggle_menu, and the popup class is .claude-usage-menu, mirroring the github widget.

PR diff is down to 6 files with no schema.json. Let me know if you'd like any further changes

@amnweb
Copy link
Copy Markdown
Owner

amnweb commented Jun 6, 2026

I still don't get why you need a hardcoded image there, or why all this mess with it and the {logo} placeholder?
You can use an image anyway in the label label: "<img src='logo.png'> {five_hour}"
CallbacksConfig is also wrong, you could use someting like

class ClaudeUsageCallbacksConfig(CallbacksConfig):
    on_left="toggle_menu",
    on_middle="do_nothing",
    on_right="toggle_label",

and than

class ClaudeUsageConfig(CustomBaseModel):
    ...
    callbacks: ClaudeUsageCallbacksConfig = ClaudeUsageCallbacksConfig()
    ```

@ManaphatDev
Copy link
Copy Markdown
Author

ManaphatDev commented Jun 6, 2026

Yeah you're right, that was overcomplicated

Cleaned it up:
Dropped the bundled image and the whole {logo} placeholder thing. The icon is just part of the label now — a Nerd Font glyph by default, and if someone wants the actual Claude logo they can just drop in like you said. Added a note in the docs pointing to svgl.app for the logo.
Fixed the callbacks too moved them into a ClaudeUsageCallbacksConfig(CallbacksConfig) subclass instead of passing kwargs, so the generated schema picks up the right defaults.
Pushed. Thanks for bearing with me on this

@amnweb
Copy link
Copy Markdown
Owner

amnweb commented Jun 6, 2026

Thanks, a few more suggestions:

QProgressBar is not a good solution for showing progress bars because there is really annoying calculation involved, and if you have a border radius for the progress bar and the value is low, you end up with a square fill. That is a known issue in Qt. Check the Copilot widget, where the progress bar is drawn manually.

Another suggestion: clean up all validation comments. We really do not need them there.

Also, I'm still not sure about CLAUDE_ICON = "\U000f06a9". In this way, you force users to install a specific font to display these icons. If you "must" show this icon, keep it configurable. If you don't need it, remove it. I don't know if any popup shows icons in this way in the project, to be honest.

@ManaphatDev
Copy link
Copy Markdown
Author

ManaphatDev commented Jun 6, 2026

Thanks a ton for the review — super helpful, and all three make sense.

1. Progress bar — yeah, I get the rounded-corner square-fill thing. I'll ditch QProgressBar and go with the track + child .fill QFrame setup like the Copilot widget (including the max(fill_width, height) trick so it stays rounded at low values). Bonus: it ends up fully CSS-styleable.

2. Validation comments — yep, stripping those out.

3. Icon — fair point, I don't want to force a font on anyone either. I've actually already moved it off the Nerd Font glyph and render it as an SVG with QtSvg (same as launchpad / open_meteo / quick_launch), so no font needed and it's the real logo instead of a code-point. Still configurable (color/size) and totally optional — and if you'd rather it ship without an icon by default, just say the word and I'll pull it.

I'll push the updated version shortly. Cheers!

@amnweb
Copy link
Copy Markdown
Owner

amnweb commented Jun 6, 2026

I really don’t think you need icons for this. Make it a header like we have in all other popups, like Copilot, GitHub, etc. Icons in Open-Meteo or Quick Launch are used for a different purpose, to be honest.

@ManaphatDev
Copy link
Copy Markdown
Author

Makes sense dropping the icon and going with a plain header like the other popups. Pushing shortly

@ManaphatDev
Copy link
Copy Markdown
Author

Pushed an update addressing all three points:

  • Draw the menu progress bar as a track + child .fill QFrame instead of QProgressBar, keeping the fill at least as wide as it is tall so the rounded corners survive at low values (the QProgressBar::chunk square-fill issue).
  • Plain text menu header like the other popups (Copilot, GitHub) — dropped the icon.
  • Removed the explanatory comments from the validation schema.
image image

@amnweb
Copy link
Copy Markdown
Owner

amnweb commented Jun 6, 2026

OK, thanks. Just please remove lines like this one:

# -- popup menu -------------------------------------------------------

I really hate this type of comment when AI adds it. And please clean up the commit history, all of this can be one commit. When you think it is ready to merge, please ping me.

Shows Claude Code 5-hour and 7-day subscription usage on the bar, with a
popup menu of progress bars and reset countdowns. Reuses the OAuth
credentials the Claude Code CLI already stores (no API key needed); a
shared, reference-counted service polls the usage endpoint off the UI
thread and caches the result to disk with a 429 fallback.
@ManaphatDev ManaphatDev force-pushed the feat/claude-usage-widget branch from 0110655 to f081825 Compare June 7, 2026 03:45
@ManaphatDev
Copy link
Copy Markdown
Author

Done

Removed all those banner comments
Squashed the whole branch down to a single commit.
I think it's good to merge now ping! Thanks for taking the time to review this.

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