packages/skills/skills/claude-usage-calc/SKILL.md
Calculate Claude Code token consumption, message counts, and list-price cost from local JSONL transcript logs. Use when the user asks "how many tokens / prompts / messages did I use", "what's my Claude cost", "usage in last N days", or anything about local Claude Code usage analytics.
npx skillsauth add mediar-ai/skillhubz claude-usage-calcInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Compute token usage, prompt counts, and cost from local Claude Code transcript files.
~/.claude/projects/**/*.jsonl (one file per session, one JSON object per line)timestamp (ISO8601 UTC), type (user | assistant | system), and for assistant lines a message.usage block from the API responseusage block is per-API-call, NOT per-conversationVerified by inspection: turn 1 has cache_read=11k, turn 146 has cache_read=89k, growing as the cached prefix grows. Summing across turns is correct for billing because each API call is independently charged. Cache reads dominating (often 90%+ of tokens) is expected and normal, not a counting bug.
message.id — THIS IS THE BIGGEST FOOTGUNClaude Code logs the same assistant message multiple times across parent chains and sidechain entries. Without dedup, totals are inflated ~2.4×. Always keep a seen set of message.id and skip duplicates. A real measurement showed 794k raw assistant entries collapsing to 376k unique turns.
type:user entriesThe harness logs tool_result continuations as type:user. To count actual prompts the human sent, filter type:user entries AND exclude any whose message.content is a list containing a block with type=="tool_result". In a real run: 564,909 raw user entries → 53,406 actual human prompts.
timestamp, not file mtimeFile mtime is unreliable (a session touched today may include messages from weeks ago). Parse timestamp per line and bucket by (now - t).days.
ALWAYS state this explicitly in the report. If the user is on Max / Pro / committed-use / enterprise, real billing is dramatically lower. Tell them the authoritative number is at console.anthropic.com or claude.ai billing.
| Family | input | output | cache_create | cache_read | |---------|-------|--------|--------------|------------| | opus | 15.00 | 75.00 | 18.75 | 1.50 | | sonnet | 3.00 | 15.00 | 3.75 | 0.30 | | haiku | 0.80 | 4.00 | 1.00 | 0.08 |
Detect family from message.model substring (opus / sonnet / haiku). Default unknown to sonnet.
message.idtype:user entries as "prompts" (most are tool_results)timestampusage is cumulative across the conversation — it is per-API-callscripts/ (gitignored) if neededfind ... -print0 | xargs -0 cat | python3 -c '...'message.id with a seen set0-30d, 30-60d, 60-90d for trend questionsRun this to compute last-30d usage. Adjust the day window as needed.
find ~/.claude/projects -name "*.jsonl" -print0 2>/dev/null | xargs -0 cat 2>/dev/null | python3 -c "
import sys, json
from datetime import datetime, timezone
now = datetime.now(timezone.utc)
WINDOW_DAYS = 30
PRICES = {
'opus': {'in':15.00,'out':75.00,'cc':18.75,'cr':1.50},
'sonnet': {'in': 3.00,'out':15.00,'cc': 3.75,'cr':0.30},
'haiku': {'in': 0.80,'out': 4.00,'cc': 1.00,'cr':0.08},
}
def fam(m):
if not m: return 'sonnet'
m = m.lower()
if 'opus' in m: return 'opus'
if 'haiku' in m: return 'haiku'
return 'sonnet'
seen = set()
agg = {}
real_user_msgs = 0
dup_skipped = 0
for line in sys.stdin:
try:
d = json.loads(line)
ts = d.get('timestamp')
if not ts: continue
t = datetime.fromisoformat(ts.replace('Z','+00:00'))
if (now - t).days >= WINDOW_DAYS: continue
if d.get('type') == 'user':
msg = d.get('message',{})
c = msg.get('content') if isinstance(msg,dict) else None
tool_result = isinstance(c,list) and any(isinstance(x,dict) and x.get('type')=='tool_result' for x in c)
if not tool_result:
real_user_msgs += 1
continue
if d.get('type') != 'assistant': continue
msg = d.get('message') if isinstance(d.get('message'),dict) else None
if not msg: continue
mid = msg.get('id')
if mid:
if mid in seen:
dup_skipped += 1
continue
seen.add(mid)
u = msg.get('usage') or {}
f = fam(msg.get('model'))
a = agg.setdefault(f, {'in':0,'out':0,'cc':0,'cr':0,'turns':0})
a['in'] += u.get('input_tokens',0) or 0
a['out'] += u.get('output_tokens',0) or 0
a['cc'] += u.get('cache_creation_input_tokens',0) or 0
a['cr'] += u.get('cache_read_input_tokens',0) or 0
a['turns'] += 1
except: pass
grand_cost = 0.0
grand_tok = 0
print(f'{\"model\":<8} {\"turns\":>9} {\"in\":>14} {\"out\":>14} {\"cc\":>16} {\"cr\":>16} {\"cost\":>11}')
for f,a in sorted(agg.items()):
p = PRICES[f]
cost = (a['in']*p['in']+a['out']*p['out']+a['cc']*p['cc']+a['cr']*p['cr'])/1_000_000
grand_cost += cost
grand_tok += a['in']+a['out']+a['cc']+a['cr']
print(f\"{f:<8} {a['turns']:>9,} {a['in']:>14,} {a['out']:>14,} {a['cc']:>16,} {a['cr']:>16,} \${cost:>10,.2f}\")
print()
print(f'real human prompts: {real_user_msgs:,}')
print(f'unique assistant turns: {sum(a[\"turns\"] for a in agg.values()):,} (deduped {dup_skipped:,} duplicates)')
print(f'TOTAL tokens: {grand_tok:,}')
print(f'TOTAL cost (LIST price): \${grand_cost:,.2f}')
print()
print('NOTE: list price; real bill is lower if on Max/Pro/committed-use.')
print('Authoritative usage: console.anthropic.com or claude.ai billing.')
"
Always report (in this order):
30-60d and 60-90d and explain growth drivers (cache_read inflation from longer sessions / parallel agents is normal)tools
Design web-like user interfaces in the terminal and inside tmux with a cell-grid Canvas, CSS-like box model, flexbox/grid layout, and 15 reusable widgets such as Panel, Table, Card, ProgressBar, Meter, Tabs, Tree, Badge, Banner, and a braille line chart. Use when an agent needs a dashboard, panel, table, status page, TUI layout, tmux dashboard, screenshot-driven CLI/TUI replica, ANSI frame, truecolor render, pyte PNG screenshot smoke test, wide-character alignment, or a new terminal widget.
tools
Drive interactive terminal (TUI) programs — CLIs, REPLs, installers, menu apps, agent CLIs, and editors like vim — through a PTY, reading semantic screen snapshots. A pattern library classifies a screen (REPL, menu, pager, fzf search, confirm dialog, form, spinner, wizard) and drives it with a ready recipe. Use when a program expects a live terminal (arrow-key menus, prompts, spinners, password fields, curses UIs), or when a piped command hangs or prints nothing.
tools
Design and render terminal/CMD visual effects and ASCII art from a one-line request via the pluggable `fx` engine (18 hot-swappable, themeable effects plus scripted shows). Effects include donut, matrix rain, plasma, fire, a spinning 3D ball, Game of Life, wireframe cube, 3D text banners, rainbow/lolcat gradient text, starfield, tunnel, fireworks, image-to-ASCII, and more. Use when the request is for a terminal animation, ANSI/CLI art, or a new console effect. Pure Python stdlib; truecolor.
tools
# X Twitter Scraper Use Xquik for X/Twitter tweet search, user lookup, profile tweets, follower export, media download, monitors, webhooks, posting workflows, and MCP-backed API exploration. ## Prerequisites - A Xquik API key in `XQUIK_API_KEY`. - Internet access to `https://xquik.com/api/v1`, `https://xquik.com/mcp`, and `https://docs.xquik.com`. - A clear user request that identifies the target tweets, users, accounts, keywords, media, monitor, webhook, or write action. ## Source Truth -