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
# 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 -
tools
Use when the user says "mk0r", "appmaker CLI", "open a VM", "run something in the sandbox", "talk to the VM agent", "spin up an E2B sandbox", or "chat with appmaker from CLI." Wraps the `mk0r` CLI to list projects, exec commands inside their E2B sandboxes, stream chat with the VM agent (same `/api/chat` the web UI uses), toggle SOAX residential IP, manage schedules, and copy files. Supports a sticky default project via `mk0r projects use`.
testing
Use when the user mentions "influencer candidates", "social media operator", "check proposals on Upwork/Fiverr", "review influencer applications", "qualify candidates", or "reach out to operators". Manages the IG/TikTok account operator hiring pipeline — review applicants, check replies, qualify, and do proactive outreach.
tools
End-to-end newsletter pipeline: investigate recent features, draft, send via API endpoint, and track delivery/open/click metrics.