Skip to content

About

CLI for Claude and OpenAI token usage, rate-limit utilization and reset times

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

TokenCheck

TokenCheck

A zero-dependency CLI that captures every channel of telemetry Claude emits — subscription limits, local token consumption, plan and quota tier, and the OpenTelemetry stream Claude Code exports — and explains each figure alongside it. Rate limits and usage for OpenAI (ChatGPT/Codex) are reported too, from the same command.

$ tokencheck local
Claude local usage  (2026-05-07 → 2026-08-13)
  1,139 API responses · 10 sessions · 8 projects · from Claude Code session transcripts

  input                 3,748  fresh prompt tokens, billed at full rate
  cache write 1h    4,056,281  written to the 1-hour prompt cache (2x the input rate)
  cache write 5m      120,711  written to the 5-minute prompt cache (1.25x the input rate)
  cache read      313,802,138  served from cache at ~10% of the input rate
  output            1,004,836  generated by the model, incl. thinking
  total           318,987,714  every token the account was charged for
  est. cost           $222.89  estimated at Anthropic API list prices — subscription usage is not billed per token

  of which subagents/sidechains: 22 responses, 1.4M tokens (0.4%), $3.56

By model
  MODEL               RESP  INPUT  CACHE-W  CACHE-R  OUTPUT   TOTAL    EST $
  ──────────────────────────────────────────────────────────────────────────
  claude-opus-5      1,031   2.8K     3.9M   306.8M  921.8K  311.6M  $215.75
  claude-sonnet-4-6     66    939   105.9K     5.8M   66.8K    5.9M    $3.37
  claude-fable-5        22     42   120.7K     1.3M   15.6K    1.4M    $3.56

Every figure carries a one-line gloss explaining what it is. Pass --no-notes to drop them.

The four telemetry channels

Claude exposes usage data in four places. Most tools read one.

Channel What only it has Needs
Session transcripts (~/.claude/projects/**/*.jsonl) Per-response tokens, model, effort, cache TTL split, skill/MCP/subagent attribution — retroactively, for every session ever run nothing
OTLP export (CLAUDE_CODE_ENABLE_TELEMETRY=1) Tool accept/reject decisions, API errors and retries, lines of code, commits, PRs, active time, MCP connection failures a listener
OAuth endpoints Live rate-limit windows and reset times claude login
Admin Usage & Cost API Org-wide, authoritative billed cost sk-ant-admin… key

Install

Python 3.10+, no third-party packages.

pipx install .          # or: pip install .

Or run it straight from the checkout:

PYTHONPATH=src python3 -m tokencheck

Commands

Command What it reports Auth
tokencheck limits (default) Rate-limit windows, utilization and reset times — for Claude and ChatGPT/Codex OAuth
tokencheck local Token consumption from local transcripts — by day, model, project, session, MCP tool, skill, effort or version —
tokencheck plan Subscription product, rate-limit tier, org role, extra-usage state, first-token date, live windows, tool/skill counters OAuth
tokencheck collect Runs an OTLP receiver capturing what Claude Code emits —
tokencheck telemetry Renders the captured metrics and events —
tokencheck all Plan, limits, local usage and telemetry in one view OAuth
tokencheck usage Org-wide input/cache/output tokens and USD cost Admin API key
tokencheck whoami Account, organization, role and plan — for any provider OAuth
tokencheck setup What this machine still needs, and the command for each gap —
tokencheck auth Which credential sources are present (no secrets printed) —

Every command takes --json and --no-color. limits, whoami and usage take --provider/-p, accepted either before or after the subcommand. local also takes --by <dimension> and --project <substring>.

Exit codes: 0 success, 1 error, 2 auth problem.

Reporting period

usage, local, telemetry and all take --period:

--period 1h the last hour
--period 1d the last 24 hours — the default
--period 30d the last 30 days

Any Nh/Nd also parses, so --period 6h and --period 14d work. The window is trailing — now − P through now — not calendar-aligned, which is what "last 30 days" normally means. 31 days is the longest window TokenCheck will fetch.

Periods of a day or less are fetched in hourly buckets, longer ones in daily buckets; --daily shows that breakdown. One wrinkle worth knowing: both Anthropic's and OpenAI's cost endpoints only bucket by day, so on a sub-day period the cost figure covers the calendar day so far and is labelled (day so far). Token counts still honour the exact window.

--days N is still accepted as an alias for --period Nd.

Providers

tokencheck limits --provider claude|openai|all — the default is all, so a bare tokencheck reports every provider you are signed in to. One you have no credentials for is reported in place rather than failing the run.

The flag works on either side of the subcommand: tokencheck -p openai and tokencheck limits -p openai are the same command.

$ tokencheck
Claude subscription limits  (max)

  5-hour session      █░░░░░░░░░░░░░░░░░░░░░░░   4.0%  resets in 1h 41m (Aug 13, 4:49 PM)
  7-day (all models)  ░░░░░░░░░░░░░░░░░░░░░░░░   0.0%  resets in 6d 23h (Aug 20, 2:59 PM)

ChatGPT / Codex limits  (plus)
  someone@example.com

  primary (7-day)  ░░░░░░░░░░░░░░░░░░░░░░░░   0.0%  resets in 6d 23h (Aug 20, 3:08 PM)

whoami takes the same --provider and the same all default, reporting the account behind each credential — email, plan, organization and role.

tokencheck usage --provider claude|openai fetches org-wide token counts and cost. It defaults to claude rather than all: it is an admin-key report against a single organization, so there is nothing sensible to merge across providers, and -p all is rejected rather than guessed at.

usage reports API billing only. Claude Pro/Max and ChatGPT Plus/Pro subscription usage is not billed per token and never appears in these reports — limits and local are the commands that cover subscription consumption. On an individual Anthropic account usage cannot be used at all (see below).

What each provider reports:

Claude OpenAI
Rate-limit windows + reset ✓ ✓
Utilization as % used ✓ ✓
Plan / tier ✓ ✓
Token counts by model ✓ admin key ✓ admin key
Cost ✓ admin key ✓ admin key
Cache-write tokens ✓ not reported by the API

Gemini was removed

TokenCheck reported Gemini Code Assist quota until August 2026, via the private cloudcode-pa.googleapis.com endpoints the Gemini CLI uses. Google has since retired that client — the endpoint now answers with "This client is no longer supported for Gemini Code Assist for individuals" and points at Antigravity — and the provider offered no token-count or cost API to fall back on. It was dropped rather than left to decay. git log -- src/tokencheck/gemini_api.py has the implementation if it is ever worth reviving.

Account type

TokenCheck is built for individual Claude subscriptions: it reads the OAuth rate-limit windows behind a personal plan and the transcripts on this machine.

  • On a Team or Enterprise account it prints a short notice and exits 0 without running. Organization-wide usage is a different reporting problem, answered by Anthropic's Admin and Analytics APIs, which aggregate across members. Set TOKENCHECK_SKIP_ACCOUNT_CHECK=1 to run anyway.
  • On an individual account, tokencheck usage exits gracefully rather than making a request that cannot succeed — the Admin API is unavailable for individual accounts, and subscription usage is not API-billed regardless. limits and local cover that account's usage.

Classification reads organizationType, seatTier and billingType from ~/.claude.json, and fails open: an unrecognised account is unknown and nothing is gated, so a misread can never make the tool unusable.

Storing admin keys so they survive a reboot

Put them in the macOS Keychain rather than a shell rc file — a key in .zshrc gets committed if your dotfiles are version-controlled, and an exported key sits in the environment of every process you launch.

security add-generic-password -a "$USER" -s anthropic_admin_key -w 'sk-ant-admin...' -A -U
security add-generic-password -a "$USER" -s openai_admin_key    -w 'sk-admin...'     -A -U

TokenCheck reads these directly — no shell configuration, no env var.

-A matters. Without it the item's access control trusts only the process that created it, so every read from another program raises a macOS approval dialog. A non-interactive run will never answer that dialog, so the read hangs and then fails. TokenCheck reports this case as "stored, but Keychain approval pending" rather than "not set", because the two need completely different fixes. -U updates in place, so re-running the command rotates a key.

To keep the key out of ~/.zsh_history, let zsh read it silently:

read -rs "k?Admin key: " && security add-generic-password -a "$USER" -s anthropic_admin_key -w "$k" -A -U && unset k

Expired credentials

Two different mechanisms, because the credentials differ:

OAuth tokens (Claude, Codex) carry an expiry timestamp locally, so TokenCheck knows before making a request. auth shows remaining life (valid (expires in 4d 20h)), any command warns when under 15 minutes remain, and an already-expired token is a hard error naming the command that renews it.

API keys carry no expiry, so a 401 is the only signal that one has expired or been revoked. TokenCheck cannot distinguish that from a wrong-kind-of-key, so the rejection message covers both and gives the command to replace the stored copy in place.

TokenCheck also checks the key's prefix and warns before the request when you have stored an ordinary API key (sk-ant-api…, sk-proj…) rather than an admin key — those are rejected with a bare 401 that otherwise reads like a bad key rather than the wrong kind of key.

Setting up a machine

tokencheck setup (or tokencheck --setup) inspects what is already configured and prints the exact command for each gap — nothing more. It never runs an installer or a login flow.

$ tokencheck setup
TokenCheck setup
────────────────────────
  2 of 2 credentials configured

  ✓ Claude subscription   tokencheck limits, plan, whoami
  ✓ ChatGPT / Codex       tokencheck limits -p openai, whoami -p openai
  – Anthropic admin key   This looks like a regular API key (`sk-ant-api…`), not an admin key (`sk-ant-admin…`). The usage endpoints will reject it.
  – OpenAI admin key      This looks like a regular API key (`sk-proj…`), not an admin key (`sk-admin…`). The usage endpoints will reject it.

  Everything required is configured.

Optional
────────────────────────

  Anthropic admin key
      requires a Console organization — the Admin API is unavailable for
      individual accounts. Covers API usage only, not Pro/Max subscription usage

Four markers, four different situations: ✓ configured, ! present but expired, · never set up, – optional and therefore not counted against the tally. The admin keys are optional because usage is the only command that needs them, and usage covers API billing rather than subscription usage.

Local usage — why deduplication is the whole game

Claude Code writes one transcript row per content block, and every one of those rows repeats the same usage object. Resumed and forked sessions copy earlier rows into a second file, and subagents write to a nested <session>/subagents/*.jsonl a level deeper than a one-level glob will find.

On the machine this was developed against, 2,607 assistant rows are 1,101 real API responses. Summing rows inflates every number by 2.37x. TokenCheck deduplicates on message.id across all files, keeps the largest row for each (a row can be flushed before the response finishes streaming), and skips <synthetic> rows, which are Claude Code's own notices rather than API calls.

Cost is computed with the 1-hour and 5-minute cache writes priced separately (2x and 1.25x the input rate) — they are different line items, and the transcript reports them separately in cache_creation. A model with no known price shows its tokens and a — for cost; TokenCheck never guesses a rate for a model that may have shipped after this table was written.

Capturing emitted telemetry

Transcripts record what the API charged for. They say nothing about what happened around those calls. That lives in the OpenTelemetry stream, which Claude Code emits only if something is listening.

tokencheck collect --print-env      # prints the exports below
tokencheck collect                  # leave running in another shell
export CLAUDE_CODE_ENABLE_TELEMETRY=1
export OTEL_METRICS_EXPORTER=otlp
export OTEL_LOGS_EXPORTER=otlp
export OTEL_EXPORTER_OTLP_PROTOCOL=http/json
export OTEL_EXPORTER_OTLP_ENDPOINT=http://127.0.0.1:4318
export OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE=delta

delta means each export carries only the increment since the last one, so appending batches and summing them is correct. Under cumulative every export repeats the running total — summing those would multiply the figures by the number of exports. TokenCheck detects cumulative points and counts only each series' increment, so a store captured either way reports the same totals.

Then run claude in a shell carrying those exports, and read it back with tokencheck telemetry. Captured payloads are appended as NDJSON to ~/.local/share/tokencheck/ (override with $TOKENCHECK_DATA_DIR).

http/json only. OTLP's default transport is protobuf over gRPC, which is out of reach for a stdlib-only project; a protobuf request is rejected with a clear message rather than silently mis-parsed. The receiver binds to loopback only.

No conversation content. OTEL_LOG_USER_PROMPTS, OTEL_LOG_ASSISTANT_RESPONSES and OTEL_LOG_RAW_API_BODIES exist and are deliberately never set — TokenCheck captures counters, not what you typed.

Relationship to CodexBar

The endpoint, header and credential-storage knowledge for the OAuth path came from CodexBar. The two tools then diverge: CodexBar is a macOS menu-bar app covering ~69 providers broadly; TokenCheck covers one provider deeply. Verified against CodexBar main:

CodexBar TokenCheck
Providers ~69 Claude, OpenAI
OTLP telemetry capture none — zero OpenTelemetry sources in the repo receiver + renderer
Tool decisions, API errors, lines of code, commits, active time not available captured
Local transcript scan day × model day, model, project, session, MCP tool, skill, effort, version, subagent
Cache-write TTL reads the flat cache_creation field — does not distinguish 1h from 5m writes 1h and 5m split and priced separately (2x vs 1.25x)
Plan / quota tier surfaced limits and spend plus organizationType, organizationRateLimitTier, role, extra-usage state
Explanations of each figure — one-line gloss per metric
Runtime macOS 14+ app (Swift), plus a CLI stdlib Python, anywhere Python runs

The gaps above are the ones TokenCheck was extended to close. CodexBar remains far ahead on breadth, live menu-bar presentation, browser-session auth, and non-Claude providers.

Authentication

OAuth (Claude subscription). Resolved in this order:

  1. $CLAUDE_CODE_OAUTH_TOKEN — set this in CI or on a headless box (claude setup-token mints one)
  2. macOS Keychain item Claude Code-credentials — what claude login writes
  3. $CLAUDE_CONFIG_DIR/.credentials.json
  4. ~/.claude/.credentials.json

TokenCheck reads this credential and never writes it back. It deliberately does not perform an OAuth token refresh: refresh tokens rotate, so redeeming Claude Code's refresh token would invalidate the session Claude Code itself is holding. If the token has expired, TokenCheck says so and asks you to run claude.

Admin API key — organizations only. Anthropic's Admin API docs state plainly: "The Admin API is unavailable for individual accounts." An sk-ant-admin… key can only be provisioned by an admin of a Console organization, so on a personal account there is no such key to create and tokencheck usage is simply not applicable. Resolved from --admin-key, then $ANTHROPIC_ADMIN_KEY, then $ANTHROPIC_ADMIN_API_KEY, then the Keychain item anthropic_admin_key. This must be an admin key (sk-ant-admin…) from https://console.anthropic.com/settings/admin-keys — a regular API key will not authorize the Usage & Cost API. Org owner or admin role required.

OpenAI. The subscription path reads the token Codex CLI writes to ~/.codex/auth.json ($CODEX_HOME respected); re-auth is codex login. The usage path needs either an admin key (sk-admin…) from https://platform.openai.com/settings/organization/admin-keys, or a project key carrying the api.usage.read scope — OpenAI's own 403 names both routes. It is resolved from --admin-key, then $OPENAI_ADMIN_KEY, then $OPENAI_API_KEY, then the Keychain item openai_admin_key.

The same no-refresh policy applies to both: TokenCheck reads access tokens and never redeems a stored refresh token, because rotating it would invalidate the session the owning CLI is holding. An expired token is reported as expired, naming the command that renews it.

Data sources

Read-only GETs and read-only local files. TokenCheck never writes to anything under ~/.claude.

Source Purpose
GET api.anthropic.com/api/oauth/usage Subscription rate-limit windows. Requires anthropic-beta: oauth-2025-04-20 and a claude-code/<version> user agent.
GET api.anthropic.com/api/oauth/profile Account and organization identity.
GET api.anthropic.com/v1/organizations/usage_report/messages Token counts, bucketed daily, grouped by model.
GET api.anthropic.com/v1/organizations/cost_report Cost, bucketed daily. Amounts are in the currency's lowest unit (cents).
~/.claude/projects/**/*.jsonl Per-response token usage, model, effort, attribution.
~/.claude.json Plan, rate-limit tier, cached utilization, tool/skill/plugin counters.
~/.claude/stats-cache.json Claude Code's own activity rollup (corroboration only — often stale).
POST 127.0.0.1:4318/v1/{metrics,logs} The OTLP stream Claude Code emits.
GET chatgpt.com/backend-api/wham/usage ChatGPT/Codex plan and rate-limit windows. Bearer token from ~/.codex/auth.json, with a ChatGPT-Account-Id header.
GET api.openai.com/v1/organization/usage/completions OpenAI token counts, grouped by model. Buckets by 1m/1h/1d.
GET api.openai.com/v1/organization/costs OpenAI spend, grouped by line item. Daily buckets only; amounts are in whole dollars, unlike Anthropic's cents.

Credits and license

TokenCheck is MIT licensed. The endpoint, header and credential-storage details were reverse-engineered from CodexBar by Peter Steinberger — MIT licensed, which permits commercial reuse provided the copyright and permission notice are preserved. See NOTICE and third_party/CodexBar-LICENSE. No CodexBar source is copied verbatim; this is an independent Python implementation.

About

CLI for Claude and OpenAI token usage, rate-limit utilization and reset times

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages