session-cost
Skill0 starsChanged 3 months agoMITView on GitHub
Compute token usage and USD cost for Claude Code sessions by parsing local transcript files, and track work against a self-imposed spend budget. Use when the user asks what a session cost, how many tokens were used, "what's my spend", "cost breakdown", "token usage", asks for /cost-style information, compares cost across sessions or models, or asks to set a budget/target and keep working until it is reached.
- Reads credentials
4 other projects use a version of this.
Adopted by
Most recently taken up by
- PeteChu/skillstheir own version, first seen Oct 11, 2026
- dewil/ai-toolkittheir own version, first seen Aug 25, 2026
- dewil/claude-toolkittheir own version, first seen Aug 25, 2026
- MikkoNumminen/claude-skillstheir own version, first seen Jun 22, 2026
Other versions4 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 4
- dewil/ai-toolkit★ 9same name
- dewil/claude-toolkit★ 9same name
- PeteChu/skills★ 1same name
- MikkoNumminen/claude-skills★ 0same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
The file
We split this skill into the rules it gives an agent
4 rules. About 0 are common, 2 are distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈2
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 36
Run it from the directory the session belongs to — the project slug is derived from cwd (path with / replaced by -).
- Distinctive: line 166
Do a meaningful chunk of real work — a feature, a fix, a file.
- Very specific: line 167
Run --status and read the verdict.
- Distinctive: line 172
The budget is a ceiling, not a quota to spend: If the task is done at 30% of budget, stop and say so.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Session Cost
The built-in /cost command is handled by the CLI and cannot be invoked by Claude. This
skill reconstructs the same information from the transcript files on disk.
Where the data lives
~/.claude/projects/<cwd-slug>/<session-uuid>.jsonl — one JSON object per line. Every
assistant turn carries message.model and message.usage:
input_tokens— uncached inputoutput_tokenscache_creation.ephemeral_5m_input_tokens/ephemeral_1h_input_tokenscache_read_input_tokensspeed—"fast"means fast mode (premium pricing on Opus 5 / 4.8)
There is no costUSD field in current versions, so cost is derived from a pricing
table in the script. usage.iterations is a per-attempt breakdown of the same turn —
do not add it to the top-level totals.
Usage
python3 $HUD/cost.py # current session (newest transcript)
python3 $HUD/cost.py --all # every session for this cwd
python3 $HUD/cost.py --session a1b2c3d4 # by id or prefix
python3 $HUD/cost.py --project ~/.claude/projects/<cwd-slug>
python3 $HUD/cost.py --json # machine-readableRun it from the directory the session belongs to — the project slug is derived from
cwd (path with / replaced by -). "Current session" = most recently modified
transcript in that directory, which is the live one.
Budgets — working toward a target
Two independent gates: real plan limits (from Anthropic) and a self-imposed spend
budget (local). --status checks both and stops on whichever trips first.
Plan limits — real, but via an undocumented endpoint
Nothing on disk carries quota state (transcripts have no rate_limit_info / resetsAt
— verified across the full record-key set). But the live numbers are one authenticated
GET away, which is how openusage does it:
token ← macOS keychain "Claude Code-credentials" (source of truth on macOS)
← $CLAUDE_CONFIG_DIR/.credentials.json (often stale — check expiresAt)
← $CLAUDE_CODE_OAUTH_TOKEN
GET https://api.anthropic.com/api/oauth/usage
Authorization: Bearer <token>
anthropic-beta: oauth-2025-04-20Response carries a limits[] array (kind, percent, severity, resets_at) plus
flat five_hour / seven_day objects and extra_usage. Handling rules:
- Never print, log, or echo the token.
read_oauth_token()returns it to one caller which puts it straight into a header and drops it. Keep it that way. - This is not documented API surface. It can change shape or vanish; every call path
degrades to "Plan limits unavailable:
<reason>" rather than failing the run. - It throttles. Responses cache for 5 minutes (
CACHE_TTL); on 429/5xx the skill backs off 15 minutes (BACKOFF) and serves the stale copy. Do not poll per turn. - Token refresh is out of scope. Claude Code keeps the keychain entry fresh. On a 401 the skill says the entry looks stale rather than writing new credentials itself.
Model-scoped windows. A weekly_scoped entry carries scope.model.display_name
naming the model it caps, and is_active: true marks the window actually binding right
now. limit_rows() renders these as weekly:Fable* — a bare "weekly_scoped" label is
useless, since the whole question is which model.
Gating is model-aware, and must stay that way. A Fable-scoped cap at 100% must not
halt an Opus session. report_status() compares each scoped window against the model
in use (taken from the transcript's most recent usage record) and sorts them into
blocked vs advisory; only blocked returns exit 2. Unscoped windows (session,
weekly_all) always apply. Every window shows its own reset countdown — ↻6h55m in
the statusline, in 6h55m (23:00) in the table.
Always-on statusline
$HUD/statusline.py renders limits + live spend on every prompt, wired into
~/.claude/settings.json as statusLine.command. Output looks like:
5h 8% │ wk 75% │ scoped 100% │ ↻23:00 │ $15.26 │ Opus 5Green / yellow / red track severity. It costs zero tokens — the CLI runs it and
prints to the terminal; the output never enters the model's context.
The statusline payload is the primary source — read it before adding anything. Claude
Code passes a rich JSON blob on stdin, which already carries context_window
(used_percentage, context_window_size, total_input_tokens), rate_limits
(five_hour / seven_day with used_percentage and epoch resets_at), cost,
model, effort, and exceeds_200k_tokens. All of it is free and always fresh.
Dump stdin to a file from the script to inspect the current shape rather than guessing.
Consequently the statusline prefers payload values for the 5h/weekly windows and calls
the API cache only for what the payload lacks: model-scoped caps (weekly:Fable) and
severity. Older CLI versions send no rate_limits, so the API path remains as fallback.
cost.total_cost_usd in the payload is not the session total. It counts from CLI
process start, so a restart or resume zeroes it while the transcript keeps accumulating —
observed $6.95 (payload) vs $34.49 (transcript) for the same session. Both are correct
over different spans; this skill reports the transcript figure, which is the session's
whole life. Growth per turn matches between the two, which is how the gap was diagnosed.
Two invariants keep it fast enough to run per keystroke-render (~26ms):
- Never fetch inline. It reads the cached usage blob and, when stale, spawns a
detached
cost.py --limits --refresh. The current render uses slightly old data rather than waiting on the network. - Never re-parse the transcript. Spend is scanned incrementally from a byte offset
in
cache/spend-<session>.json. Transcripts are append-only, so each render parses only new bytes.
Dedupe on requestId when touching either scanner. One assistant turn is written as
several records sharing a requestId, each repeating the same usage block — counting
them all inflates spend roughly 2.5x. scan() and spend_usd() both guard against it,
and they should agree to the cent; if they diverge, that guard is the first suspect.
Where the scripts live
$HUD below is this bundle's scripts/ directory:
- installed as a plugin →
${CLAUDE_PLUGIN_ROOT}/scripts - cloned standalone → the repo's
scripts/directory
Resolve it once, then use the commands as written. Runtime state (budget targets, the
cached usage blob) lives in ~/.claude/session-cost/, overridable with
SESSION_COST_HOME — deliberately outside the install directory so a plugin update or
re-clone cannot wipe it.
Commands
python3 $HUD/cost.py --limits # plan windows only
python3 $HUD/cost.py --limits --refresh # bypass the 5-min cache
python3 $HUD/cost.py --set-budget 12.00 --note "refactor the API layer"
python3 $HUD/cost.py --set-token-budget 2000000
python3 $HUD/cost.py --status # budget + limits + verdict
python3 $HUD/cost.py --status --no-limits # budget only, no network
python3 $HUD/cost.py --clear-budget--status stops on whichever gate trips first: any window at severity: critical or
past --limit-threshold (default 95%), or the local budget.
Targets persist per session in targets/<session-uuid>.json, so --status works across
turns. --status exit codes are the branch point:
| exit | meaning | what to do |
| 0 | under budget | keep working |
| 2 | budget reached | stop, wrap up, report to the user |
| 3 | no budget set | ask the user for a target, or just report spend |
How to run a budgeted work loop
- Set the budget once, with a
--notenaming the actual goal. - Do a meaningful chunk of real work — a feature, a fix, a file.
- Run
--statusand read the verdict. - On
CONTINUE, do the next chunk. OnSTOP, finish cleanly and report.
Two rules that keep this honest:
- The budget is a ceiling, not a quota to spend. If the task is done at 30% of budget, stop and say so. Never invent filler work to consume the remainder — a budget authorizes spending, it does not require it.
- Check between chunks, not between tool calls. Polling
--statusafter every command burns tokens measuring token burn.
For a genuinely open-ended loop, pair this with the /loop skill (self-paced repeats)
rather than hand-rolling one. Note also that this harness has a native token target:
the user can append +500k-style directives to a prompt, which populates
budget.total / budget.spent() / budget.remaining() inside the Workflow tool.
That one is enforced by the runtime — agent() calls throw once the target is hit —
whereas this skill's budget is advisory and depends on Claude actually checking it.
Reporting results
Report the total and the per-model breakdown. Two caveats worth stating once:
- These are list prices. On a Pro/Max subscription there is no per-token bill, so
the figure is notional spend — point the user at
/usagefor actual plan limits. - Cache writes bill at 1.25x (5m TTL) / 2x (1h TTL) the input rate; cache reads at 0.1x. Long sessions are usually dominated by cache reads, which is why the total is far below what raw token counts suggest.
Maintaining the pricing table
PRICING in cost.py is USD per million tokens, (input, output). It is a cached
snapshot — when a new model ships or rates change, update that dict. Do not write
prices from memory; load the claude-api skill, which carries the current table, or
fetch https://platform.claude.com/docs/en/pricing.md. Unknown models fall back to a
longest-prefix match (so dated snapshots like claude-haiku-4-5-20251001 resolve), and
anything still unmatched is reported as unpriced rather than silently costed at zero.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

