Skip to content

About

Tells you whether to speed up or slow down so you finish each Claude quota window at 95%

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

41 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

aicon-ccmon

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.

How the parts fit together

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
Loading

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.

Use it

git clone https://github.com/baloise/aicon-ccmon
cd aicon-ccmon
./ccmon

That 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.

The desktop widget

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.

The wallboard

Two ways to reach the same page:

  • GitHub Pages — published from the data branch 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.

What it will not do

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.

Licence

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.

About

Tells you whether to speed up or slow down so you finish each Claude quota window at 95%

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages