Skip to content

Add opt-in quota colors for menu bar meters - #5072

Open
mccaly wants to merge 2 commits into
steipete:mainfrom
mccaly:menu-bar-quota-colors
Open

mccaly wants to merge 2 commits into
steipete:mainfrom
mccaly:menu-bar-quota-colors

Conversation

@mccaly

@mccaly mccaly commented Nov 12, 2026

Copy link
Copy Markdown

Summary

Adds an opt-in Color bars by quota left toggle under Settings → Menu Bar → Icon (default off). When it is on, each meter bar in the Critters and Meter bars styles is drawn by how much of that quota is left:

  • green with 50% or more left
  • orange from 25%
  • red below 25%
  • gray for a lane without a value

This is meant as a different request from #3533 (provider-colored meters, closed as not planned): the color carries quota state, like Color Pace Indicator (#3429), rather than brand identity. It follows #3429's shape (one toggle, off by default) and reuses the contrast policy raised in #3533.

Quota colors proof

Synthetic proof rendered through IconRenderer.makeIcon (Claude critter, light and dark rows, default vs. quota colors); see IconRendererQuotaColorTests.

Behavior

  • Thresholds use the percentage left. With Show usage as used, colors still follow the quota left.
  • Contrast fallbacks match MenuBarLayoutRenderer.effectiveProviderTintColor: the meter returns to the monochrome template while the menu is open (highlighted), data is stale or loading, the inactive-display contrast option or system Increase Contrast is on, or the appearance is an accessibility appearance or unknown.
  • Shades are fixed sRGB per light and dark menu bar (darker on light bars, brighter on dark bars), and each passes meetsAppearanceContrast (2:1 against the 85% / 25% gray references). System green and orange fail that check on light bars, hence fixed shades.
  • Default rendering is unchanged. Without the setting, makeIcon returns the same template image. The color style is part of the icon cache key and the status item render signature, so toggling the setting or an appearance change redraws.
  • Scope: Icon & percent shows the brand icon, so the toggle is disabled there. With Color by provider also on, the meter uses quota colors. Like provider colors, a colored image is not dimmed by the system on inactive displays; the existing inactive-display contrast option turns quota colors off.

Changes

  • IconRenderer+QuotaColors.swift: QuotaColorStyle (levels, shades, render signature) and effectiveQuotaColorStyle(options:increasedContrast:isLoading:).
  • IconRenderer.makeIcon(..., quotaColors:): per-bar colors, non-template image only when colors apply, status overlay drawn in the neutral shade.
  • StatusItemController: computes the style from the existing render options and passes it to the meter icon.
  • Settings: menuBarColorByQuota (default off, persisted, part of menu observation) and the toggle in the Menu Bar pane.
  • Two strings in all 23 catalogs, docs/ui.md, and a CHANGELOG entry.

Commands run

  • Scripts/install_lint_tools.sh swiftformat swiftlint, then swiftformat and swiftlint lint --strict on the touched files: clean
  • node Scripts/check-app-locales.mjs and node Scripts/sync-widget-locales.mjs --check: OK
  • source Scripts/test_environment.sh && swift test --filter "IconRendererQuotaColorTests|MenuBarQuotaColorSettingsTests|IconRendererHideCrittersTests|IconRendererStatusOverlayTests|MenuBarPaceColorSettingsTests|MenuBarLayoutRendererTests|ProviderArchitectureGatekeeperTests|IconRendererGrokTests": 190 tests in 8 suites passed (Xcode 26.6 / Swift 6.3.3; the test target needed raised -solver-*-threshold limits to type-check existing upstream tests on this older toolchain)
  • Proof: CODEXBAR_QUOTA_COLOR_PROOF_DIR=.github/pr-proof swift test --filter IconRendererQuotaColorTests

Not run locally: make test-fast / make test. The test harness requires a python3 with os.waitid, and this machine only has 3.11 and 3.9, so the full suite is left to PR CI. make check ran its lint and script tests but stops at the same os.waitid precondition.

Notes

  • The two new strings were translated with AI assistance; corrections from native speakers are welcome.
  • Live menu-bar check: an earlier always-on build of this coloring has been running on macOS 26.3.1. This opt-in version is covered by the tests and proof render above.

🤖 Generated with Claude Code

Add "Color bars by quota left" under Menu Bar → Icon, off by default. When
on, each meter bar is green with 50% or more left, orange from 25% and red
below 25%; a lane without a value is gray. Colors follow the quota left
even with "Show usage as used".

Quota colors reuse the provider-color fallbacks: the meter stays a
monochrome template while highlighted, stale or loading, with increased
contrast, or in accessibility appearances. Shades are fixed per light and
dark menu bar and each passes meetsAppearanceContrast. The color style is
part of the icon cache key and status item render signature.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@clawsweeper

clawsweeper Bot commented Nov 12, 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.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 12, 2026 •

Copy link
Copy Markdown
Codex Review Summary: ✅ Completed

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-12T18:15:29.121038Z 3330a5c PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3330a5c6f0

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

func quotaColorStyle(for provider: UsageProvider, button: NSButton, isLoading: Bool) -> IconRenderer
.QuotaColorStyle?
{
guard self.settings.menuBarColorByQuota else { return nil }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Re-render quota-only icons on color-mode changes

When users enable only Color bars by quota left (while Color by provider remains at its default off value), menu tracking, appearance KVO, and Increase Contrast notifications all call refreshStatusItemContentForColorMode, but that helper still returns unless menuBarColorByProvider is enabled. Consequently this state-dependent style is not recomputed when a menu opens/closes or the appearance/accessibility mode changes, so the non-template colored icon can remain highlighted or retain light-mode shades in dark mode until some unrelated icon update; the refresh gate needs to accept either color option.

Useful? React with 👍 / 👎.

warpEyesFilled: Bool = false)
{
// With quota colors the whole bar (track, outline, fill and critter details) uses its color.
let baseFill = quotaColors.map { $0.color(forBarValue: remaining) } ?? monochromeFill

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep credits fallback colors based on remaining credits

With Show usage as used enabled and Codex rendering its credits-only fallback (for example, credits have loaded before a usage snapshot), creditsRatio in this renderer is still derived from creditsRemaining, but this line sends it through a style that complements every value as though it were percent used. That inverts the threshold color—a nearly full credits bar can become red and a nearly empty one green—so the credits lane must be identified as already representing percent left when its color is selected.

Useful? React with 👍 / 👎.

hideCritters: self.settings.menuBarHidesCritters,
quotaLayoutPolicy: .provider(provider, snapshot: snapshot))
quotaLayoutPolicy: .provider(provider, snapshot: snapshot),
quotaColors: quotaColors)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Apply quota colors to user-plugin meters

When the unified icon's current selection is a user provider plugin in Critters/Meter bars mode, applyIcon takes the plugin branch at lines 265-310 and returns after calling IconRenderer.makeIcon without quotaColors, so this new argument is reached only for built-in providers. Plugin snapshots already supply primary and secondary percentage lanes via pluginMeterPercents, yet enabling the global quota-color toggle leaves those meter bars monochrome; compute and pass the same style in the plugin branch as well.

Useful? React with 👍 / 👎.

@clawsweeper clawsweeper Bot added clawsweeper:intake:feature Preliminary submission classification; full source review pending. P3 Low-risk cleanup, docs, polish, ergonomics, or speculative feature. proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. and removed clawsweeper:intake:feature Preliminary submission classification; full source review pending. labels Nov 12, 2026
@clawsweeper

clawsweeper Bot commented Nov 12, 2026

Copy link
Copy Markdown

Codex review: needs real behavior proof before merge.

What this changes

Adds an off-by-default setting that colors menu bar meters green, orange, or red according to remaining quota.

Example: Claude has 80% session quota and 30% weekly quota remaining.

  • Before: Both meter bars use monochrome rendering.
  • After: Enabling the new setting makes the session bar green and the weekly bar orange.

Review scores

Measure Result What it means
Overall readiness 🧂 unranked krab (1/6) The renderer demonstration supports the visual idea, but required app proof is absent and concrete integration defects remain.
Proof confidence 🧂 unranked krab (1/6) Real behavior proof is necessary before merge. See Before merge.
Patch quality 🦪 silver shellfish (2/6) 4 actionable review findings remain.

Product

Kind: Feature · Worth it: Needs a maintainer decision
User problem: Users must inspect bar lengths to distinguish healthy and nearly exhausted quotas at a glance.
Reason: Quota urgency is distinct from provider identity and pace, but another persisted appearance setting requires an owner decision.

Merge readiness

⛔ Blocked before merge - 5 items remain

Keep open for a maintainer decision on the new color preference; lifecycle, credits, plugin coverage, and cache defects need correction.

Priority: P3
Reviewed head: 3330a5c6f0085a2bb6725612996ec6616108ed21
Owner decision: Required. See Decision needed.

Decision needed

  • Question: Should CodexBar add a separate off-by-default quota-threshold color preference alongside provider and pace colors?
  • Recommendation: Accept the narrow quota-color preference: Approve the remaining-quota meaning and default-off setting, subject to the listed implementation and validation work.
  • Why: This introduces a new persisted visual option without recorded owner approval; the approvals on the related color features cover different meanings and surfaces.

Before merge

  • Add real behavior proof - The inspected image exercises IconRenderer directly with synthetic values, bypassing the new Settings control and production status-item lifecycle; the earlier always-on build and older pace screenshots do not prove this head. No fresh-install or latest-stable upgrade run covers the persisted menuBarColorByQuota preference, although source defaults an absent key to false without rewriting existing keys. After adding proof, update the PR body, then request a new review with @clawsweeper re-review. The PR author or someone with repository write access can request it.
  • Refresh status-item content when quota colors are enabled (P2) - With quota colors enabled and provider colors disabled, menu tracking, appearance changes, and Increase Contrast notifications reach refreshStatusItemContentForColorMode but return at its provider-only guard. The new style therefore retains colored output during highlighting or obsolete appearance shades until another icon update. Allow either color preference to activate the existing refresh path. This also confirms the existing inline review concern.
  • Keep credits fallback colors based on remaining credits (P2) - In used-display mode, QuotaColorStyle complements every drawBar value. Credits fallback values are already remaining percentages: 900 credits produces a 90% bar against the existing 1000-credit cap, but is colored as 10% left and becomes red; 100 credits becomes green. Preserve the credits lane's remaining-value semantics when selecting its color instead of applying the quota-window conversion.
  • Apply the global quota-color setting to plugin meters (P2) - Selecting a user provider plugin in Meter bars mode takes the earlier plugin branch, which calls makeIcon at lines 292–298 without quotaColors and returns before this new argument is supplied. A plugin reporting 10% remaining consequently stays monochrome while built-in meters become red under the same global setting. Resolve the style through the existing instance-ID render options and pass it through the plugin meter path too.
  • Add data-model compatibility proof - The review found that existing stored data may not work after upgrade. Show that existing data still loads and works with this change.

Findings

  • [P2] Refresh status-item content when quota colors are enabled — Sources/CodexBar/StatusItem/StatusItemController+MenuBarLayout.swift:173-178
  • [P2] Keep credits fallback colors based on remaining credits — Sources/CodexBar/IconRenderer.swift:185-186
  • [P2] Apply the global quota-color setting to plugin meters — Sources/CodexBar/StatusItem/StatusItemController+Animation.swift:529-532

Tests

  • Low-value test Tests/CodexBarTests/IconRendererQuotaColorTests.swift: Remove signature distinguishes appearance and used mode: it checks the cardinality of a directly constructed string helper rather than catching a distinct rendering or consumer failure.
  • Missing end-to-end proof: Provide current-head app screenshots or a recording showing the setting and actual meter transitions, including menu and appearance/accessibility changes, plus a latest-stable upgrade preserving settings; redact personal information and credentials.
Agent review details

How this fits together

Provider snapshots and saved display preferences enter the status-item controller, which selects quota values and rendering options and sends rendered images to the macOS menu bar.

flowchart LR
 A[Provider snapshots] --> C[Status item controller]
 B[Saved display preferences] --> C
 D[Appearance and menu state] --> C
 C --> E[Icon renderer and cache]
 E --> F[Menu bar button]
Loading

Technical review

Best possible solution:

If the owner accepts this preference, complete it within the existing renderer and lifecycle paths, preserving remaining-quota semantics, plugin coverage, and threshold-aware caching.

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

This proposes new behavior rather than reporting a current-main bug; the introduced defects have concrete source paths but were not executed during this read-only review.

Is this the best way to solve the issue?

Extending the existing renderer is appropriately scoped, but the proposal needs owner approval and complete integration with existing refresh, credits, plugin, and cache behavior.

Full review comments:

  • [P2] Refresh status-item content when quota colors are enabled — Sources/CodexBar/StatusItem/StatusItemController+MenuBarLayout.swift:173-178
    With quota colors enabled and provider colors disabled, menu tracking, appearance changes, and Increase Contrast notifications reach refreshStatusItemContentForColorMode but return at its provider-only guard. The new style therefore retains colored output during highlighting or obsolete appearance shades until another icon update. Allow either color preference to activate the existing refresh path. This also confirms the existing inline review concern.
    Confidence: 0.99
  • [P2] Keep credits fallback colors based on remaining credits — Sources/CodexBar/IconRenderer.swift:185-186
    In used-display mode, QuotaColorStyle complements every drawBar value. Credits fallback values are already remaining percentages: 900 credits produces a 90% bar against the existing 1000-credit cap, but is colored as 10% left and becomes red; 100 credits becomes green. Preserve the credits lane's remaining-value semantics when selecting its color instead of applying the quota-window conversion.
    Confidence: 0.99
  • [P2] Apply the global quota-color setting to plugin meters — Sources/CodexBar/StatusItem/StatusItemController+Animation.swift:529-532
    Selecting a user provider plugin in Meter bars mode takes the earlier plugin branch, which calls makeIcon at lines 292–298 without quotaColors and returns before this new argument is supplied. A plugin reporting 10% remaining consequently stays monochrome while built-in meters become red under the same global setting. Resolve the style through the existing instance-ID render options and pass it through the plugin meter path too.
    Confidence: 0.98
  • [P3] Include quota levels in the cached icon identity — Sources/CodexBar/IconRenderer.swift:885-886
    The cache still rounds quota percentages to tenths, while colors use exact 25% and 50% boundaries. Rendering 25.00% and then 24.99% with the same other inputs produces the same cache key, so the second call returns the orange image instead of red. Include the resolved lane color levels in cache identity so quantization cannot cross a color threshold.
    Confidence: 0.99

Overall correctness: patch is incorrect
Overall confidence: 0.98

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning medium; reviewed against 7447bc77c249.

Provenance checked

  • Monochrome meter rendering changes intended behavior with a stated reason (unknown: The base explicitly uses template images for native monochrome rendering; later provider-color work preserves that path for selected, stale, and accessible states. The PR explains its opt-in departure. A deeper historical git show failed on an unavailable blob, so the original introduction is not established.)
  • Icon cache keeps the original intent (ed99fab: The supplied provenance identifies performance caching as the reason; this PR retains the cache and adds color style to its identity.)

Testing

Proof path: in-process harness.

Security

None.

Evidence

What I checked:

Likely related people:

  • Peter Steinberger: Raw commit fc046bf adds Sources/CodexBar/StatusItemController+MenuBarLayout.swift:160 relative to its recorded parents. This identifies author metadata, not feature responsibility or a PR merger. (role: source-line author; confidence: high; commits: fc046bfd8aae; files: Sources/CodexBar/StatusItemController+MenuBarLayout.swift)
  • David Aronchick: Raw commit fd7fab6 adds Sources/CodexBar/StatusItemController+MenuBarLayout.swift:154 relative to its recorded parents. This identifies author metadata, not feature responsibility or a PR merger. (role: source-line author; confidence: medium; commits: fd7fab6cee00; files: Sources/CodexBar/StatusItemController+MenuBarLayout.swift)

Preflight source

Source unknown. Source comparison at the observed PR snapshot only. Completion is self-reported; body, policy, tests, execution, and report bytes are not verified.

Labels

Label changes:

  • add P3: This is optional menu bar presentation work with an unchanged default and no reported broken upstream workflow.
  • add proof: 📸 screenshot: Contributor real behavior proof includes screenshot evidence.
  • add rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🧂 unranked krab and patch quality is 🦪 silver shellfish.
  • add status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Label justifications:

  • P3: This is optional menu bar presentation work with an unchanged default and no reported broken upstream workflow.
  • rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🧂 unranked krab and patch quality is 🦪 silver shellfish.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask.
  • proof: 📸 screenshot: Contributor real behavior proof includes screenshot evidence.

Rating scale

6/6 🦀 challenger crab · 5/6 🦞 diamond lobster · 4/6 🐚 platinum hermit · 3/6 🦐 gold shrimp · 2/6 🦪 silver shellfish · 1/6 🧂 unranked krab. Overall follows the weaker of proof and patch quality; ✨ marks media proof (a screenshot, video, or linked artifact) that directly shows the changed behavior.

Workflow

ClawSweeper edits this one comment on every review. Comment @clawsweeper re-review for a fresh review only. Repair and merge execution lanes are retired.

Reviewed November 12, 2026, 1:26 PM ET / 18:26 UTC.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

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

Labels

P3 Low-risk cleanup, docs, polish, ergonomics, or speculative feature. proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant