npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

tokenhud

v0.1.5

Published

Live terminal heads-up display for coding-agent usage, limits and cost

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.

tokenhud's Overview on made-up accounts: a limits card per account, spend from the last hour to all time, a 24-hour cost chart, the top models and the week's limit events

The Overview on made-up accounts. Views explains every part of every screen.

Install

With Bun (recommended on Linux and macOS):

bun add -g tokenhud

No 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 tokenhud installs a command that fails at once with interpreter executable "/bin/sh" not found. On Windows, use npm i -g tokenhud or 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 | sh

On Windows (PowerShell):

irm https://raw.githubusercontent.com/ZhuoQiuMcgill/tokenhud/main/install.ps1 | iex

Both 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 | iex

Alpine 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 tokenhud

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

The Overview with seven numbered boxes: header, limits cards, MCP agents, spend, activity chart, top models, limit events

  1. 🟥 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.
  2. 🟧 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 and avg over the week so far, that <2h means within 2 hours, and that every countdown and time on a card is an estimate. Reading a limits card explains each reading.
  3. 🟨 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 session when 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.
  4. 🟩 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. 1h and 5h are the last 60 minutes and the last 5 hours (shown on screens 120 columns wide or more). today, this week and this month start at local midnight, on Monday and on the 1st. all-time is everything tokenhud has stored, including usage whose transcripts are gone. For * and ≈, see Glyphs and colours.
  5. 🟦 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), and t switches 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.
  6. 🟪 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/d switch the window with the chart's, and t ranks by tokens. A fast or priority tier gets its own row, marked (fast). A model with no published price shows unpriced and 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.
  7. 🟫 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:05 is when tokenhud first saw the window usable again after its reset; resets and 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

Close-up of four limits cards, with the account, meters, percentages and countdowns, pace, verdict, stale age and a not-signed-in account boxed and numbered

  1. 🟥 Account. The account's label and its provider, claude or codex. The label comes from the account's config directory (~/.claude-work is work) unless you renamed it.
  2. 🟧 Meters. The 5h row is the 5-hour window, the week row 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.
  3. 🟨 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; 1h52m is the time left until that window resets. On the weekly row, 41% used and 5d21h (5 days 21 hours) to go. Once a window has reset, the card reads 0 % and — until the next fetch.
  4. 🟩 Pace. The spend pace the verdict comes from, at API prices, as dollars per hour (tokens per hour with costs hidden). pace with (30m) is what the account spent in the last 30 minutes: $6.8/h here, and $0/h for nothing in that time. avg with this week is 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) or this week goes first, then the word; the number stays.
  5. 🟦 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 (just now under 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's this week first, then the time, then the in, 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, or idle · 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.
  6. 🟪 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.
  7. 🟫 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.

The History view with six numbered boxes: tabs, heat map, day card, period table, totals, footer

  1. 🟥 Tabs. What the table lists, switched with a/d; the one shown is in brackets. this week and this month list the days so far of the current week or month (History opens on this week), days every day of the heat map, weeks (Monday to Sunday) and months one row each. On the right, what * and ≈ mean, and f, the model filter: with a filter, every number on the screen counts only the models whose name or id contains what you typed.
  2. 🟧 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.
  3. 🟨 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%.
  4. 🟩 Period table. The rows of the tab shown, newest first, moved through with w/s. On the weeks or months tab, enter lists a row's days and esc goes back; on a day with limit events, enter lists them. input, output and cache (reads and writes) are tokens; cost is at API prices. vs 30-day avg compares 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 model is the period's most expensive model, accounts those with usage, most cost first.
  5. 🟦 Totals. Every period listed, added up: here the 177 days of the heat map's 26 weeks, today included.
  6. 🟪 Footer. Its first line is the keys of the view you are on: a/d its tabs, w/s the selection, enter to open it, then the view's own; esc back joins 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.

The Models view with five numbered boxes: rate board, total, footnotes, rates card, who used it

  1. 🟥 Rate board. Every model used in the window, by cost (r sorts by tokens, then by name). The tabs on the right are the windows, switched with a/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 $/M rate they are billed at today, in dollars per million tokens (—: no price). cost prices 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, and enter shows or hides its cards below.
  2. 🟧 Total. All models together. Rates don't add up, so the total has none.
  3. 🟨 Footnotes. $/M is 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-review is priced as the model OpenAI said serves it.
  4. 🟩 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.
  5. 🟦 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.

The Accounts view with six numbered boxes: account list, selected account, where it comes from, limits, weekly history, last 30 days

  1. 🟥 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/s select an account, and enter opens 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.
  2. 🟧 Account. The selected account, its provider, and when its limits were last fetched.
  3. 🟨 Where it comes from. root is 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) or disabled. history: how many requests tokenhud has stored for it, and the day of the first.
  4. 🟩 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.
  5. 🟦 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.
  6. 🟪 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).
  • < in 100% in <2h: within that long, an estimate. ~ in wk ~94%, 100% in ~3d or (~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-work is labelled work);
  • Codex: ~/.codex and $CODEX_HOME;
  • under WSL, the same directories on the Windows side (/mnt/c/Users/*/.claude*, /mnt/c/Users/*/.codex*), labelled with a -win suffix. 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@tokenhud

The 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 mcp

Then add the alert hooks the plugin would have brought, once per account:

tokenhud mcp install --hooks
tokenhud mcp install --hooks --config-dir ~/.claude-work

Native 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 session alert (the default) ends with its Claude Code session: tokenhud removes it when the session ends, or after 24 hours without any activity from it. A persistent one 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 only limits.json and alerts.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 --hooks adds it to the account's settings.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 when settings.json is a link), and tokenhud mcp install --hooks --remove takes it out. tokenhud doctor shows which accounts have it; set_alert warns 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 accounts

Each 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 *, and tokenhud doctor lists the models and how much of your usage is priced.
  • codex-auto-review is 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.db remembers 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 claude command refresh it. For Codex it asks the installed codex app 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 store

A 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 it

How tokenhud update updates depends on how tokenhud was installed:

  • With Bun or npm (globally): it asks the package manager which version npm's latest tag points at (next for a release candidate, as long as next is no older than it), installs exactly that version (bun add -g --no-cache [email protected] or npm install -g [email protected]), then checks that the tokenhud command runs it and says which version it went from and to. It never installs an older version than the one you have; --allow-downgrade does. --no-cache makes Bun ask the registry rather than reuse an answer from a few minutes ago.
  • With install.sh or install.ps1: the binary replaces itself. It downloads the new release, checks its SHA-256 against the release's SHA256SUMS, 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:

  1. Remove the program: bun remove -g tokenhud or npm uninstall -g tokenhud; for install.sh's binary, rm ~/.local/bin/tokenhud; on Windows, delete %LOCALAPPDATA%\tokenhud and remove its bin folder from your user PATH (Settings › System › About › Advanced system settings › Environment Variables).
  2. Remove it from Claude Code, once per account: claude plugin uninstall tokenhud@tokenhud or claude mcp remove -s user tokenhud.
  3. 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 source

bun 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)

License

MIT