tokenhud
v0.1.5
Published
Live terminal heads-up display for coding-agent usage, limits and cost
Maintainers
Readme
tokenhud
tokenhud is a terminal dashboard for your coding-agent usage. It reads the transcripts that Claude Code and Codex write on your machine and shows, for every account, how close you are to your subscription limits, what your usage would cost at API prices, and where it went: by day, by model and by account. It keeps that history after the transcripts are deleted. It also runs an MCP server, so a Claude Code agent can check its own account's limits and wait for a reset instead of failing halfway through a task.
tokenhud succeeds cc-usage and imports its history on first run.

The Overview on made-up accounts. Views explains every part of every screen.
Install
With Bun (recommended on Linux and macOS):
bun add -g tokenhudNo Node is needed. Bun puts the tokenhud command in ~/.bun/bin, which Bun's installer
adds to your PATH; tokenhud doctor says if it isn't there. Release candidates:
bun add -g tokenhud@next.
Bun ends by saying Blocked 1 postinstall. That is expected, and harmless on Linux and
macOS: the script it blocked is tokenhud's own preinstall, which sets up the command for
npm on Windows and does nothing anywhere else. Leave it blocked; don't bun pm -g trust it.
On Windows, Bun isn't supported yet.
bun add -g tokenhudinstalls a command that fails at once withinterpreter executable "/bin/sh" not found. On Windows, usenpm i -g tokenhudor the PowerShell installer (see On Windows, below).
With npm:
npm install -g tokenhud # or run it without installing: npx tokenhud, or bunx tokenhud (not on Windows)Either way you get tokenhud, and the prebuilt binary for your machine in a platform
package (@tokenhud/linux-x64 and so on), which the package manager installs as an optional
dependency: don't install with --omit=optional. On Linux and macOS the tokenhud command
is a small sh script that starts the binary: no JS runtime runs, so it needs neither Node
nor Bun, and nothing in the directory you run it in (a .env, a bunfig.toml) can reach
tokenhud.
If a download of that package fails, Bun and npm install tokenhud without it, and the
command only says the package is not installed (tokenhud doctor, from another copy, says
so too). Right after a release, npm's servers can take a few minutes to serve it
everywhere; wait a few minutes and reinstall:
bun remove -g tokenhud && bun add -g --no-cache tokenhud, or
npm install -g --prefer-online tokenhud.
On Windows, tokenhud is supported through npm (npm i -g tokenhud, Node 18 or later)
or the PowerShell installer, install.ps1, below; not through Bun. npm's install script
sets up a Node launcher for the command. If you installed with Bun, that command can't run,
so switch by hand: bun remove -g tokenhud, then npm i -g tokenhud. tokenhud doctor,
run from an npm or install.ps1 copy, points out a bun install left behind.
On Windows the command needs that install script. Where scripts are off, the command fails
at once with The system cannot find the path specified. (tokenhud update says so too);
each of these puts it right:
| Scripts off by | Repair |
|---|---|
| npm install -g --ignore-scripts, or ignore-scripts=true in your .npmrc | npm rebuild -g --ignore-scripts=false tokenhud |
| npx with ignore-scripts=true | delete the _npx folder in npm's cache (npm config get cache shows where), then npx --ignore-scripts=false tokenhud |
| pnpm 10 or later, which runs no dependency's scripts unless approved | pnpm approve-builds -g, choose tokenhud, then pnpm add -g tokenhud |
| yarn 1, which writes the command before it runs install scripts | yarn global remove tokenhud, then install with npm |
Without a package manager, on Linux and macOS:
curl -fsSL https://raw.githubusercontent.com/ZhuoQiuMcgill/tokenhud/main/install.sh | shOn Windows (PowerShell):
irm https://raw.githubusercontent.com/ZhuoQiuMcgill/tokenhud/main/install.ps1 | iexBoth download the binary for your machine from
GitHub Releases, check its SHA-256
against the release's SHA256SUMS, and install it without sudo or admin rights:
install.sh to ~/.local/bin/tokenhud (it tells you if that isn't on your PATH),
install.ps1 to %LOCALAPPDATA%\tokenhud\bin\tokenhud.exe, which it adds to your user
PATH. Running either again reinstalls, or updates to the newest release. Install one way
only: tokenhud doctor lists every tokenhud on your PATH (see Update
for switching).
| Variable | Effect |
|---|---|
| TOKENHUD_VERSION | Install this release, e.g. 0.1.0 or a release candidate such as 0.2.0-rc.1. Default: the latest stable release |
| TOKENHUD_INSTALL | Install into this directory instead |
| TOKENHUD_NO_MODIFY_PATH | 1: install.ps1 leaves your PATH alone |
curl -fsSL https://raw.githubusercontent.com/ZhuoQiuMcgill/tokenhud/main/install.sh | TOKENHUD_VERSION=0.1.0 sh$env:TOKENHUD_VERSION = '0.1.0'; irm https://raw.githubusercontent.com/ZhuoQiuMcgill/tokenhud/main/install.ps1 | iexAlpine and other musl-based Linux need the C++ runtime the binary links against:
apk add libstdc++ libgcc. With Bun or npm, name the musl binary's package as well, since
it is not an optional dependency (Bun would download it on every Linux machine), and do the
same to install another version by hand. tokenhud update updates both.
bun add -g @tokenhud/linux-x64-musl tokenhud # on arm64: @tokenhud/linux-arm64-musl
npm install -g @tokenhud/linux-x64-musl tokenhudBy hand: download tokenhud-<os>-<arch> (linux-x64, linux-arm64, linux-x64-musl,
linux-arm64-musl, darwin-x64, darwin-arm64, windows-x64.exe, windows-arm64.exe)
and SHA256SUMS from a release, check it with sha256sum --check --ignore-missing
SHA256SUMS (shasum -a 256 --check --ignore-missing SHA256SUMS on macOS), make it
executable and put it on your PATH. On macOS, a binary downloaded with a web browser is
quarantined, and macOS refuses to start it, because tokenhud's binaries are signed but not
notarized. Clear the flag with xattr -d com.apple.quarantine tokenhud-darwin-arm64 (or
-x64). install.sh downloads with curl, which doesn't set the flag.
First run
Run tokenhud. It finds your Claude Code and Codex accounts (see Accounts),
and on its first start:
- if you used cc-usage, it imports cc-usage's usage history and settings (what comes over);
- it reads every transcript once to build its store. That takes a few seconds; after that, it reads only what's new as the agents write it.
tokenhud --once prints the Overview once and exits: with colours in a terminal, as plain
text when piped. --width N sets its width. tokenhud doctor reports what tokenhud found:
the store, the accounts it follows, unpriced models, anything still only in cc-usage, and
every tokenhud on your PATH.
Keys
Every view moves the same way, with the left hand on WASD or either hand on the arrows:
| Key | Does |
|---|---|
| a/d or ←/→ | Switch the tab: what the view shows |
| w/s or ↑/↓ | Move the selection: which row or card |
| enter | Open the selection |
| esc | Go back one step: close, un-drill, clear |
Letters work the same with Caps Lock on. In a text field (History's model filter, the time zone filter, a new label) letters are just text.
| Key | Does, in every view |
|---|---|
| 1-4 | Switch view: Overview, History, Models, Accounts |
| tab or shift-tab | Next view, or the previous one |
| c | Cycle the account scope: all accounts, then each account, then all again |
| x | Open settings |
| ? | Show the keys, the current view's included |
| q or Ctrl-C | Quit |
A view with tabs shows them as a strip, ◀ a … d ▶, over what they switch. The footer
shows the keys of the view you are in.
Overview
| Key | Does |
|---|---|
| a/d | Switch the window of the activity chart and the top models: the last 5 hours, 24 hours or 7 days |
| w/s | Select an account card (none is selected at first) |
| enter | Open the selected card's account (the first card's when none is selected) in Accounts |
| esc | Clear the card selection |
| t | Show cost or tokens in the activity chart and the top models |
History
| Key | Does |
|---|---|
| a/d | Switch the table: this week, this month, every day, the weeks or the months |
| w/s | Select a row; the heat map highlights its day, week or month |
| pgup/pgdn, home/end | Move ten rows, or to the first or last |
| enter | On a week or month, list its days; on a day, list its limit events |
| esc | Close the limit events, then the open week or month, then clear the filter |
| f or / | Filter every number by model: type part of its name or id, enter applies it |
Models
| Key | Does |
|---|---|
| a/d | Switch the window: today, this week, this month, all time, the last 1, 5 or 24 hours |
| w/s | Select a model |
| enter | Show or hide the selected model's rates and who used it |
| r | Sort by cost, tokens or name |
Accounts
| Key | Does |
|---|---|
| w/s | Select an account; the last entry is "add a root…" |
| enter | Open the account's action menu; on "add a root…", the settings account editor |
Account menu
enter on an account, in the Accounts view or in settings under Accounts, opens a small
menu: show only this account (again: all accounts), enable or disable it, rename it, mark
it history only or not, mark it as the same subscription account as another directory
("Same account as…", picked from a list) and, once linked, unlink it.
| Key | Does |
|---|---|
| w/s or ↑/↓ | Select an action |
| enter | Run it |
| esc | Close the menu |
Help
| Key | Does |
|---|---|
| esc, ?, enter or q | Close the help |
Settings
| Key | Does |
|---|---|
| w/s or ↑/↓ | Move; in the time zone list, only the arrows (letters filter it) |
| a/d or ←/→ | Step the selected setting's value in place |
| pgup/pgdn, home/end | Move ten rows, or to the first or last |
| enter | Open the selected setting's list, pick a value, or open an account's action menu |
| esc, x or q | Back; from the main list, back to the view (x only there) |
| backspace | Delete the last character of a filter or label |
Settings are the refresh interval, the default spend window, whether to show cost, the
theme (dark, light, high contrast), the time zone, whether to check for updates, and the
accounts. They are saved in ~/.config/tokenhud/config.json.
Views
tokenhud has four views; the number keys switch between them (see Keys). The screenshots below are tokenhud at 120 × 45, the top half of a portrait monitor, on made-up accounts. In each legend, the numbers and colours match the boxes in the picture above it.
Overview screen
How close each account is to its limits, and what your usage is costing right now.

- 🟥 Header. The four views, the one you are on highlighted. On the right, the account scope:
all accounts, or the one account that every number in every view is narrowed to. Then the status dot.● live · 5s(teal): this tokenhud reads new transcript lines as Claude Code and Codex write them, and refreshes its clock-driven numbers every 5 seconds (the refresh interval setting).● stale(amber): it isn't reading transcripts itself, because another tokenhud is (this one shows what that one stores), or it is still starting, or reading failed.● error(red): the numbers have stopped updating while tokenhud restarts the part that computes them. - 🟧 Limits. A card per account, Claude Code and Codex alike: its 5-hour and weekly subscription limits, and what its current spending means for them. The note on the right is a reminder of the two paces,
pace (30m)over the last 30 minutes andavgover the week so far, that<2hmeans within 2 hours, and that every countdown and time on a card is an estimate. Reading a limits card explains each reading. - 🟨 Agents. Shown while tokenhud's MCP server runs for a Claude Code session (see Use with Claude Code). One line per agent session that called a tool in the last 10 minutes: its project (the name of the directory the session runs in, never its path;
claude sessionwhen the server doesn't say), the account the call was about, the tool, and how long ago. A narrow card leaves out the account, then the project. With no recent calls, it says how many servers are running. - 🟩 Spend. What your usage would cost at the providers' API prices (not what your subscription costs), and its tokens: input, output, cache reads and cache writes together.
1hand5hare the last 60 minutes and the last 5 hours (shown on screens 120 columns wide or more).today,this weekandthis monthstart at local midnight, on Monday and on the 1st.all-timeis everything tokenhud has stored, including usage whose transcripts are gone. For*and≈, see Glyphs and colours. - 🟦 Activity. Cost over the last 24 hours, one bar per time slot. The tabs on the right switch the chart and the top models beside it to the last 5 hours or 7 days (
a/d; the one shown is in brackets), andtswitches both to tokens. The title gives the slot's length, which grows until the chart fits the width: 30 minutes here. On the left, the tallest slot's cost, half of it, and zero; below, hours back from now. - 🟪 Top models. The five models with the most cost in the chart's window, its tab in the title (
TOP MODELS · 24h): the cost, its share of the window's cost, and a bar of that share.a/dswitch the window with the chart's, andtranks by tokens. A fast or priority tier gets its own row, marked(fast). A model with no published price showsunpricedand comes last. Under the list, when a row is free,more windows: 3 Models: the Models view (3) has today, this week, this month and more. Then the chart's tallest slot and when it started. - 🟫 Limit events. Limits hit in the last 7 days: day and time, account, and what happened.
5-hour limit reached(red) is a window that reached 100 %;weekly passed 80%(amber) is a weekly window crossing 80 %. After a reached limit,resumed 16:05is when tokenhud first saw the window usable again after its reset;resetsand a time, when a window that is still full will reset;—, that no fetch has seen it since. Limits reached come first, newest first, then the 80 % marks. Up to 8 lines; the rest are counted on the last one.
Reading a limits card

- 🟥 Account. The account's label and its provider,
claudeorcodex. The label comes from the account's config directory (~/.claude-workiswork) unless you renamed it. - 🟧 Meters. The
5hrow is the 5-hour window, theweekrow the weekly one. Each bar is how much of that limit is used: blue below 50 %, amber from 50 %, red-orange from 80 %. A model's own weekly limit isn't on the card; the Accounts view lists it. - 🟨 Used, and time to reset.
84%is the share of the 5-hour limit used, as the provider reported it the last time tokenhud fetched the limits;1h52mis the time left until that window resets. On the weekly row,41%used and5d21h(5 days 21 hours) to go. Once a window has reset, the card reads 0 % and—until the next fetch. - 🟩 Pace. The spend pace the verdict comes from, at API prices, as dollars per hour (tokens per hour with costs hidden).
pacewith(30m)is what the account spent in the last 30 minutes:$6.8/hhere, and$0/hfor nothing in that time.avgwiththis weekis a weekly window's average since it began, idle time and nights included: the pace a weekly verdict comes from. Where a card is narrow,(30m)orthis weekgoes first, then the word; the number stays. - 🟦 Verdict. What that pace means for the two windows: an estimate (see How the projection works). The first of these that applies:
at 100% until …, a window is full now, until the last full one resets;100% in <45m, how soon the 5-hour window fills at its pace, rounded up to the next of 5, 10, 15, 20, 30 or 45 minutes, or 1, 1.5, 2, 3, 4, 6, 8, 12, 18 or 24 hours, so it never says later than it is (justnowunder a minute), and where the card has room, when (… (12:13), with the day when it isn't today);100% <18h, the same for the weekly window at its average, past a day in days with a~, and its time only to a part of the day (… (~tonight), or tomorrow morning, Sunday evening and so on; never to the minute, which a week's average can't tell). A narrow card drops a weekly average'sthis weekfirst, then the time, then thein, then the pace's basis.wk ~94%(week ends ~…on a wider card), the weekly window is on course to end its week at 80 % or more;idle, nothing spent in 30 minutes, oridle · week N%when a window is at 80 % or more all the same;safe(safe until …on a wider card), both windows last until they reset;no estimate yet, too little spending in a window to tell. Red means a window is or will be full, amber a high week. - 🟪 Stale limits. The limits were fetched more than 15 minutes ago:
(52m old)says how long ago, and the card shows them as they were then. - 🟫 Not signed in here. A history-only account: one you marked history only, or one that isn't signed in on this machine (it runs on another computer now, say). Its limits can't be read here, so it has no meters, but its usage history stays. See Accounts.
How the projection works
Each window is projected at a pace of its own, at API prices:
- The 5-hour window: what the account spent in the last 30 minutes, times two
(
pace … (30m)on the card). - A weekly window: its average since it began, what the account has spent in it so far
over the hours since it opened, nights and idle time included (
avg … this week). Half an hour is too little of a week: two agents working at once for 30 minutes would otherwise say the week runs out tonight. In a weekly window's first 6 hours there is too little to average, and the 30-minute pace stands in.
For each window, tokenhud estimates how much of the limit a dollar uses: the window's use
when the limits were last fetched, divided by what the account had spent in that window by
then (at least $0.50, or there is no estimate). It adds what was spent since that fetch, and
works out how long the rest of the window lasts at its pace. If that ends before the window
resets, the card counts down to it, rounded up so it never says later than it is: within 5,
10, 15, 20, 30 or 45 minutes, 1, 1.5, 2, 3, 4, 6, 8, 12, 18 or 24 hours, or for a weekly
window about so many days (100% in <2h, 100% in ~3d; 100% now under a minute). Where
the card has room it also says when: to the minute for the 5-hour window
(100% in <2h (12:13)), and to a part of the day for a weekly one
(100% in ~3d (~Sun evening); or tonight, tomorrow morning and so on), as precise as a
week's average can be. If after, the window is safe. For the weekly window it
also works out where the week would end at its pace: that is the week ends ~N% figure,
shown from 80 %. Treat it as a rough guide:
- tokenhud sees only the transcripts on this machine. Use of the same subscription elsewhere (another computer, claude.ai) fills the meter without showing up here, which makes the estimate too early.
- API prices stand in for the provider's own accounting, which isn't published, so a change in models or in cache use changes the estimate.
- A burst or a break dominates the 30-minute pace, and so the 5-hour estimate. The weekly average is slow to follow a change of habit instead: a busy day after a quiet week shows late.
History screen
Your usage day by day, week by week and month by month, and the days you hit a limit.

- 🟥 Tabs. What the table lists, switched with
a/d; the one shown is in brackets.this weekandthis monthlist the days so far of the current week or month (History opens on this week),daysevery day of the heat map,weeks(Monday to Sunday) andmonthsone row each. On the right, what*and≈mean, andf, the model filter: with a filter, every number on the screen counts only the models whose name or id contains what you typed. - 🟧 Heat map. One square per day for the last 26 weeks: a column per week, Monday at the top. The shade is the day's cost against the busiest day shown: the darkest square is a day without usage, and the four lighter shades are under a quarter of the busiest day, under a half, under three quarters, and the rest. The table's selected row is white: here a day; on the weeks or months tab, that week's or month's days. Days after today are blank.
- 🟨 Day card. The selected day.
cost, and how it compares with your usual day:2.4×is the day's cost divided by your average daily cost over the 30 days before today (or fewer, if your usage started more recently).tokens, split into input, output and cache (reads and writes).models: its three most expensive models, with their share of the day's cost.accounts: each account's cost that day.limits: the day's limit events.hit 100% at 14:10 (waited 1h55m)is a window that reached its limit, and how long it was until tokenhud saw it usable again; a weekly window crossing 80 % reads passed 80%. - 🟩 Period table. The rows of the tab shown, newest first, moved through with
w/s. On the weeks or months tab,enterlists a row's days andescgoes back; on a day with limit events,enterlists them.input,outputandcache(reads and writes) are tokens;costis at API prices.vs 30-day avgcompares the period with your average day times the period's days so far: the bar is full at 2.25 times, 1 times is a little under half of it, and it turns red-orange above 1.5 times; the ratio follows it.top modelis the period's most expensive model,accountsthose with usage, most cost first. - 🟦 Totals. Every period listed, added up: here the
177 daysof the heat map's 26 weeks, today included. - 🟪 Footer. Its first line is the keys of the view you are on:
a/dits tabs,w/sthe selection,enterto open it, then the view's own;esc backjoins them while there is something to go back from. Its second line is the keys every view has (all of them are in Keys). On the right,MCP ● 2 agents: tokenhud's MCP server is running (teal dot) and two agent sessions called it in the last 10 minutes;MCP ○means no server is running. A newer release, or another tokenhud reading the transcripts, is noted here too.
Models screen
What each model cost you, the rates it was billed at, and who used it.

- 🟥 Rate board. Every model used in the window, by cost (
rsorts by tokens, then by name). The tabs on the right are the windows, switched witha/d; the one shown is in brackets. Today, this week, this month and all time are calendar periods, and 1h, 5h and 24h the last hours. One row per model and tier; a fast or priority tier is its own row,(fast). For input, output and cache (reads and writes): the tokens used, and the$/Mrate they are billed at today, in dollars per million tokens (—: no price).costprices each request at the rate in effect on its date, so it can differ from tokens times today's rate. The bar and the percentage are the model's share of the window's cost.*after a name: some or all of its tokens have no published rate, so they are counted but not priced. The selected row (w/s) is highlighted, andentershows or hides its cards below. - 🟧 Total. All models together. Rates don't add up, so the total has none.
- 🟨 Footnotes.
$/Mis the base rate; cache writes, and requests over a model's long-context threshold, cost more. Then the share of the window's tokens that have a price, and which costs are estimates:codex-auto-reviewis priced as the model OpenAI said serves it. - 🟩 Rates. The selected model's prices today, per million tokens: input and output; cache reads, and what fraction of the input rate they are; cache writes, for 5 minutes and for 1 hour (Anthropic) or one rate (OpenAI); the fast tier's prices; the long-context threshold and its multipliers, for models that have one; where the prices come from and when they were last checked; and any price change inside the window.
- 🟦 Who used it. Each account's share of the selected model's cost in the window, and that cost. Then the day the model was first used, and how many requests the window holds.
Accounts screen
Every account in detail: where its data comes from, its limits now and in past weeks, and its last 30 days.

- 🟥 Accounts. Every account tokenhud has usage for: those active on this machine first, then by all-time cost. The dot and the percentage show the account's most-used limit among its windows that haven't reset yet: blue below 50 %, amber from 50 %, red-orange from 80 %.
○and a grey label: inactive here (history only, not signed in, turned off, or its config directory isn't on this machine).+ add a root…opens the account settings. Under the list, the keys:w/sselect an account, andenteropens its menu: show only this account, enable or disable it, rename it, history only, and linking it to another directory on the same subscription account. - 🟧 Account. The selected account, its provider, and when its limits were last fetched.
- 🟨 Where it comes from.
rootis the config directory its transcripts are read from, and how:watched(read as they are written),polled(checked at intervals, for a Windows drive under WSL) ordisabled.history: how many requests tokenhud has stored for it, and the day of the first. - 🟩 Limits. Every limit window of the account: 5-hour, weekly, then any of a model's own. The bar and the percentage are how much is used (colours as on the cards), then when the window resets: a time today, a weekday and a time within a week, else a date. A window projected to fill before it resets says so under its bar, as the cards do:
→ 100% in <45m (12:13), and for a weekly window→ 100% in ~2d (~tomorrow night). A window that has reset since the last fetch shows an empty bar,—, and how long ago it reset. A failed fetch is noted under the meters. Under them, dim, any limit alerts agents have set on the account: the window and its threshold, the scope, when it last fired, and the agent's note. - 🟦 Weekly history. The weekly window over the last 8 weeks, on a 0–100 % scale, each week labelled with the day it reset. The last bar (grey) is this week so far. Earlier weeks are known only from limit events:
100%for a week that reached its limit,≥80%for one that passed 80 %,—for no record: under 80 %, or not seen by tokenhud. - 🟪 Last 30 days.
spend 30d: one bar per day for the last 30 days, today last, each against the busiest of them; then their total cost.models: the account's models over those 30 days, by share of cost.agents: its latest MCP tool call in the last 10 minutes, and how many calls it made.
Glyphs and colours
━bars: a limit meter or a share. The coloured part is the share used, the dark track the rest. Limit meters are blue below 50 %, amber from 50 % and red-orange from 80 %; share bars are amber for cost and blue for tokens.▂▃▄▅▆▇█columns: the activity chart, the 30-day bars and the weekly history, in eighths of a row; any usage at all shows as▂or more. A dim baseline,▁, = no usage in that bucket, so a quiet stretch reads as part of the chart, not its end. Without colour,▁still means none.■heat map: the darkest square is a day without usage; the four lighter shades are days under a quarter of the busiest day shown, under a half, under three quarters, and the rest. White is the table's selected row: a day, or a week's or month's days.*after a cost: some of its tokens have no price, so the cost leaves them out and is a lower bound. After a model's name: some or all of its tokens have no published rate.unpriced: none of its tokens has a price. See Pricing.≈before a cost: part of it is priced from an estimate (codex-auto-review, priced as the model OpenAI said serves it).<in100% in <2h: within that long, an estimate.~inwk ~94%,100% in ~3dor(~tonight): a projection, the last to a part of the day. Every countdown and time on a limits card is an estimate.- Grey (dim) text is secondary: labels, notes, and what is old or inactive, such as a
limits card's
(52m old), an inactive account's○, or a window past its reset. - Dots: teal
●is live (the header) or an MCP server running (the footer); amber●stale; red●an error. In Accounts, an account's dot takes its limit colour. - Highlights: a lighter background marks the selected row, and the active view, tab or
window; a tab strip's active tab is in brackets too (
[24h]), for plain text and for anyone who can't tell the colours apart.
The layout adapts to the terminal: it is laid out for half of a 1080p screen (about 105 × 50), the top half of a portrait monitor (about 120 × 45), 80 × 24 and wider. On narrower screens, columns and sections drop out, least important first, and the limits cards turn into two lines each; a number is never cut short.
Accounts
An account is one Claude Code or Codex config directory. tokenhud finds:
- Claude Code:
~/.claude,$CLAUDE_CONFIG_DIR, and every~/.claude-*directory (~/.claude-workis labelledwork); - Codex:
~/.codexand$CODEX_HOME; - under WSL, the same directories on the Windows side (
/mnt/c/Users/*/.claude*,/mnt/c/Users/*/.codex*), labelled with a-winsuffix.TOKENHUD_WSL_USERS=(empty) skips them.
Directories elsewhere go in config.json as claude_roots or codex_roots, for example
"claude_roots": [{"path": "/srv/claude-ci", "label": "ci"}]. In the Accounts view, or in
settings under Accounts, enter opens an account's menu: turn it off, rename it, or mark it
history only. c narrows every view to one account.
History-only accounts. An account that isn't signed in on this machine any more (it now runs on another computer, say) keeps all of its history. Its card says "not signed in here" instead of showing an error, and tokenhud checks its limits only once a day, or never once you mark it history only (in its menu).
Several directories on one subscription account. Two config dirs signed in to the same
Claude (or ChatGPT) account share one set of limits: under WSL, ~/.claude and the
Windows-side .claude often are. tokenhud then shows them as one limits account: one
card titled with both labels, limits fetched once through whichever is signed in, and a
pace summed over both, since both spend from the same limit. History, spend and the
Accounts view stay per directory; there, each says which directories it shares its account
with, and the account's 30-day total.
tokenhud links them by itself when their limits reset at the same times (within 2 s) and their use moves together: equal on two pairs of fetches seconds apart, at most ten minutes apart, and changed in between. An account nobody is using proves nothing, so two directories on an idle account show apart until it is used. Once they are linked, the other directory is still fetched every 30 minutes, and once more right away when its credential file changes. If a reset differs, the two show apart straight away, and a second difference in a row unlinks them; a difference in use alone is checked again next round. These checks ride on the account's own fetches, the TUI's and the MCP server's alike. Finding two directories on one account in the first place is left to the fetches the TUI makes every 5 minutes: the MCP server fetches only the account it is asked about, so an agent asking often adds no fetches of a directory not linked to it.
An account's menu (enter on it, in the Accounts view or in settings under Accounts) links
it to another by hand ("Same account as…") and unlinks it ("Unlink"). These are saved as
same_account and separate_accounts in config.json, and win over what tokenhud finds.
A link you made is never undone: if the limits differ, Accounts and tokenhud doctor say
so. tokenhud doctor lists the linked directories, how each link was made, and the pairs
kept apart.
Use with Claude Code
tokenhud's MCP server lets a Claude Code agent check the limits of the account it runs
on, decide whether to pause, wait for a reset, and set alerts that tell it when
a limit reaches a percent. That matters most for sessions that can't resume on their own:
claude -p, background tasks and teammates. Interactive Claude Code resumes by itself
after a reset, so there an agent should tell you instead of waiting.
Install
Install tokenhud first, so tokenhud is on the PATH Claude Code starts with:
the plugin and the MCP server both run tokenhud mcp. Otherwise /mcp in Claude Code
shows the server as failed.
Plugins and user-scope MCP servers belong to one Claude config dir, so install once per
account: once for ~/.claude, and once more for each CLAUDE_CONFIG_DIR you use.
tokenhud doctor shows which accounts have it, and whether tokenhud is on the PATH.
The plugin adds the MCP server, a skill that tells agents when to use it, and the hooks that deliver alerts:
claude plugin marketplace add ZhuoQiuMcgill/tokenhud
claude plugin install tokenhud@tokenhud
# another account
CLAUDE_CONFIG_DIR=~/.claude-work claude plugin marketplace add ZhuoQiuMcgill/tokenhud
CLAUDE_CONFIG_DIR=~/.claude-work claude plugin install tokenhud@tokenhudThe MCP server on its own:
claude mcp add -s user tokenhud -- tokenhud mcp
CLAUDE_CONFIG_DIR=~/.claude-work claude mcp add -s user tokenhud -- tokenhud mcpThen add the alert hooks the plugin would have brought, once per account:
tokenhud mcp install --hooks
tokenhud mcp install --hooks --config-dir ~/.claude-workNative Windows: an npm install puts a tokenhud.cmd shim on the PATH, which Claude
Code can't start directly. Register the server through cmd instead of installing the
plugin: claude mcp add -s user tokenhud -- cmd /c tokenhud mcp. The standalone
tokenhud.exe (installed with install.ps1) works directly, plugin included.
Tools
| Tool | What it does |
|---|---|
| limits | The account's limit windows (5-hour, weekly, per model): utilization from 0 to 1, reset time, the spend pace each window is projected at (pace_basis: 30m, the last 30 minutes, or for a weekly window window_avg, its average since it began), and when the window would run out at that pace (projected_exhaustion_at, and projected_exhaustion_in_s, the seconds until then; an estimate, a weekly window's good to a part of a day). Fetches fresh limits when the cached ones are over 60 s old. For a directory that shares its subscription account with others, the windows and pace are the account's, and shared_with names the others. |
| should_wait | wait: true when a window is at 90 % or more (min_headroom, default 0.1), when estimated_cost (USD) would take it there, or when it is projected to run out within 10 minutes, before its reset. The 5-hour and weekly windows always count; a per-model window (such as a model's weekly limit) counts only when model names that model, and is otherwise just mentioned. Returns a short reason, the window it is about with its pace and projection as limits gives them, and wait_s: until the reset, plus 30 s. |
| wait_for_reset | Waits until the window should_wait binds on (for the same model) resets, or its utilization drops under until_utilization_below, for at most max_wait_s (5 hours or less). Sends progress every 30 s, re-checks the limits every 5 minutes, and stops at once when the call is cancelled. |
| usage | Tokens and API-equivalent cost for a period, optionally by model, account, day, week or month (at most 500 groups per call), as tokenhud json usage prints them (schema), plus stale_s, the age of the store's data. |
| accounts | The accounts on this machine, from cached data only: whether their limits can be read here (signed_in, null until first checked), their last usage, which one this session runs on, and group, the same id for every directory on one subscription account. |
| set_alert | Sets an alert: window (5h, weekly, weekly_scoped for a model's own weekly limit, or any), at (a percent, 1 to 100), and optionally account, scope (session, the default, or persistent) and a note of up to 200 characters to get back when it fires. Returns the alert's id and the window's state now; a window already at or over at is said so, and fires next after its reset. Warns when this session doesn't run tokenhud's hook. |
| list_alerts | This session's alerts and every persistent one: each armed, or fired (and when) for the window's current instance, and whether alerts reach this session. |
| clear_alert | Clears one alert by id, or all of this session's with all: true (persistent ones too with persistent: true). |
Every tool answers for the account the session runs on: CLAUDE_CONFIG_DIR, else
~/.claude, confirmed by finding the session's transcript. limits reports how it was
found (detected_via). Pass account (a label from accounts) for another account, or
provider: "codex" for Codex. An account that isn't signed in on this machine reports
signed_in: false, and should_wait doesn't make agents wait on it.
Alerts
An agent can ask to be told when a limit fills: "tell me when the 5-hour window reaches
80%", or "when the weekly reaches 90%". It calls set_alert, carries on, and once the
window gets there a line appears in its context, on its next batch of tool calls or your
next prompt:
[tokenhud alert] 5-hour limit (personal) is at 82% (alert at 80%), resets in 1h12m. Note: pause the refactor and commit. Call should_wait before long tasks.- Once per window. An alert fires once for each window instance, and again after the
window resets and climbs back. One set while the window is already over the line is
told so at once, and fires next after the reset. When the limits it read are over two
minutes old, the line says how old (
limits as of 6m ago). - Scope. A
sessionalert (the default) ends with its Claude Code session: tokenhud removes it when the session ends, or after 24 hours without any activity from it. Apersistentone stays until cleared, and is told to any session on that account, or on another directory of the same subscription account. Alerts go to the session's main agent, not to subagents. - Delivery. A Claude Code hook,
tokenhud hook, runs after each batch of tool calls and on each prompt; it reads onlylimits.jsonandalerts.json, never the network, and takes about 20 ms. Its command line ends in; exit 0, so with a tokenhud too old to have it, or none on the PATH, it stays silent and never holds up a prompt. The plugin installs it. With the MCP server added by hand,tokenhud mcp install --hooksadds it to the account'ssettings.json(by the installed tokenhud's full path, run by PowerShell on Windows; every other hook is kept, the file's permissions too, and a backup copy is made beside it, beside the real file whensettings.jsonis a link), andtokenhud mcp install --hooks --removetakes it out.tokenhud doctorshows which accounts have it;set_alertwarns an agent whose session doesn't run it, or whose session id the MCP server could not follow after a/clear. - Fresh limits. While one of its session's alerts is armed, the MCP server fetches that account's limits every 5 minutes. A fetch by the TUI or by an agent's own call in between counts, so with the TUI running there are no extra requests, and with no alert armed the server asks for nothing.
- Where you see them. The Accounts view lists each account's alerts, dim. There is no desktop notification: alerts are for agents.
Scripts: tokenhud json
tokenhud json usage --period this_week --group-by day
tokenhud json models --period today
tokenhud json accountsEach prints one JSON document from the store, with the same queries the MCP server uses. docs-public/JSON.md documents the options, the output and the schema-1 contract.
Pricing
Costs are API-equivalent: what the tokens would cost at the providers' published API
prices, not what your subscription costs. Each request is priced by its model, its date
(prices that changed apply from the day they changed), its tier (Claude fast mode, Codex
priority), long context, and cache reads and writes. The bundled table and where every price
comes from are in src/pricing (pricing.json, SOURCES.md).
- A model with no price is counted but not priced. Its cost shows as
unpriced, totals that leave tokens out are marked*, andtokenhud doctorlists the models and how much of your usage is priced. codex-auto-reviewis priced as an estimate, at the model OpenAI said serves it.- Costs are recomputed from the stored token counts every time, so a price correction applies to all of your history.
Your own prices go in ~/.config/tokenhud/pricing.overrides.json, which holds only your
entries; rates are USD per 1 million tokens:
{
"models": {
"my-local-model": { "input": 3, "output": 15, "cache_read": 0.3 },
"gpt-5.6-sol": {
"periods": [
{ "from": null, "card": { "input": 5, "output": 30, "cache_read": 0.5 } },
{ "from": "2026-08-21T07:00:00Z", "card": { "input": 4, "output": 20, "cache_read": 0.4 } }
]
}
}
}input and output are required. cache_read defaults to a tenth of input and
cache_write to 1.25 × input; fast holds a fast or priority card in the same form. An
entry replaces everything the bundled table says about that model, its dated prices and
fast card included. Because the file holds only your entries, later corrections to the
bundled table still reach every other model. An entry tokenhud can't read is skipped, with
a warning in tokenhud doctor.
Data and privacy
- Provider data is read-only. tokenhud reads the transcripts under Claude Code's and Codex's config directories, and never writes, moves or deletes anything there.
- It stores token counts, not content: per request, its time, model, token counts and
account. No prompts, responses or file contents. (
cache.dbremembers which transcript files it has read, by path, so it can pick up where it left off.) - Credentials stay in memory. To show a Claude account's limits, tokenhud reads that
account's OAuth token from its credentials file and calls Anthropic's usage endpoint; when
the token has expired, it lets the
claudecommand refresh it. For Codex it asks the installedcodexapp server. Tokens are never logged, cached or sent anywhere else. - Network: the limit requests above, and GitHub's list of tokenhud releases: when you
run
tokenhud update, and at most once a day while the TUI runs, to show when a newer release is out (settings, "Check for updates", turns that off). No telemetry; prices are bundled, never fetched.
tokenhud's own files are in ~/.config/tokenhud/ (or $XDG_CONFIG_HOME/tokenhud/):
tokenhud.db your usage history: the only copy of usage whose transcripts are gone
tokenhud.db.bak a verified daily backup of it, and tokenhud.db.bak.prev before that
cache.db how far each transcript has been read (safe to delete: it is rebuilt)
config.json settings
pricing.overrides.json your prices, if any
limits.json the last limits fetched
alerts.json the limit alerts agents set: windows, thresholds and their notes
update-check.json when GitHub was last asked about a newer release, and its answer
logs/tokenhud.log errors, for tokenhud doctor and bug reports
logs/hook.log errors of tokenhud hook, which never shows them to the agent
mcp/ which MCP servers are running, their projects' names and sessions, and
when tokenhud hook last ran for each session
ingest.lock.db which tokenhud process writes the storeA store that can't be read is renamed tokenhud.db.corrupt-<time> and its history
recovered into a new one; it is never deleted.
Update and uninstall
tokenhud update --check # is there a newer release?
tokenhud update # install itHow tokenhud update updates depends on how tokenhud was installed:
- With Bun or npm (globally): it asks the package manager which version npm's
latesttag points at (nextfor a release candidate, as long asnextis no older than it), installs exactly that version (bun add -g --no-cache [email protected]ornpm install -g [email protected]), then checks that thetokenhudcommand runs it and says which version it went from and to. It never installs an older version than the one you have;--allow-downgradedoes.--no-cachemakes Bun ask the registry rather than reuse an answer from a few minutes ago. - With
install.shorinstall.ps1: the binary replaces itself. It downloads the new release, checks its SHA-256 against the release'sSHA256SUMS, checks that it starts, and only then swaps it in. - Through npx or bunx, or as a project's dependency: it prints the command that updates it.
--prerelease includes release candidates (npm's next tag). --print prints the command
that updates your install, naming the tag rather than its version, and runs nothing. After updating, tokenhud update warns if
another tokenhud comes first on your PATH, since a shell would still run that one.
Nothing updates on its own. When a newer release is out, the TUI says so in its footer, in dim text; it asks GitHub at most once a day, and the "Check for updates" setting turns that off.
Switching from install.sh to Bun: run bun add -g tokenhud, then the new copy's
doctor, ~/.bun/bin/tokenhud doctor (plain tokenhud may still start the old one). It
lists every tokenhud on your PATH, with its version and how it was installed, marks the one
a shell runs, and names the file the old install left, such as ~/.local/bin/tokenhud.
Delete that file (rm ~/.local/bin/tokenhud): doctor never deletes anything. Until you do,
if ~/.local/bin comes before ~/.bun/bin on your PATH, typing tokenhud still runs the
old copy. On Windows the same goes for switching from install.ps1 to npm: delete
%LOCALAPPDATA%\tokenhud and remove its bin folder from your user PATH.
To uninstall:
- Remove the program:
bun remove -g tokenhudornpm uninstall -g tokenhud; forinstall.sh's binary,rm ~/.local/bin/tokenhud; on Windows, delete%LOCALAPPDATA%\tokenhudand remove itsbinfolder from your user PATH (Settings › System › About › Advanced system settings › Environment Variables). - Remove it from Claude Code, once per account:
claude plugin uninstall tokenhud@tokenhudorclaude mcp remove -s user tokenhud. - If you no longer want your usage history, delete
~/.config/tokenhud/.
Development
Prerequisite: Bun 1.4.2 or later. CI pins 1.4.2; Bun 1.3.12 and 1.4.0 produced macOS binaries with broken signatures.
bun install # dependencies and dev tooling
bun run check # typecheck (tsc), lint and format check (Biome), tests (bun test)
bun run build # standalone binary for this machine at dist/tokenhud
bun src/cli.ts # run from sourcebun run build --target=<bun target> cross-compiles one binary, for example
--target=bun-windows-x64 writes dist/tokenhud.exe. bun run build --release builds all
eight release binaries and SHA256SUMS (install with bun install --os="*" --cpu="*"
first), and bun run build --smoke runs the ones this machine can, each also as an MCP
server driven over stdio (scripts/mcp-smoke.ts) and with selftest workers, a developer
command that starts each of the binary's Workers and round-trips a message through it.
test/release/npm-e2e.test.ts installs and updates the npm packages with bun and with npm
from a registry on localhost, as CI does; its header says how to run it. bun run format
rewrites files in the project style. VERSIONING.md describes releases.
Repository layout:
src/cli.ts entry point: parses arguments and dispatches commands
src/commands/ one module per subcommand: json, mcp, doctor, import-cc-usage, update
src/tui/ the interactive views, --once, settings
src/ingest/ reading transcripts into the store, live
src/sources/ the Claude Code and Codex transcript parsers, and account discovery
src/limits/ subscription limits, pace and limit events
src/mcp/ the MCP server: account detection, the tools, waiting for a reset
src/query/ the query layer: periods, totals and groupings, priced to the cent
src/store/ the SQLite usage store, its hourly rollup, backups and recovery
src/pricing/ the dated price table and the cost engine
src/update.ts tokenhud update: install method, releases, verified replacement
src/installs.ts every tokenhud on PATH and how it was installed, for doctor and update
test/ bun test suites
scripts/build.ts builds, checksums and smoke-tests the binaries
install.sh the Linux and macOS installer; install.ps1 is the Windows one
npm/ the npm package's command (sh) and Windows launcher; scripts/stage-npm.ts
builds the npm packages, scripts/publish-npm.ts publishes them
plugin/ the Claude Code plugin (listed by .claude-plugin/marketplace.json)