codeburn/docs/menubar.md
ozymandiashh 59ed66b977
feat(dock): one Claude ring per config directory, with its own sessions and today (#1570)
* feat(dock): one Claude ring per config directory, with its own sessions and today (#1523)

Rate limits are per account, so a machine with a work and a personal
~/.claude cannot be served by one Claude ring. When the CLI knows two or
more Claude config directories:

- `codeburn quota --format json` adds a top-level `claudeProfiles` array,
  one entry per directory (`providers[]` unchanged). Each entry carries
  the directory's own windows, read from its own `<dir>/.credentials.json`
  (the macOS Keychain fallback stays reserved for the default ~/.claude),
  plus that directory's own today totals from a single Claude-only,
  cache-backed parse of today's range, filtered per source id exactly like
  the menubar's per-config payloads.
- Live sessions carry `claudeConfigSourceId`, so a per-profile ring claims
  only its own sessions. Claude Desktop sessions keep their own bucket id
  and belong to no profile.
- The Windows Capacity Dock gains a `claudeProfiles` preference (combined,
  default; separate draws one captioned ring per directory). Profile rings
  keep addressing the `claude` provider id for the provider set, glyphs,
  colors and the connect button; the settings row appears only when the
  CLI reports more than one profile.
- Captioned rows are taller by two new metrics (caption line + gap),
  mirrored in TS and Rust: the page tells Rust the rail is captioned in
  the layout request, and the frame carries the effective row extent the
  hit-test uses. Non-captioned rails are pixel-identical to before.
- The desktop app's shared dock-prefs schema parses and sanitizes the new
  key, so its pane cannot strip it from windows-dock.json.

Closes #1523

* review: opt-in profile reads, today timeout, missing-dir filter (#1570)

- `quota --claude-profiles` gates the per-directory reads: without it the
  payload lists profiles ({id,label,path}) only, so a combined rail and
  WSL users pay nothing; the Windows dock passes the flag only while its
  claudeProfiles preference is separate, and an unknown option from an
  older CLI reads as CliOutdated.
- The default ~/.claude profile reuses the claude provider row's result —
  no second request, no second macOS Keychain read.
- claudeTodayBySource races the same timeoutMs and answers an empty map
  on loss, so a silent child cannot cost the dock every provider's quota.
- Missing config directories are filtered before the >1 check.
- `captioned` applies only while a Claude ring is in the selected set;
  profile rows tolerate a list-mode answer; comments trimmed; merge with
  #1560 keeps both keepExpanded and claudeProfiles.

* test(quota): set USERPROFILE for the default-dir check; drop issue refs

---------

Co-authored-by: Resham Joshi <65915470+iamtoruk@users.noreply.github.com>
2026-09-28 19:06:53 +02:00

9.1 KiB

Menu bar, tray, and Capacity Dock

macOS

codeburn menubar

One command: downloads the latest .app, installs it, and launches it. A copy you already have is replaced where it lives, in /Applications or ~/Applications, so you never end up with two bundles and two login items; if that folder cannot be written to, the install goes to ~/Applications and names the old copy for you to move to the Trash. Re-run with --force to reinstall. Launching the app retires the copy already running, so there is only ever one flame in the menu bar. You can also install and manage it from the desktop app's Plugins page. The native Swift and SwiftUI app lives in mac/ (see mac/README.md for build details).

The menubar icon shows the spend period selected in Settings (Today by default; Week, Month, and 6 Months are also available). Non-today periods add a short suffix such as $42 / mo so the menu bar value stays clear. Click to open a popover with agent tabs, period switcher (Today, 7 Days, 30 Days, Month, All), Trend, Forecast, Pulse, Stats, and Plan insights, activity and model breakdowns, optimize findings, and CSV/JSON export. Refreshes every 30 seconds.

You can also set the menubar status period from Terminal:

defaults write org.agentseal.codeburn-menubar CodeBurnMenubarPeriod -string month

Allowed values are today, week, month, and sixMonths. Relaunch the app to apply external defaults changes.

Compact mode shrinks the menubar item to fit the text, dropping decimals (e.g. $110 instead of $110.20):

defaults write org.agentseal.codeburn-menubar CodeBurnMenubarCompact -bool true

Relaunch the app to apply. To revert: defaults delete org.agentseal.codeburn-menubar CodeBurnMenubarCompact.

Second row adds an optional smaller line under the menubar figure. Turn it on in Settings → General → Display and pick what it shows: quota remaining with its reset countdown (for whichever connected provider is nearest its limit), today's cost, today's tokens, or running sessions. It is off by default, and the line hides itself while the chosen metric has no data, so the item falls back to its single-row figure. From Terminal:

defaults write org.agentseal.codeburn-menubar CodeBurnMenubarSecondRowEnabled -bool true
defaults write org.agentseal.codeburn-menubar CodeBurnMenubarSecondRowMetric -string todayCost

Allowed metric values are quotaRemaining, todayCost, todayTokens, and activeSessions. Relaunch the app to apply external defaults changes.

Refresh cadence is set in Settings under Usage Refresh. Auto (the default) refreshes every 30 seconds on AC power and backs off on battery, in Low Power Mode, and while the display sleeps; fixed 1, 5, or 15 minute cadences and a Manual mode (refresh only when you open the popover or click Refresh Now) are also available. From Terminal:

defaults write org.agentseal.codeburn-menubar CodeBurnMenubarRefreshSeconds -int 300

Seconds between refreshes: 60, 300, or 900; 0 is Manual and -1 is Auto. Takes effect on the next refresh tick, no relaunch needed.

Preferred terminal decides where Full Report and Optimize open. Set it in Settings → General → Terminal, or from Terminal:

defaults write org.agentseal.codeburn-menubar CodeBurnPreferredTerminal -string iterm2

Allowed values are terminal (macOS Terminal.app, the default) and iterm2. Anything else falls back to terminal. Only terminals that can script a command into a live window are offered; if the chosen app is missing or fails to accept the command, CodeBurn tries Terminal.app and then runs the command in the background, logging each step to Console.app. Takes effect on the next launch of a command, no relaunch needed.

Windows

The recommended install is the Microsoft Store (Store ID 9P0R4ZL5XMB8), which ships the desktop app with the tray app inside it. Microsoft signs that package at submission, and the Store keeps it up to date, so the tray app leaves its own update checker switched off there.

Windows gets the same ambient view from the system tray, from the same one command:

codeburn menubar

It downloads the .msi for your CLI version, verifies its sha256, runs it through msiexec /passive, and launches the tray app. Re-run with --force to reinstall; an already-installed matching version is just launched. You can also download the .msi yourself from the latest Windows Menubar release.

Today's spend sits in the tray as a number beside the flame icon (turn it off in Settings, and the tooltip always carries it). Click for the same popover the macOS app shows: agent tabs, period switcher, Trend, Forecast, Pulse, Stats and Plan insights, activity and model breakdowns, optimize findings, and CSV/JSON export. Settings covers launch at login, the tray number, theme, and currency. It refreshes every 60 seconds while the popover is open and every 2 minutes while it is closed.

Turn on Show Capacity Dock in the tray menu, or from the desktop app, for the same edge-docked quota rail the macOS menubar has: one ring per connected provider, hover for every quota window with its reset time, drag it to any screen edge. It is off by default and needs codeburn 0.9.24 or newer for codeburn quota. The hover card can keep its own appearance (Settings > General > Capacity Dock > Hover bubble).

With more than one Claude config directory configured (CLAUDE_CONFIG_DIRS or the claudeConfigDirs key in ~/.config/codeburn/config.json), Settings → General → Capacity Dock gains a Claude profiles row: Combined keeps the single Claude ring, Separate rings draws one captioned ring per directory — each with that account's own limit windows, running sessions and today totals, since rate limits are per account.

The desktop app installs and configures the tray companion from a card on its Plugins page, the way it does the macOS menu bar: Install, Update, Open, Settings, Quit and Uninstall, a Running dot with the installed version, and the Capacity Dock switch. codeburn menubar --uninstall removes it from the command line.

The tray app reads everything through the CLI, so install that first (npm install -g codeburn). It needs codeburn 0.9.9 or newer, and shows a setup screen with the install command until it finds one. Source and build instructions are in windows/ (windows/DEVELOPMENT.md).

The .msi under the windows-v* releases and the desktop setup .exe are a developer preview. Both are unsigned, so SmartScreen prompts on first run: click "More info", then "Run anyway". The preview builds also do not update themselves. The tray app still tells you when a newer version exists and links to the release; taking it means re-running codeburn menubar --force or downloading the new build yourself.

WSL

Agents you run inside a WSL distro write their history to the distro's Linux home, not to your Windows user profile, so a Windows-only scan reports nothing for them. CodeBurn on Windows now also scans each WSL distro's home directories (\\wsl$\<distro>\home\* and \\wsl$\<distro>\root) for Claude Code (~/.claude) and Codex (~/.codex) history, merging what it finds with your Windows sessions. It is read-only, and the tray app inherits it — it reads everything through the CLI.

Only running distros are scanned by default: reaching into \\wsl$\<distro> boots a stopped distro, which CodeBurn will not do behind your back. Start the distro (or set CODEBURN_WSL=all) if you want the others included. Stopping a distro does not lose its numbers — an offline root is not a deleted transcript, so its usage keeps counting and comes straight back out of the cache when you start it again. When that home is reachable, an ordinary transcript actually deleted there is evicted normally instead of being mistaken for an offline root; Claude rows carrying PR attribution keep the existing historical-retention exception. codeburn doctor lists every root it probed, WSL ones included, and says so in one line when it probed none.

Value Behaviour
CODEBURN_WSL=running Default. Scans running distros only.
CODEBURN_WSL=all Scans every installed distro, starting stopped ones on first access.
CODEBURN_WSL=off Disables WSL discovery and UNC access immediately; wsl.exe is never run. Historical usage already in CodeBurn's cache remains reportable and is reused if discovery is re-enabled.

Linux (GNOME)

Linux gets the same ambient view through a GNOME Shell extension (GNOME 45+): spend in the top panel, period switcher, compact mode, and daily budget alerts. It lives in gnome/:

git clone https://github.com/getagentseal/codeburn && cd codeburn/gnome
./install.sh
gnome-extensions enable codeburn@codeburn.dev

See gnome/README.md for settings and development notes. The Tauri tray app in windows/ also builds and runs on Linux, but it is experimental and unreleased there — the GNOME extension is the supported Linux surface.