claude_tokens.5m.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Show hidden characters
#!/usr/bin/env python3
import json
import subprocess
import os
import glob
from datetime import datetime
from typing import Any
def format_number(num):
"""Formats a number into a human-readable string with K/M suffixes."""
if num >= 1000000:
return f"{num / 1000000:.1f}M"
if num >= 1000:
return f"{num / 1000:.1f}K"
return str(num)
def get_ccusage_data() -> dict[str, Any]:
"""Fetches Claude Code usage statistics using the `npx ccusage@latest -j` command."""
try:
env = os.environ.copy()
common_paths = [
"/usr/local/bin",
"/usr/bin",
"/bin",
"/opt/homebrew/bin", # Homebrew on Apple Silicon
os.path.expanduser("~/.nvm/versions/node/*/bin"), # NVM paths
os.path.expanduser("~/node_modules/.bin"), # Local node modules
]
expanded_paths = []
for path in common_paths:
if "*" in path:
expanded_paths.extend(glob.glob(path))
elif os.path.exists(path):
expanded_paths.append(path)
current_path = env.get("PATH", "")
for path in expanded_paths:
if path not in current_path:
current_path = f"{path}:{current_path}"
env["PATH"] = current_path
result = subprocess.run(
["npx", "ccusage@latest", "-j"],
capture_output=True,
text=True,
timeout=30,
check=False,
env=env,
)
if result.returncode == 0:
return json.loads(result.stdout)
return {
"error": f"Command failed with code {result.returncode}",
"stderr": result.stderr,
"stdout": result.stdout,
}
except subprocess.TimeoutExpired:
return {"error": "Command timed out after 30 seconds"}
except json.JSONDecodeError as e:
return {"error": f"JSON decode error: {e}", "stdout": result.stdout}
except FileNotFoundError:
return {"error": "npx command not found - Node.js may not be installed"}
def main():
"""Main function to fetch and display Claude Code usage statistics."""
today = datetime.now().strftime("%Y-%m-%d")
data = get_ccusage_data()
if not data or (isinstance(data, dict) and "error" in data):
print("⚠️ Error")
print("---")
if isinstance(data, dict) and "error" in data:
print(f"Error: {data['error']}")
if "stderr" in data:
print(f"Stderr: {data['stderr']}")
if "stdout" in data:
print(f"Stdout: {data['stdout']}")
else:
print("Failed to fetch usage data")
return
today_usage = None
for day in data.get("daily", []):
if day.get("date") == today:
today_usage = day
break
if not today_usage:
print("📊 0 tokens")
print("---")
print("No usage today")
return
total_tokens = today_usage.get("totalTokens", 0)
total_cost = today_usage.get("totalCost", 0)
print(f"📊 {format_number(total_tokens)}")
print("---")
print(f"Today's Usage ({today})")
print(f"Total Tokens: {format_number(total_tokens)}")
print(f"Input: {format_number(today_usage.get('inputTokens', 0))}")
print(f"Output: {format_number(today_usage.get('outputTokens', 0))}")
print(f"Cache Creation: {format_number(today_usage.get('cacheCreationTokens', 0))}")
print(f"Cache Read: {format_number(today_usage.get('cacheReadTokens', 0))}")
print(f"Cost: ${total_cost:.2f}")
print("---")
totals = data.get("totals", {})
print("Total Usage (All Time)")
print(f"Total Tokens: {format_number(totals.get('totalTokens', 0))}")
print(f"Total Cost: ${totals.get('totalCost', 0):.2f}")
if __name__ == "__main__":
main()
source & further reading
gist.github.com — original article
A system prompt to stop AI from writing like a LinkedIn/X thought leader.
terminal-browser — setup guide: standalone, as a herdr plugin, or hand it to your agent (yoelgal/terminal-browser fork, upstream-proposal branch)
Building an LLM Wiki for Your Project — a step-by-step guide (agent-maintained knowledge base: schema, ingest/query/lint workflows, qmd search, lint script)