Local-only token usage plugins for UsageBoard, aggregating Claude Code / Gemini CLI / Codex CLI sessions into one macOS menu-bar dashboard.
简体中文 · English

Usage Overview (hero total + per-model rows + right-column token count) atop per-CLI panels
📊 Click to see expanded 7-day charts

Click the chevron under any panel to expand its 7-day stacked bar chart by model
- Local-first data — token stats are read entirely from local JSONL/JSON session files; no ChatGPT subscription token needed. The only optional remote call is the Claude account quota lookup (on by default, disable with
SHOW_CLAUDE_QUOTA=off). - Claude account quota on top — the overview card leads with your official account's 5-hour and weekly quota (with real reset times) plus the account email under the title; it auto-hides whenever OAuth credentials are unreadable (pure API key / relay setups).
- Three CLIs in one panel — Claude Code, Gemini CLI, Codex CLI usage aggregated by model.
- Global multi-period filter + layered details — one top segmented picker switches
today/7d/30d/90d/all; Usage Overview shows one share row per provider (Claude/Gemini/Codex) with the period total in the title badge, while per-model details live in the per-CLI cards following the same period. - Clear token accounting — Claude can be shown as
billableorraw, and Codex/Gemini keep their reported-token semantics. - Setup helper CLI —
tokenused doctor,sync-plugins,install-config, andsmokemake installation and debugging repeatable. - Auto-hide empty panels — if you've never used a CLI (e.g. Gemini), its panel disappears automatically.
- Right-column token count — UsageBoard's reset-time slot is repurposed via the
trailingTextfield to show the per-model token count. - Native macOS WidgetKit project included — code-complete in
widget/; gallery distribution requires a paid Apple Developer Program account (see Native Widget).
| Component | Version | Notes |
|---|---|---|
| macOS | 13.0 + | UsageBoard requirement |
| Python 3 | 3.8 + | System Python or Homebrew both fine |
| UsageBoard | upstream main |
Will be patched and rebuilt locally |
| Swift toolchain | 6.2 + | Only needed if you build UsageBoard from source |
| Xcode 16 + | optional | Only needed if you also build the native widget app |
You also need at least one of these CLIs to have produced session data:
- Claude Code →
~/.claude/projects/**/*.jsonl - Gemini CLI →
~/.gemini/tmp/**/session-*.json - Codex CLI →
~/.codex/sessions/**/*.jsonland~/.codex/archived_sessions/*.jsonl
CLIs with zero data hide automatically — install all four plugins anyway and use what you have.
brew tap unistark/tap
brew install tokenusedPlugins land in $(brew --prefix)/opt/tokenused/share/tokenused/, and the helper CLI becomes available as tokenused.
Shortest path after Homebrew:
# 1. Check prerequisites and paths
tokenused doctor
# 2. Patch + build UsageBoard (one time)
git clone https://github.com/marsmay/UsageBoard.git ../UsageBoard
cd ../UsageBoard
git apply "$(brew --prefix)/opt/tokenused/share/tokenused/patches/usageboard-build-and-refresh.patch"
bash scripts/build.sh
cd -
# 3. Copy/update TokenUsed plugins into UsageBoard
tokenused sync-plugins
# 4. Merge TokenUsed entries into UsageBoard config without removing other plugins
tokenused install-config
# 5. Run installed-plugin smoke checks
tokenused smokebrew info tokenused also prints the activation guide.
# 1. Clone
git clone https://github.com/uniStark/token-used.git
cd token-used
# 2. Patch + build UsageBoard (one time)
git clone https://github.com/marsmay/UsageBoard.git ../UsageBoard
cd ../UsageBoard
git apply ../token-used/patches/usageboard-build-and-refresh.patch
bash scripts/build.sh
cd ../TokenUsed
# 3. Check prerequisites and paths
python3 bin/tokenused doctor
# 4. Copy/update TokenUsed plugins into UsageBoard
python3 bin/tokenused sync-plugins
# 5. Merge TokenUsed entries into UsageBoard config without removing other plugins
python3 bin/tokenused install-config
# 6. Run installed-plugin smoke checks
python3 bin/tokenused smoke
# 7. Open UsageBoard, click the menu-bar icon — you should see the overview + per-CLI panelsIf anything goes wrong, see Troubleshooting below.
If you cannot use bin/tokenused, the old manual install path still works:
mkdir -p "$HOME/Library/Application Support/UsageBoard/plugins"
cp plugins/*.py "$HOME/Library/Application Support/UsageBoard/plugins/"
chmod +x "$HOME/Library/Application Support/UsageBoard/plugins/"*.py
sed "s|__HOME__|$HOME|g" examples/config.example.json > "$HOME/Library/Application Support/UsageBoard/config.json"Prefer tokenused install-config when possible because it merges/upserts the TokenUsed plugin entries instead of replacing your whole UsageBoard config.
patches/usageboard-build-and-refresh.patch makes several small changes to upstream UsageBoard:
| File | Change | Why |
|---|---|---|
Package.swift |
swift-tools-version: 6.3 → 6.2 |
Lets Swift 6.2 toolchains build it |
Sources/UsageBoardApp/DashboardView.swift |
Adds store.refreshAll(), visiblePlugins, a global top segmented period picker (@AppStorage("usageboard.period.global")) shared by every card with dimensions, enlarged badge rendering via PlanTag(size: 14), and layout tweaks for long titles; the badge / card icon prefer the active dimension's badge / iconURL; renders subtitle (account email) under the title with click-to-copy and a hover tooltip showing the full value |
Refresh on every panel open; auto-hide CLIs with no data; switch periods across overview and per-CLI cards without re-running plugins; token-count badges are prominent; badge and dominant-provider icon follow the selected period; account info is visible and copyable |
Sources/UsageBoardApp/UsageBoardStore.swift |
Preserves iconURL, dimensions, defaultDimension, dimensionOrder, and subtitle in cached plugin state |
Keeps dynamic icons, multi-period data, and account info after restart |
Sources/UsageBoardCore/Models.swift |
Adds dimensions, defaultDimension, dimensionOrder, iconURL, subtitle, per-dimension badge / iconURL, and UsageItem.trailingText support across plugin output, snapshots, and cached state; percent labels cap at 99% until truly 100%. PluginSnapshot.hasNoUsageItems now checks the default dimension only (with fallback to "all empty" if no default is set) |
Lets plugins emit all periods at once; allows dynamic icon/subtitle overrides; shows token counts in the right column; 99.8% no longer rounds up to a misleading 100%; CLIs whose default period has no data auto-hide even when older periods still contain history |
Sources/UsageBoardCore/PluginExecutor.swift |
Changes the default timeout from 15s to 180s, prefers plugin-emitted iconURL, and passes through subtitle |
Prevents cold scans of large directories from timing out; lets Usage Overview show the dominant provider icon and account email |
Sources/UsageBoardApp/DesignSystem/UBDesignTokens.swift |
canvasBackground switched from hardcoded RGB (0.961, 0.961, 0.969) to Color(nsColor: .windowBackgroundColor) |
Card-gap canvas now follows light/dark mode instead of staying frozen light |
Sources/UsageBoardApp/DesignSystem/PlanTag.swift |
Adds a size parameter (default 9.5 to keep upstream PRO/PLUS plan tags unchanged) with proportional padding / radius / monospacedDigit(); default badge palette switched from gray.opacity(0.16) + .secondary to primary.opacity(0.10) + primary.opacity(0.85) |
Token-count badges can render at size 14 and stay readable in dark mode (light-grey bg + light-grey text was almost invisible) |
Sources/UsageBoardApp/DesignSystem/BrandTile.swift |
When an icon image is loaded, lay a Color.white rounded fill behind it and bump inner padding; stroke opacity raised from 0.06 to 0.10 |
Dark logos (e.g. OpenAI black PNG from lobe-icons) stay readable on dark popovers; coloured logos still look right on a clean white tile |
If you'd rather use UsageBoard unmodified, the plugins still work — you just lose auto-hide, right-column token counts, in-panel period switching, dynamic icons, and the dark-mode tweaks.
Use tokenused <command> after Homebrew install, or python3 bin/tokenused <command> from a manual clone.
| Command | What it does |
|---|---|
doctor |
Checks Python, UsageBoard paths, plugin/config locations, session-data visibility, and common patch/install problems. Start here when the panel is empty or stale. |
sync-plugins |
Copies or updates TokenUsed plugin scripts in ~/Library/Application Support/UsageBoard/plugins/ and makes them executable. |
install-config |
Merges/upserts TokenUsed plugin entries into UsageBoard config.json; it should not remove unrelated UsageBoard plugins or user settings. |
smoke |
Runs lightweight installed-plugin checks so you can catch JSON/schema/runtime errors before opening UsageBoard. |
The CLI helps with TokenUsed installation only. The UsageBoard patch remains the key enhancement path: without it, plugins can still run, but multi-period switching, right-column token counts, auto-hide, layout fixes, and dynamic icons are degraded or unavailable.
All four plugins read parameters from the UsageBoard plugin settings UI. Defaults work out of the box. Override only when needed.
Aggregates Claude / Gemini / Codex usage by period. The plugin emits all five periods at once, and the top global picker controls both the overview and per-CLI cards.
| Parameter | Default | Description |
|---|---|---|
CLAUDE_DIR |
~/.claude/projects |
Where Claude Code stores session JSONL |
GEMINI_DIR |
~/.gemini/tmp |
Where Gemini CLI stores session-*.json |
CODEX_DIR |
~/.codex |
Codex CLI base dir (scans sessions/ + archived_sessions/) |
STAT_PERIOD |
30d |
Default period: today / 7d / 30d / 90d / all |
SHOW_CLAUDE_QUOTA |
on |
Shows the official Claude account's 5-hour/weekly quota and account email at the top of the overview card. Reads the local Claude Code OAuth credentials (Keychain or ~/.claude/.credentials.json) and calls the official oauth/usage endpoint; results are cached for 120s with a 30-minute stale fallback on failure. Auto-hides entirely when credentials are unreadable or the API returns 401 (pure API key / relay setups). Set to off to disable this — the only — remote call |
TOKEN_MODE |
billable |
billable (input+output+cache_creation, matches Claude Code /cost) or raw (also includes cache_read_input_tokens hits — typically ~95% of the total) |
Per-CLI plugins (claude-code-usage-plugin.py, gemini-cli-usage-plugin.py, codex-local-usage-plugin.py)
| Parameter | Default | Description |
|---|---|---|
*_DIR |
same as above | Override scan path for that CLI |
STAT_PERIOD |
30d |
Default period: today / 7d / 30d / 90d / all |
TOKEN_MODE (Claude only) |
billable |
Same semantics as Daily Overview. Has no effect on Codex/Gemini panels (their reported tokens have no cache-read concept) |
Global segmented picker: Usage Overview and each per-CLI plugin emit a
dimensionsmap with all five periods, so once data is in cache (~30s first run),Today ↔ 7d ↔ 30d ↔ 90d ↔ Allswitches every card instantly — no plugin re-spawn, no re-parse. The selection is persisted globally via@AppStorage("usageboard.period.global").
Why two modes? Claude's
usagereport counts every prompt-cache hit ascache_read_input_tokens. With heavy tool use, this can balloon the "raw" total to 100×+ what you actually billed.billablematches the four-component cost formula Anthropic uses (input + output + cache_creation); switching only re-projects the in-cache totals — no reparse.
Overview layering: the overview card leads with the Claude account quota block (optional), followed by one share row per provider (Claude / Gemini / Codex) with the period total in the title badge; per-model details live in the per-CLI cards. The card icon shows the period's dominant provider and follows the period switch.
To customise: open UsageBoard → menu-bar icon → gear → Plugins → click the plugin → adjust parameters. No restart needed.
Colour carries quota-alert semantics only, to avoid misreads:
- Claude quota rows — blue < 60%, orange ≥ 60%, red ≥ 85%, with the real reset time in the right column
- Provider / model / total rows — always neutral blue (they show shares, not alerts), with token counts in the right column
TokenUsed/
├── bin/
│ └── tokenused # Install/debug helper CLI
├── plugins/ # UsageBoard Python plugins
│ ├── daily-overview-plugin.py # ⭐ Usage overview (3 CLIs aggregated by period and model)
│ ├── claude-code-usage-plugin.py # Claude Code single-CLI panel
│ ├── gemini-cli-usage-plugin.py # Gemini CLI single-CLI panel
│ ├── codex-local-usage-plugin.py # Codex CLI single-CLI panel
│ ├── _shared.py # Compatibility facade imported by plugin entrypoints
│ └── _shared_*.py # Private shared modules (core/cache/parsers/builders/quota)
├── patches/
│ └── usageboard-build-and-refresh.patch # UsageBoard UI / schema / executor enhancements
├── examples/
│ └── config.example.json # Drop-in UsageBoard config with all four plugins registered
├── widget/ # Native macOS WidgetKit app (Xcode project — see status below)
├── images/ # README screenshots
├── README.md # This file (English)
├── README_ZH.md # 中文版
└── LICENSE # MIT
widget/ contains a complete WidgetKit + SwiftUI Xcode project (Small / Medium / Large sizes, Swift Charts 7-day bar chart). It builds and runs locally, but on macOS 15+ Sequoia / Tahoe the system daemon chronod refuses to register Personal-Team-signed widget extensions in the desktop widget gallery — you need a paid Apple Developer Program ($99/yr) account to actually use it.
If you don't pay for the Program, stick with the menu-bar UsageBoard panel — it has all the same data. The widget code is kept ready to ship the day signing becomes possible.
| Plugin | Reads from | Field |
|---|---|---|
| Claude Code | ~/.claude/projects/**/*.jsonl |
message.usage.{input,output,cache_*}_tokens + message.model |
| Gemini CLI | ~/.gemini/tmp/**/session-*.json |
messages[].tokens.total + messages[].model |
| Codex CLI | ~/.codex/sessions/**/*.jsonl + archived_sessions/*.jsonl |
payload.info.total_token_usage.total_tokens (model picked from preceding turn_context) |
The overview plugin reads all three in parallel.
Start with tokenused doctor: it checks the common failure points in one place:
tokenused doctor
# or, from a manual clone:
python3 bin/tokenused doctorUse its output to confirm whether the issue is missing UsageBoard paths, missing session data, unsynced plugins, an unmerged config, or an unpatched UsageBoard build.
Panel shows "JSON 解析失败 / failed to parse": run the plugin manually to see the raw error:
python3 "$HOME/Library/Application Support/UsageBoard/plugins/daily-overview-plugin.py" \
--usageboard-param USAGEBOARD_LANGUAGE=enYou can also run tokenused smoke to exercise the installed plugins through the helper CLI.
Build error swift-tools-version 6.3 is not supported: you forgot to apply the patch. cd UsageBoard && git apply ../TokenUsed/patches/usageboard-build-and-refresh.patch.
Right column shows --: you're running unpatched UsageBoard. The trailingText feature requires the patch.
Gemini panel still shows with 0 tokens: you're running unpatched UsageBoard, or the Gemini plugin is from before the empty-items change — cp plugins/gemini-cli-usage-plugin.py ~/Library/Application\ Support/UsageBoard/plugins/ and click the menu-bar icon to refresh.
PRs welcome. Useful directions:
- New CLI plugins (e.g. Aider, Cursor CLI, Cline, OpenRouter) — copy any
*-usage-plugin.pyas a template, follow the# UsageBoardPlugin: ... # /UsageBoardPluginmetadata block. - Better colour/threshold rules — current rules are documented in the Configuration section.
- Native widget polish — once the Apple Developer Program issue is sorted, the
widget/project is ready for distribution. - Localisations beyond
zh-Hans/en.
Please run python3 plugins/<your-plugin>.py --usageboard-param USAGEBOARD_LANGUAGE=en and confirm the JSON validates against existing fixtures before submitting.
Run the test suite locally — same one CI runs:
python3 -m unittest tests.test_plugins -vpatches/usageboard-build-and-refresh.patch is a real git diff and must stay one. If you have RTK (Rust Token Killer) installed in Claude Code, its hook intercepts git diff / git status etc. and rewrites the output into a token-compressed form that is not a valid unified diff. To regenerate the patch correctly:
cd ../UsageBoard
# bypass the RTK hook so git produces a real unified diff
rtk proxy git diff > ../TokenUsed/patches/usageboard-build-and-refresh.patch
# verify on a clean tree
git stash && git apply --check ../TokenUsed/patches/usageboard-build-and-refresh.patch && git stash popCI (.github/workflows/ci.yml) runs git apply --check and a patched swift build on every push, so malformed or uncompilable patches fail before they can ship.
MIT — see LICENSE. Plugin scripts are free to modify and redistribute.
- UsageBoard — the menu-bar host this project plugs into.
- lobe-icons — plugin icon set referenced in
examples/config.example.json.