Imported from Wicked-Sick-Ltd/token-usage (
skills/report/SKILL.md). Install upstream withnpx skills add Wicked-Sick-Ltd/token-usage --skill report. Copyright stays with the author.
token-usage report
Produce a per-activity token-usage breakdown: slash commands (Claude Code), skills (Cowork), or composer activities (Cursor), plus subagent rollups and API-equivalent cost estimates. Also handles cross-session history and transcript comparison.
Prefer the MCP tools when present
If this session exposes MCP tools from the token-usage server (session_cost,
history, insights, diff, top_consumers), call them instead of shelling out.
Host-specific tool names differ (Claude Code plugin prefix, user-scope registration, or
Cursor plugin wiring); match on the tool basename, not a single hardcoded prefix. For
Cursor, pass runtime: "cursor" (or "auto" when only Cursor artifacts exist) on
session and corpus tools. Use format: "markdown" when the user wants the table shown
verbatim. Fall back to the CLI below when the tools are absent (e.g. Cowork without MCP,
or Cursor before the plugin/MCP server is enabled).
How to run
The parser script lives at ../../scripts/token_usage.py relative to this skill's base directory (i.e. <plugin-root>/scripts/token_usage.py). Resolve the plugin root from the "Base directory for this skill" path shown above, then run:
# Current session — markdown table
python3 "<plugin-root>/scripts/token_usage.py" report [transcript-path]
# Add per-agent-type ↳ breakdown rows (subsets of parent row, not additive)
python3 "<plugin-root>/scripts/token_usage.py" report --agents [transcript-path]
# Add per-model ↳ breakdown rows (also subsets of the parent row)
python3 "<plugin-root>/scripts/token_usage.py" report --models [transcript-path]
# Compare two transcripts — per-label cost and output deltas
python3 "<plugin-root>/scripts/token_usage.py" report --diff OLD.jsonl NEW.jsonl
# Machine-readable JSON
python3 "<plugin-root>/scripts/token_usage.py" json [transcript-path]
# JSON diff between two transcripts
python3 "<plugin-root>/scripts/token_usage.py" json --diff OLD.jsonl NEW.jsonl
# Cross-session history
python3 "<plugin-root>/scripts/token_usage.py" history [--by project|day|command|model] [--since 7d|DATE] [--project SUBSTR] [--json|--csv]
# Insights — rule-based checks, no LLM involved
python3 "<plugin-root>/scripts/token_usage.py" insights [transcript-path] # session mode
python3 "<plugin-root>/scripts/token_usage.py" insights --since 7d|30d|DATE [--project SUBSTR] # window mode
python3 "<plugin-root>/scripts/token_usage.py" insights --json [transcript-path]
# Costliest sessions or commands in a window
python3 "<plugin-root>/scripts/token_usage.py" top_consumers [--by session|command] [--since 30d] [--limit N]
# Cursor — latest discovered session, or an explicit Cloud export .json path
python3 "<plugin-root>/scripts/token_usage.py" report --runtime cursor
python3 "<plugin-root>/scripts/token_usage.py" report --runtime cursor /path/to/cloud-export.json
python3 "<plugin-root>/scripts/token_usage.py" json --runtime cursor
- With no argument,
reportandjsonauto-discover the most recently modified session transcript for the current working directory's project (~/.claude/projects/<cwd-slug>/*.jsonl) — normally the live session. In Cowork (the Claude desktop app), where there is no Claude Code project for the cwd, discovery falls back to the read-only transcript mounted in the session sandbox (<mount>/.claude/projects/…,/sessions/*/mnt/.claude/projects/…). Failing both of those, it falls back further to the newest transcript under any project on the machine — so runningreport/json/insightsfrom a directory with no Claude Code history of its own will analyse whatever project's session is most recent rather than reporting "not found". Pass an explicit transcript path (orsession_idfor the MCP tools) when it matters which session gets analysed. - If the user supplied a path, treat it as the transcript path (a session's
.jsonl) and pass it through. - For
history,--sinceaccepts relative values (7d,30d) or ISO dates (2026-06-01).--bydefaults toproject.--projectis a substring filter that composes with any--by. Relative--sincewindows append a burn-rate footer (avg $/day, projected $/week). - For
insights, pass a transcript for session mode OR--sincefor window mode — not both. Session mode checks cost outlier vs the 30-day project median, prompt-cache regression, ad-hoc-work dominance, unpriced models, agent fan-out concentration, and budget pace. Window mode checks spend trend, the top mover behind an increase, and unpriced models across the window.--projectcomposes with--sincethe same way it does forhistory; it is a window-mode filter only, so passing it without--sinceis an error rather than a silently ignored flag.
A live ledger may also exist at ~/.cache/token-usage/<session-id>.json (maintained by this plugin's Stop hook). Prefer running the script fresh — it is fast (~1s) and always current mid-turn; the ledger only updates at turn boundaries. The Stop hook is Claude-Code-only, so in Cowork there is no ledger — always run the script fresh.
How to present the result
For report (current session)
- Show the markdown table the script prints, verbatim — it is already formatted (columns: Activity, Calls, Output, Input, Cache read, Cache write, Est. cost).
- Add one or two sentences of interpretation: name the biggest consumer and anything notable (e.g. a single command dominating cost, heavy subagent fan-out, unusually low cache-read ratio).
- Keep the script's pricing disclaimer line — costs are API-price estimates and subscription (Max/Pro) users are not billed per token.
For report --agents / report --models
Show the full table including the ↳ indented rows. Clarify to the user that ↳ rows (agent types or models) are subsets of their parent row's totals — they do not add to the parent, they break it down. Use --models when the user asks which model consumed the tokens (e.g. Opus main loop vs Haiku subagents).
For report --diff / json --diff
Show the diff output verbatim. Note that — in a delta column means one side had unresolvable model pricing — the tool deliberately avoids fabricating savings in that case.
For history
Show the table verbatim. If the user asked about spending over a time period (e.g. "what did I spend this week"), use --since 7d and --by day. If asking about a specific project, use --by project (or --project SUBSTR to filter to it). If asking about command patterns, use --by command. If asking which models cost the most, use --by model. If asked for a spreadsheet/export, use --csv.
For insights
Use session mode (no --since) when the user asks about the current or a specific past session (e.g. "why was this session expensive", "any tips on my token spend"). Use window mode (--since 7d|30d|DATE) when they ask about a period (e.g. "analyse my token usage this month").
- Show the findings verbatim — each is a
- [warn|info] messageline, already worded for a human to read. - Add at most 1–2 sentences of interpretation on top (e.g. which finding is most actionable). Do not restate every line in prose.
- Never invent a finding the tool didn't emit — if the tool says
No notable findings., say that plainly; it's a normal, healthy result, not a failure or something to explain away. - The output says what it managed to examine — pass that on rather than dropping it.
No sessions in window — nothing was scanned.means the scan found no transcripts at all (check the window and--project). A trailing(baseline: …)— which appears whether or not anything fired, because several rules need no baseline — means some rules were off:(baseline: N prior session(s); the comparison rules need 5)switches off cost-outlier and cache-regression for that project, and(baseline: no sessions in the window's first half; …)(orno spend …, when the first half held sessions that spent nothing) switches off spend-trend and top-mover for that window. A footnote readingNo Claude Code projects directory at <path> — nothing was scanned.means there was no corpus to read at all — usually a wrongTOKEN_USAGE_PROJECTS_DIRor a differentHOME— so report it as a setup problem, not as "you spent nothing". In every case an expensive session or a rising trend could have gone unremarked, so don't present the findings shown as the complete picture.
Interpreting the columns
- Activity — a slash command (one row per command name, summed across invocations), a skill invoked via the Skill tool in Cowork (also shown as
/skill-name), or(no command)for turns before the first command/skill in the session.(+N agents)means N subagent transcripts were rolled up into that row. - Output — tokens the model generated; the dominant cost driver at 5× the input rate.
- Cache read / Cache write — prompt-cache traffic. Cache reads cost ~0.1× the input rate (0.025× on Fable 5.1 / Mythos 5.1); large cache-read numbers are normal for long sessions and much cheaper than they look.
- Est. cost — computed per model from the bundled pricing table (
data/pricing.json) plus any user overlay, cache-aware (5m writes at 1.25×, 1h writes at 2×, reads at the model's cache-hit rate).—means the model was not in the pricing table. Intop_consumers, a trailing*marks a cost that prices only part of the row's usage (the rest ran on an unpriced model) — those rows are ranked on an understated number, so say so rather than reading the figure straight.
Troubleshooting
- "transcript not found: ": the path passed does not exist (typo, stale path, wrong machine) — check it before looking anywhere else.
- "no transcript found": nothing was passed and discovery found no transcripts at all — not under
~/.claude/projects(Claude Code), nor a Cowork mount. Ask the user for the transcript path, or list~/.claude/projects///sessions/*/mnt/.claude/projects/to locate the right transcript. - "no transcript found under … (project dir …)" from an MCP tool: the projects tree exists but that project has no sessions yet. An explicit project dir never falls back to another project's session — pass
transcriptorsession_idfor a session elsewhere. - "TOKEN_USAGE_TRANSCRIPT is set to but that file does not exist": the environment override points at a missing file; unset it or fix the path.
- Zero rows / empty table: the session has no assistant turns yet.
- Costs look ~2.5× too high vs
/cost: the dedup-by-requestId logic failed — verify the transcript entries carryrequestIdfields and report the issue. historyshows fewer sessions than expected:--sincefilters by the first timestamp in each transcript; sessions with no timestamps are skipped.