Tells you whether to speed up or slow down so you finish each quota window at 95% — using as much as you have paid for, without running out.
The Anthropic API reports only what your usage is right now, with no history
endpoint, and no absolute token figures at all (limit_dollars and friends are
null on a Team plan). ccmon polls it every 5 minutes, keeps a local snapshot,
and commits each sample so the trend survives.
For each window it answers three things:
| when does it renew | "resets in 3h 43m" |
| speed up or slow down | "faster 1.5x", "on pace", "ease off 0.7x" |
| by how much | "16%/day still available" |
The bar carries the absolute level, with a tick marking where usage would be if the window were spent evenly to 95% — the gap between that tick and the end of the fill is your headroom.
flowchart LR
API["Anthropic usage API"]
GW["Bedrock gateway<br/><i>optional</i>"]
subgraph machine["each machine (WSL or macOS)"]
POLL["poller<br/><i>every 5 min</i>"]
SNAP[("usage-snapshot.json<br/><i>this machine's last reading</i>")]
BSNAP[("bedrock-snapshot.json<br/><i>live only, never shared</i>")]
HIST[("history clone<br/><i>every machine's samples</i>")]
SYNC["history-sync<br/><i>every 15 min</i>"]
end
WIDGET["desktop widget"]
STATUS["Claude Code status line"]
CHART["ccmon chart.sh"]
REPO[("GitHub repo<br/><b>data</b> branch")]
PAGES["GitHub Pages<br/><i>public</i>"]
SERVE["ccmon serve"]
BOARD["wallboard"]
API -->|poll| POLL
API -.->|"own feed"| STATUS
POLL -->|write| SNAP
POLL -->|"append own file"| HIST
SNAP -->|read| WIDGET
GW -->|"every 15 min to hourly"| POLL
POLL -->|write| BSNAP
BSNAP -->|read| WIDGET
HIST --> SYNC
SYNC -->|"push own file"| REPO
REPO -->|"fetch every machine"| SYNC
SYNC -->|"merge + rebuild manifest"| HIST
HIST -->|read| CHART
HIST -->|serve| SERVE
REPO -->|serve| PAGES
PAGES -->|"no auth"| BOARD
SERVE -->|"no auth, LAN"| BOARD
Four moving parts, each with one job:
| Part | Reads | Writes |
|---|---|---|
| poller | the usage API | the snapshot, and one line in its own history file |
| widget | the snapshot only — this machine's own last reading | a small panel on the desktop |
| repo | — | the data branch, compacted as it grows |
| wallboard | every machine's samples, merged | a screen you can read across a room |
Sync is two-way. Each run fetches the data branch and hard-resets onto it,
keeping only this machine's own two files, then rebuilds the manifest from every
machine's latest reading. So the local clone ends up holding everyone's
samples — which is what chart.sh, ccmon serve and the wallboard read. One
file per machine is what makes that safe: no two machines ever write the same
file, so the pushes cannot conflict.
The widget reads only usage-snapshot.json, not the merged history. When
this machine cannot read its own usage — typically because its token expired
while Claude Code ran through Bedrock — the poller fills that snapshot with
another machine's reading from the clone instead, and the widget footer says
"by another machine". The quota is account-wide, so it is the same number. Only
a reading under 30 minutes old counts, and only one from the same account,
recognised by its weekly reset time; with neither, the widget shows stale.
So is the Bedrock quota. On a machine that also uses Claude Code through Amazon Bedrock, behind a gateway that enforces a monthly budget per user, the poll job reads that budget every 15 minutes to hourly and the widget shows it as a second panel. That number is never appended to the history and never pushed: it is one person's, not the account's, and it is only ever shown on that person's desktop.
The status line is fed by Claude Code itself rather than by ccmon, so it keeps working even when the poller is backed off or offline.
git clone https://github.com/baloise/aicon-ccmon
cd aicon-ccmon
./ccmonThat is the whole setup. ./ccmon checks what is present, explains anything
that is missing at the point where it matters, and offers to fix it. It is safe
to re-run at any time, and re-running after a successful pass changes nothing.
./ccmon status read-only summary
./ccmon serve serve the wallboard locally, no GitHub sign-in needed
./ccmon update git pull, then re-apply whatever drifted
./ccmon uninstall remove the timers and installed files
Deliberately, setup instructions live only in ./ccmon — not here, not in an
example env file, not in comments in the scripts. One account of the procedure,
attached to the code that performs it.
For the reverse-engineered API details and the reasoning behind the design, see
docs/findings.md.
Sits on the desktop rather than above your work: bottom of the Z-order, no taskbar entry, no alt-tab, and it never takes focus. Home is the top-right corner: drag it anywhere you like and it stays there, but a resolution change, a monitor arriving or leaving, or a dock sends it home - the arrangement you placed it in no longer exists, and a corner is somewhere you can always find it again.
The status dot - in the notification area on Windows, the menu bar on macOS - is how you reach it. Its colour is the pace verdict of whichever window is pacing worse, not how full either one is, so it stays green while you are within budget however much of the quota is already spent:
| left-click | toggles between the desktop and the front, and stays there |
| right-click | move widget · bring to front / send to desktop · hide / show · hide / show Bedrock panel · profile · open wallboard · open Bedrock usage · refresh now · update · quit |
The toggles relabel themselves, so the menu always states what the click will do rather than what the state currently is.
"Refresh now" runs the poller rather than waiting for the next tick - inside WSL on Windows, directly on macOS - and fetches the Bedrock quota as well, which otherwise waits up to an hour.
The Bedrock panel sits directly below the main one, once ./ccmon has been
told where the gateway is. The setup proposes both the gateway's address and
yours from the files its credential provider installed, and asks you to
confirm them; neither is in this repository. The panel shows how much of this
month's budget is used, with what is left in dollars beneath it and the same
bar, pace tick and verdict as the subscription windows. The gateway's "tokens"
are weighted by price, a million to the dollar, so a raw count left would mean
little. A second row appears for the shared pool you draw from, but only once
that pool is fuller than your own budget: spending it blocks everybody in it,
and until then it cannot be what stops you. The panel grows and shrinks with
it. "Open Bedrock usage" opens the gateway's dashboard on this month, filtered
to you.
Profile lists the claude-config
profiles in ~/.claude/profiles and switches between them. A switch applies
to Claude Code sessions started afterwards, not to the ones already running.
The status dot follows the active profile: on a Bedrock profile it speaks for
the Bedrock panel, otherwise for the subscription.
Either way it is a small compiled executable, built on the fly by ./ccmon
with a compiler the operating system already has, so there is nothing to
install and the repository ships source rather than a binary.
On Windows that compiler is the csc.exe from the .NET Framework, and
being compiled is not gratuitous: Windows identifies a tray icon by (executable
path + uID), so anything hosted by powershell.exe shares an identity with
every other PowerShell tray icon and can never get its own row under Settings >
Taskbar > Other system tray icons. ccmon pins it there rather than leaving it in
the hidden overflow.
On macOS it is swiftc from the Command Line Tools, and the widget sits
above the wallpaper and under the desktop icons. That last part costs the
drag: Finder's desktop window covers the whole screen and is above us, so it
takes every click that passes over the panel, and the widget never sees one.
"Move widget" in the menu lifts it just long enough to be dragged and drops it
back the moment you let go. --level icons trades that back the other way -
directly draggable, at the price of painting over the desktop icons.
Its colours come from the wallpaper underneath it. The widget samples the pixels behind the panel and asks how little scrim it can wear and still be read: a light wallpaper gets the light palette, a dark one the dark palette, and the opacity is whatever the contrast actually requires - measured on one ordinary photo, 26% rather than the fixed 90% Windows uses. "Readability" in the menu sets the target the text must hit, not the opacity, so there is no setting at which it becomes unreadable; Appearance pins the palette if the measurement disagrees with taste, and can turn the whole thing off.
Two other things are worse here than on Windows, and neither has a fix an installer can apply: a menu bar item cannot be pinned, so on a notched Mac with a crowded menu bar it can end up under the notch; and there is no balloon tip, so "Update ccmon" opens a Terminal window and lets it speak for itself.
Two ways to reach the same page:
- GitHub Pages — published from the
databranch at https://baloise.github.io/aicon-ccmon/. No sign-in, nothing to install. ./ccmon serve— the same page over plain HTTP from your own machine, no authentication at all. This is what an unattended screen should point at, since a kiosk browser will eventually be asked to sign in again.
Add ?theme=dark to pin the theme; a browser with no preference resolves to
light, which is rarely what you want on a wall.
The page polls the published data and redraws itself every minute. It will not
work opened as a file:// URL — fetch is blocked there, which is exactly why
the local option is a server rather than just opening the file.
ccmon reads Claude Code's OAuth token - from ~/.claude/.credentials.json on
Linux and WSL, and from the login Keychain on macOS, where Claude Code keeps the
same JSON as the secret of a generic password. It never refreshes or rotates that
token — doing so could log Claude Code out from under you. When the token
expires the snapshot is marked stale and keeps the last known values until you
use Claude Code again.
Nothing identifying reaches the repo: samples are timestamps and percentages.
Apache-2.0. See LICENSE.
The published data is a record of one account's Claude usage over time, including the hours during which it was used. Machines are identified by a random id rather than their hostname, which keeps naming conventions private — but commit authorship still identifies who runs it, so this is not anonymous data.