Skip to content

feat(omarchy): show session quota, weekly quota and weekly pace in the bar - #3794

Open
jsonMartin wants to merge 5 commits into
steipete:mainfrom
jsonMartin:feat/omarchy-bar-quota-and-pace
Open

jsonMartin wants to merge 5 commits into
steipete:mainfrom
jsonMartin:feat/omarchy-bar-quota-and-pace

Conversation

@jsonMartin

@jsonMartin jsonMartin commented Sep 20, 2026

Copy link
Copy Markdown
Contributor

TL;DR

The Omarchy bar now shows each provider's session limit, weekly limit and weekly pace, instead of one usage percentage. You can see your weekly usage and pace without opening a window. The bar follows your existing display settings and shows two providers by default. Each provider's text is longer than before, so the bar gets wider; see the question for the maintainer below. This builds on #3799.

What changes

  • The bar shows the session and weekly limits together, using the separator already used in the popup.
  • Weekly pace uses Core's existing calculation, never the pace of whichever limit has the least allowance left.
  • The used-or-remaining setting and Show pace preference also control the bar.
  • Show per-model caps in the bar is a new preference, off by default. These are extra limits for individual models.
  • Providers in the bar limits the displayed providers and counts the rest as +N. Hidden providers are still polled, listed in the popup, and notified about.
  • The bar keeps the provider's main allowance when several limits share a billing period.
  • The widget clears the previous response before polling, so a stopped backend cannot keep appearing to report its last usage.

For example, the bar can show:

5H 37% · 7D 61% · +14%

The first value is the 5-hour limit, and the next is the weekly limit. The last is weekly pace: how far usage is above or below Core's expected usage.

This synthetic snapshot compares Codex with weekly pace, Claude with an exhausted per-model weekly cap, Antigravity with its separate usage pools, and z.ai:

main this PR, default limit (2) this PR, All
summary (tray tooltip) CX 37% · CL 78% +2 CX 37% · CL 78% +2 CX 37% · CL 78% +2
barLabel (Omarchy bar) (not published) CX 5H 37% · 7D 61% · +14% · CL 5H 78% · 7D 11% +2 CX 5H 37% · 7D 61% · +14% · CL 5H 78% · 7D 11% · antigravity 5H 97% · 7D 93% · zai 5H 88% · 7D 70%

Question for the maintainer

The provider count stays at two after an upgrade, but each provider's text gets longer. Before: CX 37% · CL 78% +2. After: CX 5H 37% · 7D 61% · +14% · CL 5H 78% · 7D 11% +2. Is the wider default acceptable, or should upgrades keep the short one-percentage text until the user opts in? Either is a small change.

Details

Pace and display settings

The CLI already reports Core's signed pace value for each usage period. The shared model passes it through in the compact format used by MenuBarDisplayText.paceText; this PR does not recalculate it. The bar uses the weekly value only. If Core cannot calculate weekly pace, the bar leaves it out instead of showing a placeholder.

Limits are identified by their reported duration, as they are in Core, without hard-coded provider names. If a provider has no session limit, the bar omits that value and its separator. Percentages use the existing used-or-remaining preference; the widget does not invert them. Show pace controls both the bar and the native cards.

Per-model caps are off by default because most providers that report them repeat a general limit. They can be enabled with Show per-model caps in the bar.

Choosing which limits to show

These rules came from checking real provider output:

  • Antigravity reports separate session and weekly pools for each model family, marked with antigravity-quota-summary-* ids, and copies each family's most constrained pool into primary or secondary (AntigravityStatusProbe.swift:201). For each duration the bar uses the pool with the least allowance left, so an exhausted family cannot hide behind an unused one.
  • Antigravity has no general weekly limit. When a duration's only limit belongs to a model family, the bar uses it for that duration.
  • Antigravity can send an antigravity-compact-fallback-* window when neither family has a pool to show. That marked window stands in for the provider's quota. Other per-model extras without a duration do not.
  • Cursor bills its total, Auto/Composer and API usage over one billing cycle (CursorStatusProbe.swift:460). Sharing a duration does not make them the same limit, so the total stays the main quota even when a sub-limit has less left.
  • Kimi reports a subscription-only account's whole quota through extraRateWindows. The bar shows it instead of treating it as an optional per-model cap.
  • The popup's cap of eight extra limits keeps the tightest limit of each duration, and the marked fallback, first. A long list for one duration cannot push another duration out of the bar.

The tray tooltip uses the provider's own leading quota. If the provider reports its own quota, the tooltip skips a duration inferred from a per-model cap. For example, Cursor's monthly Total at 75% with an exhausted weekly Grok allowance reads cursor 75%, not cursor 0%.

Width and upgrades

Providers in the bar is under Settings → display. It defaults to two, the number shown before this PR, and counts the rest as +N. It only affects display: hidden providers are still polled, listed in the popup, and notified about. 0 (All) shows every provider where the display has room; four providers with session, weekly and pace take about 1500 logical pixels.

Depends on

This builds on #3799, which sits on main now that #3785 has merged (as 9d3f6bf54). GitHub's native stacked pull requests do not support cross-fork stacks, so this branch also carries #3799's commits. This PR's own change is commit 498aaac03. The branch has main merged in (at 1caaeb883) so it merges cleanly; once #3799 merges, the diff reduces to this PR's change.

This was rebuilt on the merged #3785. Extra keys are now extra:<id>. Fractional duration labels in the popup, notification identities and IPC key hashing from 9d3f6bf54 are unchanged. All tests added by #3785 on main are kept.

Proof

All data is synthetic. Each scenario runs the real codexbar-linux with --background --no-tray against a fake CLI, in an isolated HOME, and reads codexbar-linux --snapshot.

Installed Omarchy bar. This commit's Panel.qml was installed with install.py --omarchy on the Omarchy shell running on Hyprland. The synthetic backend served the real runtime socket, which the installed widget polls. The screenshot shows two providers and +2 for the other two, using the default display limit:

The snapshot table above shows that pace follows the weekly limit only. Claude's exhausted per-model cap stays out of the bar while Show per-model caps in the bar is off.

Upgrade. test_settings_from_before_the_bar_preferences_survive_an_upgrade starts the real binary with a linux.json written before these preferences existed. It sets custom order [claude, codex], quota shown as used, pace off, and refresh 600 s. The bar honours those settings, showing CL 5H 40% · CX 5H 40% in used mode. After an unrelated settings change, the file still contains those values plus showScopedCaps: false and barProviders: 2.

Tests

node --test Integrations/Omarchy/test.mjs Integrations/Omarchy/notifications.test.mjs  # 77 pass
CODEXBAR_LINUX_BINARY=<build of this commit> python3 -m unittest Integrations.Linux.tests.test_desktop  # 17 tests, OK
python3 Integrations/Omarchy/test_install.py       # OK
python3 Integrations/Linux/tests/test_package.py   # OK
omarchy plugin validate Integrations/Omarchy       # exit 0

CI never loads Panel.qml because Quickshell is not installed in the workflow. The widget is checked by screenshot. The label logic is tested in the JS model; the QML only displays it.

Notes for the maintainer

This is the largest PR in the set, with 766 lines added and 39 removed across nine files. The usage-limit model, selection rules, backend connection and widget need to arrive together for the bar to display the new values. I could not find a smaller shippable change.

The parts that can stand alone are separate PRs: the installer fix (#3784), extra rate windows (#3785) and provider logos (#3795).

@clawsweeper

clawsweeper Bot commented Sep 20, 2026

Copy link
Copy Markdown

🦞👀
ClawSweeper picked this up.

Pull request received. I will update this pull request when review starts.

ClawSweeper review complete

ClawSweeper finished reviewing this revision. The review result is being finalized.

View the workflow run.

@clawsweeper clawsweeper Bot added P2 Normal priority bug or improvement with limited blast radius. merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Sep 20, 2026
@clawsweeper

clawsweeper Bot commented Sep 20, 2026

Copy link
Copy Markdown

Codex review: blocked before merge. Reviewed September 21, 2026, 3:17 PM ET / 19:17 UTC (Revision 5).

ClawSweeper review

What this changes

Adds session and weekly quotas, weekly pace, provider-count controls, and optional per-model caps to the Omarchy bar, alongside quota-pool deduplication and polling cleanup.

Merge readiness

Blocked before merge - 3 items remain

Keep open: the feature remains distinct from current main and has convincing installed-bar proof. No blocking code defect was found; the previously identified product decision remains unresolved.

Priority: P2
Reviewed head: 1e87eafad9818cf5586c3d703d70f2c6aca4c4da
Owner decision: Required. See Decision needed.

Review scores

Measure Result What it means
Overall readiness 🐚 platinum hermit (4/6) A coherent implementation with strong visible proof and focused coverage; the outstanding upgrade-policy choice is separate from patch quality.
Proof confidence 🦞 diamond lobster (5/6) ✨ media proof bonus Sufficient (screenshot): The inspected installed Omarchy/Hyprland screenshot directly demonstrates Panel.qml rendering the backend’s session, weekly, pace, and +N output; reported real-binary snapshots and upgrade results supplement that visible proof. The current widget matches the previously reviewed widget blob.
Patch quality 🐚 platinum hermit (4/6) No actionable review findings were identified.

Verification

Check Result Evidence
Real behavior Verified Sufficient (screenshot): The inspected installed Omarchy/Hyprland screenshot directly demonstrates Panel.qml rendering the backend’s session, weekly, pace, and +N output; reported real-binary snapshots and upgrade results supplement that visible proof. The current widget matches the previously reviewed widget blob.
Evidence reviewed 9 items Introduced scope: Reviewed the pinned main-to-head delta across all 10 files, including the stacked Antigravity changes. The verified test merge records the pinned main and original head as its two parents.
Still needed on main: Current main renders the compact summary and has no detailed bar-label implementation. Existing popup quota information does not provide the requested persistent bar display.
Latest release comparison: The v0.64.0 widget also renders snapshot.summary rather than the new detailed label; the latest release does not supersede this feature.
Findings None None.
Security None None.

How this fits together

CodexBar’s Linux backend converts CLI usage results and saved display preferences into a private desktop snapshot. The Omarchy widget polls that snapshot to display quota information without running provider queries itself.

flowchart LR
  A[CLI usage and pace] --> C[Shared quota model]
  B[Saved display preferences] --> D[Linux desktop backend]
  C --> D
  D --> E[Private desktop snapshot]
  E --> F[Omarchy bar and popup]
  D --> G[Native tray and notifications]
Loading

Decision needed

Question Recommendation
Should existing Omarchy installations automatically adopt detailed quota labels, or retain compact labels until users opt in? Preserve compact upgrades: Retain compact text for existing installations and expose detailed labels as an explicit display choice.

Why: The contributor explicitly leaves this choice open, and successful rendering on one desktop cannot establish an acceptable default for existing bar layouts.

Before merge

  • Resolve merge risk (P1) - Existing Omarchy installations automatically receive longer labels, which can crowd neighboring widgets; the two-provider limit does not preserve the previous width, and maintainer acceptance remains outstanding.
  • Complete next step (P2) - Record maintainer acceptance of wider labels on upgrade, or preserve compact upgrade behavior before merge.
  • Resolve maintainer decision - Resolve the maintainer decision shown above before merge.
Agent review details

Security

None.

Review metrics

Metric Value Why it matters
Production and test delta Production +286/-21 lines; tests +565/-14 lines The stated production growth covers shared quota selection, backend preferences, and widget integration, with substantial regression coverage.

Merge-risk options

Maintainer options:

  1. Keep existing bar layouts compact (recommended)
    Add an explicit detailed-label choice while preserving compact text for upgraded installations.
  2. Approve the wider upgrade default
    Record maintainer acceptance that upgraded bars may require layout adjustment despite retaining the two-provider limit.

Technical review

Best possible solution:

Keep the shared backend formatting and preserve compact labels on upgrade unless maintainers explicitly approve the wider default.

Do we have a high-confidence way to reproduce the issue?

Not applicable to the central feature request; main and v0.64.0 source establish the compact-only bar behavior, and supplied installed-bar proof demonstrates the proposed display.

Is this the best way to solve the issue?

Yes, formatting in the shared backend and reusing CLI pace values is a coherent approach; the appropriate upgrade default still requires a product choice.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning medium; reviewed against 1caaeb8837dd.

Labels

Label justifications:

  • P2: This is a bounded Linux/Omarchy display improvement with no demonstrated urgent runtime failure.
  • merge-risk: 🚨 compatibility: The unconditional detailed-label default changes existing bar layouts on upgrade without recorded maintainer acceptance.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🦞 diamond lobster and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (screenshot): The inspected installed Omarchy/Hyprland screenshot directly demonstrates Panel.qml rendering the backend’s session, weekly, pace, and +N output; reported real-binary snapshots and upgrade results supplement that visible proof. The current widget matches the previously reviewed widget blob.
  • proof: sufficient: Contributor real behavior proof is sufficient. The inspected installed Omarchy/Hyprland screenshot directly demonstrates Panel.qml rendering the backend’s session, weekly, pace, and +N output; reported real-binary snapshots and upgrade results supplement that visible proof. The current widget matches the previously reviewed widget blob.
  • proof: 📸 screenshot: Contributor real behavior proof includes screenshot evidence. The inspected installed Omarchy/Hyprland screenshot directly demonstrates Panel.qml rendering the backend’s session, weekly, pace, and +N output; reported real-binary snapshots and upgrade results supplement that visible proof. The current widget matches the previously reviewed widget blob.

Evidence

What I checked:

  • Introduced scope: Reviewed the pinned main-to-head delta across all 10 files, including the stacked Antigravity changes. The verified test merge records the pinned main and original head as its two parents. (1e87eafad981)
  • Still needed on main: Current main renders the compact summary and has no detailed bar-label implementation. Existing popup quota information does not provide the requested persistent bar display. (Integrations/Omarchy/Panel.qml:43, 1caaeb8837dd)
  • Latest release comparison: The v0.64.0 widget also renders snapshot.summary rather than the new detailed label; the latest release does not supersede this feature. (Integrations/Omarchy/Panel.qml:43, 3703a72b6b66)
  • Installed visual proof: Inspected the prepared screenshot linked in the captured PR body. It visibly shows CX session/weekly quotas and +14% pace, CL session/weekly quotas, and +2 hidden providers. The contributor describes installation on Omarchy/Hyprland with synthetic data served through the runtime socket. The current Panel.qml blob matches the previously reviewed 498aaac revision. (Integrations/Omarchy/Panel.qml:48, 1e87eafad981)
  • Upgrade coverage and remaining choice: The native upgrade test preserves custom provider order, used-quota display, disabled pace, and refresh interval while adding conservative defaults for the two new settings. However, Panel.qml selects the detailed label unconditionally. The captured body explicitly asks whether upgrades should receive wider text; supplied discussion and live review/comment reads contain no maintainer acceptance. (Integrations/Linux/tests/test_desktop.py:188, 1e87eafad981)
  • Earlier findings addressed: Current code retains cadence representatives before truncating extra windows and excludes inferred per-model allowances from the tray headline when a provider quota exists. Logo documentation is absent from the introduced README changes. The remaining prior rank-up item is the upgrade-width decision. (Integrations/Linux/Shared/Usage.js:190, 1e87eafad981)

Likely related people:

  • Peter Steinberger: Suggested for follow-up; no historical authorship or introduction is verified. (role: unverified routing candidate; confidence: low)
  • unknown: The claimed source-line change could not be verified from bounded local history. (role: source history unknown; confidence: low)

Rank-up moves

Optional improvements that raise the rating; they are not merge blockers.

  • Resolve whether upgrades retain compact labels or intentionally adopt the wider detailed default.

Rating scale

Score Internal tier Crab rank Meaning
6/6 S 🦀 challenger crab Exceptional readiness
5/6 A 🦞 diamond lobster Very strong readiness
4/6 B 🐚 platinum hermit Good normal PR; ordinary maintainer review
3/6 C 🦐 gold shrimp Useful, but confidence is limited
2/6 D 🦪 silver shellfish Proof or implementation needs work
1/6 F 🧂 unranked krab Not merge-ready
N/A NA 🌊 off-meta tidepool Rating does not apply

Overall follows the weaker of proof and patch quality.
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

Workflow

  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

History

Review history (4 earlier review cycles)
  • reviewed 2026-09-20T23:19:00.179Z sha f9d9e98 :: needs real behavior proof before merge. :: [P2] [P2] Preserve cadence representatives before truncating extras | [P3] [P3] Move logo documentation to the logo implementation
  • reviewed 2026-09-21T05:21:16.091Z sha 4bb8cc5 :: needs real behavior proof before merge. :: [P2] [P2] Preserve the provider quota in the tray headline | [P3] [P3] Move logo documentation to the logo implementation
  • reviewed 2026-09-21T06:55:47.048Z sha 498aaac :: blocked before merge. :: none
  • reviewed 2026-09-21T07:18:30.487Z sha 498aaac :: blocked before merge. :: none

Antigravity reports every pool as a quota-summary extra and copies the tightest
pool of each model family into its positional windows. The popup listed both,
so each representative appeared twice: once under a bare cadence label and
again under its family title.

Show each representative in its positional slot under its family title and drop
its extra copy. The representatives stay first, so the tray meters and summary
still report the binding pools, and the extra limit can no longer hide one. The
row keeps the pool's own key, so alert history follows a pool when another
becomes binding, and families are matched as Core selects them so equal values
cannot borrow another family's title.
@jsonMartin
jsonMartin force-pushed the feat/omarchy-bar-quota-and-pace branch from f9d9e98 to 4bb8cc5 Compare September 21, 2026 05:15
@jsonMartin
jsonMartin marked this pull request as ready for review September 21, 2026 05:16
@clawsweeper clawsweeper Bot added rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. labels Sep 21, 2026
…e bar

The bar showed one quota per provider and no pace, so the weekly burn rate was
only visible by opening a window. Show each provider's session quota, weekly
quota and weekly pace.

Nothing here recomputes pace. The CLI already emits a signed delta per window,
produced by Core, so the shared model carries it through and renders it in the
compact form of MenuBarDisplayText.paceText. The pace shown is the weekly
window's, never whichever lane is most constrained, and a pace Core cannot
compute contributes no segment rather than a placeholder that reads like data.

Lanes are resolved from the cadence a provider reports, the way Core's semantic
windows do, so no provider name is hard-coded and a provider without a session
window emits neither that segment nor its separator. Three rules came out of
testing against real provider shapes rather than from design:

- Antigravity marks a per-family summary set with quota-summary ids, and its
  positional window is only whichever family represents them, so a tighter
  family was hidden behind it. Matching on that marker rather than on
  percentages matters: Claude's general weekly can coincide with one of its
  per-model caps, and reading that coincidence as a summary replaced the general
  quota with a cap scoped beneath it.
- Kimi delivers a subscription-only account's entire quota through
  extraRateWindows, so treating every extra as an optional sub-cap dropped it.
- Cursor bills its total, its Auto/Composer usage and its API usage over one
  cycle, so keeping only the tightest of a duration replaced the headline quota
  with a subquota.

Percentages run through the existing quota preference, so the bar follows the
used or remaining setting without the adapter inverting anything, and the
existing Show pace preference now governs the bar as well as the native cards.
Caps scoped to a single model are off by default behind a new preference, since
most providers that publish them restate a general lane.

A new Providers in the bar preference bounds how many providers the bar shows,
two by default, and counts the rest, so an upgrade cannot widen an existing
multi-provider bar. It is display only: every configured provider is still
polled and listed in the popup. At the default font each character occupies
roughly 7 logical pixels, so four providers each showing a session lane, a weekly
lane and a pace come to about 1500 logical pixels; the README says so, and 0
shows every provider where the display has room.

The tray tooltip names the provider's own leading quota. A cadence the bar
derives from a per-model cap is skipped while the provider reports a quota of its
own, so Cursor's exhausted weekly Grok allowance cannot read as an exhausted
account in a tooltip that carries no lane name.

The adapter also stopped reusing a previous poll's body, which let a backend that
had gone away keep reporting the quota it last had.
@jsonMartin
jsonMartin force-pushed the feat/omarchy-bar-quota-and-pace branch from 4bb8cc5 to 498aaac Compare September 21, 2026 06:51
@clawsweeper clawsweeper Bot added proof: sufficient Contributor real behavior proof is sufficient. proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. labels Sep 21, 2026
…up-duplicates

# Conflicts:
#	Integrations/Linux/Shared/Usage.js
#	Integrations/Linux/tests/test_desktop.py
# Conflicts:
#	Integrations/Linux/Shared/Usage.js
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. P2 Normal priority bug or improvement with limited blast radius. proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. proof: sufficient Contributor real behavior proof is sufficient. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant