Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

feat(plugins): feed plugin snapshots into the menu bar layout renderer

Open
#4,789 3 comments 1 reaction 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
5/5
Estimated time
Over a week
Newbie friendliness
35/100
Issue type
Feature
Clarity
Mostly clear
Activity status
Active
Tech stack
swift

Research direction

Start with StatusItemController+Animation.swift and the UsageStore.menuBarLayoutRenderData(provider:…), menuBarLayoutWindows(provider:…), and renderedMenuBarLayoutResolution(for:) paths named in the issue. Read the related work in #4761, #4763, #4720, #4784, and #4787, then adapt the #4761 end-to-end test for countdown scheduling and reset-only refreshes. Done when plugin snapshots flow through the shared layout renderer with the described window, reset, ordering, separator, conditional, cached rendering, and balance behavior.

Written by the indexing model from the issue text.

Description

clawsweeper:fix-shape-clear clawsweeper:needs-maintainer-review clawsweeper:needs-product-decision clawsweeper:no-new-fix-pr clawsweeper:source-repro impact:ux-friction issue-rating: 🦞 diamond lobster P3

With Merge icons on, Combined icon source set to Current selection, and a user plugin selected, the merged icon shows only the plugin icon and its percentage (the plugin branch of the merged applyIcon in StatusItemController+Animation.swift). Apart from the window picked with Menu bar metric (#4784), the menu bar layout (reset tokens, order, separators, window-specific tokens, conditionals) applies only to built-in providers, so the Percent + reset layout renders 69% · in 1d 12h for Claude and 37% for a plugin.

When closing #4761 and #4763 you described the shape that fits: plugin snapshots feed the existing layout renderer through one adapter, so order, separators, window selection, and the cached rendering from #4720 keep working. The same adapter carries plugin balance: a menuBarBalanceUsesPrepaidCost manifest flag read from the current manifest, with the amount going through the shared balance extractor and formatter, and the adapter itself not depending on that opt-in.

Today the layout path takes a UsageProvider end to end: UsageStore.menuBarLayoutRenderData(provider:…) and menuBarLayoutWindows(provider:…) build the data, MenuBarLayoutRenderData.provider drives the renderer's descriptor lookups (named-extra titles, lane labels, the reset-text fallback in MenuBarLayoutResetText), and renderedMenuBarLayoutResolution(for:) feeds rendering, the observation signature, and the countdown timers. Plugins arrive as a ProviderInstanceID whose firstPartyProvider is nil, which is why #4761 and #4763 each added a side path.

I'd be glad to build the adapter if you want an outside PR for it. Two questions before I start:

  1. Identity. #4763 built its render data with provider: .synthetic as a stand-in, so the renderer's descriptor lookups read the Synthetic provider's metadata. I'd rather have the render data and layout resolution take a ProviderInstanceID, keep the descriptor lookups for built-ins, and have the adapter map plugin windows, titles, and reset text from the snapshot, with balance going through MenuBarLayoutBalanceResolver. Does that match what you had in mind, or would you prefer a different seam?
  2. Which layout. #4784 saves each plugin's Menu bar metric as its own layout in the existing overrides, and menuBarLayout(forPlugin:) defaults to a lone .percent(window: .automatic), with no .icon, rather than the global layout. Should a plugin without its own layout fall back to the global layout like a built-in provider, with the metric picker saving an override as it does for built-ins? Or should plugins keep a separate layout, which needs an icon in its default and a plugin scope in the layout editor? #4784 hasn't shipped, so either default can change without migrating saved plugin layouts.

The end-to-end test from #4761 (countdown scheduling, plus a reset-only refresh through the real store observer) covers behavior the adapter has to keep, and can be adapted as its regression test. If you'd rather build this yourself, that works too; this issue is just to track it.

Related: #4787 fixes the plugin observation signature so a refresh that changes only the chosen Menu bar metric window redraws; the adapter would take over that signature.

cc @AaronJiTuo, since the same adapter would carry the plugin balance from #4763.

Refs #4761, #4763, #4720, #4784, #4787

🤖 Drafted with Claude Code; reviewed by me.

Dominant language
Swift
Stars
22.8k
Forks
2.2k
Avg merge
22h 20m
Merged PRs (30d)
380

Getting set up

This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from steipete/CodexBar

All issues in steipete/CodexBar

Similar issues

More Swift issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.