Skip to content

Repository files navigation

Left

Left is a small macOS menu-bar view of how much Claude Code, ChatGPT/Codex, and Grok allowance you have left. The menu bar carries each provider at once — each one's own mark against its own tightest remaining percentage — and the overlay shows every session, weekly, model, and credits window on one compact dark surface: one line each, no scrolling, no empty space under the last row.

The Left status item: Claude, ChatGPT/Codex, and Grok marks with remaining percentages

Left showing stale Claude data and live Codex and Grok windows

Claude, ChatGPT, and Grok marks are trademarks of Anthropic, OpenAI, and xAI. Left is not affiliated with, endorsed by, or sponsored by those companies. The numbers in these screenshots come from Fixtures/demo-quota.json, a synthetic fixture invented for tests and docs — not a dump from a live account.

Left reads quota-axi's normalized JSON. It does not implement provider authentication, store tokens, or call provider APIs itself.

The app was called UsageBar until 2026-07-28; docs/naming.md records why it is Left, and what the rename deliberately left alone.

Install

Requirements:

  • macOS 13 or newer
  • Swift from Xcode or the Xcode command-line tools
  • quota-axi 0.1.6 or newer on PATH

From this checkout, build, package, install, and launch the app with one command:

./scripts/install.sh

The default destination is ~/Applications/Left.app. Pass an explicit destination or skip launch when needed:

./scripts/install.sh \
  --destination "$PWD/.build/Left.app" \
  --no-launch

The installer builds the app, renders its icon from the app's own mark, ad-hoc signs the bundle, and verifies the signature. Before replacing anything it quits whatever is running from the old and new bundles, so only one instance survives, and it moves — never deletes — any existing Left.app and any pre-rename UsageBar.app into ~/Library/Application Support/Left/Rollbacks as a timestamped *.previous.<stamp>.app. Copies stay there rather than beside ~/Applications/Left.app, so LaunchServices does not register a second claimant of the same identifier. Rolling back is moving that bundle back to the install path and opening it.

The installer registers no login item and no launch agent: whether Left starts at login is yours to set, and the rename does not touch it. It never changes subscription credentials.

If quota-axi is missing, install the researched release explicitly:

npm install -g quota-axi@0.1.13

Claude Code may eventually need a one-time Keychain grant after its file token expires. Left shows that stale state, the provider's own reason for it, and an allowlisted repair command, instead of prompting or changing access itself.

Try the local fixture

Fixtures/demo-quota.json is synthetic: round invented percentages and generic plan labels, not a live account dump. It exercises live and stale states without reading credentials:

swift run Left --fixture Fixtures/demo-quota.json

Render the overlay, the menu-bar readout, or the app icon:

swift run Left --render-preview Fixtures/demo-quota.json docs/demo.png
swift run Left --render-status Fixtures/demo-quota.json docs/menubar.png
swift run Left --render-iconset .build/Left.iconset

docs/demo.png and docs/menubar.png are committed evidence; verify.sh compares both byte for byte, so re-render them whenever the surface changes.

Verify

./scripts/verify.sh

Verification runs the parser, state, layout, contrast, and mark tests, builds release mode, packages and signs a temporary app, exercises the UsageBarLeft migration and its rollback copy, checks the bundle identifier and icon, asserts no login-item machinery, re-renders the overlay at 340 × 430 and the menu-bar readout and compares both to the committed evidence, scans for common secret patterns, and checks the Git diff.

Smoke test after installing

verify.sh cannot click things or read the menu bar. After an install, check these five by hand — they take under a minute:

  1. The menu bar shows Claude's own mark with its percentage, ChatGPT's own mark with Codex's, and Grok's own mark with its remaining percentage — three glyphs, nothing clipped. They are the vendors' published logos, recognisable at a glance rather than a shape standing in for one. The readout inverts correctly on a light menu bar and under click highlight, because the whole thing is one template image.
  2. Clicking it opens the overlay. Every allowance window is visible at once; nothing scrolls, and the footer sits directly under the last row rather than below a void.
  3. The header reads Left · checked … ago, and it is the only place on the surface that says how current the data is.
  4. Pressing Refresh updates that statement to checked just now.
  5. ~/Library/Application Support/Left/Rollbacks/Left.previous.<stamp>.app (or UsageBar.previous.<stamp>.app after a rename install) still exists. That is the rollback: quit Left, move that bundle back to ~/Applications/Left.app (or UsageBar.app), and open it.

The interface

  • One line per allowance window, on a fixed grid: label, a continuous rail, the exact remaining percentage, and the exact reset countdown. Every window is visible at once; the layout tests hold that promise (PopoverLayoutTests), including the worst case where every provider is unhealthy and a global error banner is showing.
  • Rails are monochrome. Colour is reserved for state: amber at 25% or less, red at 10% or less, and for a provider that is stale, unauthenticated, rate limited, or broken. Nothing else on the surface is coloured.
  • Freshness is stated once, in the header, from the last successful check. A provider's own badge ages only what is stale (12m OLD).
  • Plain language, never the provider's. Upstream reasons like keychain_access_required are translated (Last good reading 12m ago · keychain blocked) and untranslatable jargon is dropped rather than printed. The raw string stays in the row's tooltip. PlainLanguage.swift owns every sentence the overlay says about a state.
  • Left's own mark is drawn in code; the providers' are theirs. LeftCore/LeftMark.swift is the app's own mark — an open ring, one shape, whose sweep is a constant because the mark is identity and the numbers beside it are data. The provider marks are Anthropic's, OpenAI's, and xAI's official logos, vendored from the vendors' own sites into Assets/provider-marks/ and drawn from their published geometry rather than redrawn: monochrome templates in the menu bar, because macOS owns a status item's appearance, and in each vendor's own colour in the overlay. docs/provider-marks.md records the sources, hashes, and trademark position; ProviderMarkProvenanceTests fails if any of it drifts.

Behavior and security

  • Refresh runs on launch, whenever the overlay opens, every five minutes, and from the labelled Refresh button.
  • Provider stale, authentication-required, rate-limited, unavailable, and error states have distinct badges. A failed whole-command refresh restates every menu-bar reading as the last known one (~50%) and adds a banner to the overlay, so held-over data never looks current.
  • The production process arguments are fixed to --provider claude,codex,grok --json. Left never passes --full, account identity, tokens, or keys as arguments, and it never prints provider errors.
  • The child process gets an allowlisted environment: reconstructed HOME and PATH, plus locale, temp, and user-name variables when they are already set. It does not inherit the rest of the app environment.
  • Command stderr is discarded. Stdout is read in a stream and aborted at 1 MiB, so a runaway child cannot fill memory. The app does not log or persist quota output.
  • Only the exact non-secret quota-axi --allow-keychain-prompt repair command can reach the UI.

Architecture

  • Sources/LeftCore/QuotaModels.swift owns schema-version 2 decoding.
  • Sources/LeftCore/QuotaAXIAdapter.swift defines the adapter protocol, production process runner, and fixture adapter.
  • Sources/LeftCore/UsagePresentation.swift maps raw states and windows to safe display values.
  • Sources/LeftCore/PlainLanguage.swift owns every state sentence, badge, and spoken value, so the menu bar and the overlay cannot word the same state two ways.
  • Sources/LeftCore/MenuBarStatus.swift composes the status item into one template image and states it in words for VoiceOver.
  • Sources/LeftCore/PopoverLayout.swift, Palette.swift, LeftMark.swift, and ProviderMark.swift hold the grid, the dark language, and the marks, so the view, the icon, and the tests all quote one source.
  • Sources/Left/ contains the status item, refresh store, SwiftUI overlay, preview renderer, and iconset renderer.
  • Fixtures/demo-quota.json is the synthetic fixture for tests, demo mode, and visual evidence.

The research and trade-offs are recorded in docs/research.md; the rebrand and redesign decision is in docs/naming.md.

License

MIT. See LICENSE. The Anthropic, OpenAI, and xAI marks are not licensed as project copyright; see NOTICE and docs/provider-marks.md.

About

Left: macOS menu-bar quota meter for Claude Code, ChatGPT/Codex, and Grok

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages