Developer Tools AI Infrastructure 161 vues

Stop Flying Blind: Track Every Claude Code Dollar with claude-usage

B
Bright Coding
Auteur
Stop Flying Blind: Track Every Claude Code Dollar with claude-usage

Stop Flying Blind: Track Every Claude Code Dollar with claude-usage

Your Claude Code bill is a black box. Here's how to crack it open.

Every day, thousands of developers fire up Claude Code, pound out thousands of tokens, and have absolutely zero idea what it's actually costing them. Anthropic's native interface? It gives you crumbs. A vague sense of usage, maybe a notification when you're "getting close" — but never the granular, session-by-session, model-by-model breakdown that engineering teams desperately need to control spend.

Sound familiar? You've probably felt that nagging suspicion: "Am I burning through my Pro plan limits? Is that massive refactor session costing me $5 or $50?" The anxiety is real, and it's justified. Claude Code writes detailed JSONL logs locally — token counts, models, sessions, projects — regardless of whether you're on API, Pro, or Max. That data is sitting on your machine right now, completely untapped. Like having a detailed receipt in your pocket while you're still guessing the total.

Enter claude-usage, the open-source dashboard that transforms those hidden logs into crystal-clear visualizations and cost estimates. Created by The Product Compass Newsletter, this zero-dependency Python↗ Bright Coding Blog tool is the financial transparency tool Claude Code users never knew they needed — until their first jaw-dropping bill.


What is claude-usage?

claude-usage is a local-first dashboard for tracking Claude Code token consumption, cost estimates, and session history — entirely from logs already stored on your machine. No cloud dependencies. No API keys. No third-party services harvesting your data.

The project lives at github.com/phuryn/claude-usage and has quickly become the go-to solution for developers who refuse to accept "trust us, it'll be fine" as a cost management strategy.

Why It's Trending Right Now

Three forces are converging to make claude-usage essential:

  1. Claude Code adoption is exploding — Anthropic's CLI and VS Code extension are now standard tooling for serious developers, but the company prioritizes product velocity over spend transparency.

  2. Token costs are non-trivial — At $15-25 per million output tokens for premium models, a heavy coding session can easily run $10-20. Multiply across a team, and you're looking at real budget impact.

  3. The "Pro/Max progress bar" gap — Anthropic teases usage visibility for paid subscribers, but it's incomplete. claude-usage delivers the full picture for everyone, including API users who get zero native tooling.

The killer insight? Claude Code writes one JSONL file per session to ~/.claude/projects/ — structured data with token counts, model identifiers, and cache operations. claude-usage simply reads what Claude already wrote, parses it into SQLite, and serves visualizations via a local HTTP server. Elegant. Brutally effective.


Key Features That Separate It from Guesswork

Zero-Dependency Architecture

Built entirely on Python's standard library: sqlite3 for storage, http.server for the dashboard, json and pathlib for parsing. No pip install, no requirements.txt, no dependency hell. If you can run Claude Code, you can run this.

Incremental Scanning Engine

The scanner tracks file paths and modification times. First run processes everything; subsequent runs fly through only new or changed sessions. For developers with hundreds of historical sessions, this matters enormously.

Multi-Source Log Ingestion

Captures usage from three critical vectors:

  • Claude Code CLI — terminal-based claude command sessions
  • VS Code extension — sidebar-driven interactions
  • Dispatched Code sessions — programmatically routed workflows

Real-Time Cost Estimation

Uses Anthropic's April 2026 API pricing to calculate spend. Distinguishes input tokens, output tokens, cache writes, and cache reads — each with distinct cost profiles. Only opus, sonnet, and haiku models are priced; others display as n/a to prevent misleading estimates.

Pro/Max Progress Bar Visualization

For subscription users, the dashboard renders usage progress against plan limits. Finally: visual confirmation of where you stand, not just "you're fine" or "slow down."

Auto-Refreshing Browser Dashboard

Serves Chart.js visualizations at localhost:8080 with 30-second auto-refresh. Model filtering with bookmarkable URLs. Environment-variable configuration for host/port binding. It's monitoring infrastructure, not a toy.

Terminal Summaries for Quick Checks

today, week, and stats commands deliver instant CLI visibility when you don't need the full browser experience.


Use Cases: Where claude-usage Pays for Itself

1. The Freelancer Managing Margins

You're billing clients for AI-assisted development, but your Claude Code costs are invisible overhead. claude-usage lets you attribute spend to specific projects via session metadata, ensuring your rates actually cover tool costs. That "quick script" that consumed 2M output tokens? Now you know it was a $30 session, not $3.

2. The Engineering Manager with Team Spend Anxiety

Your five-developer team all has Claude Code access. Monthly bills arrive as a single line item. claude-usage enables per-developer, per-project, per-model analysis from local logs — the foundation for usage policies and cost allocation that actually work.

3. The Pro Subscriber Hitting Invisible Walls

Anthropic's progress bar is vague. You're "approaching limits" but when? At what cost? claude-usage reveals your actual burn rate, letting you optimize: switch to haiku for exploration, reserve opus for final implementation, time heavy sessions strategically.

4. The API User Building Production Pipelines

No subscription safety net — every token is real money. claude-usage provides the monitoring layer Anthropic doesn't: historical trends, cost projections, cache efficiency analysis. Essential for budgeting and anomaly detection in automated workflows.

5. The Developer Optimizing Cache Efficiency

Cache reads cost 10-20x less than fresh inputs. claude-usage breaks down cache_creation_input_tokens vs cache_read_input_tokens, exposing whether your prompt engineering actually saves money or just feels clever.


Step-by-Step Installation & Setup Guide

Prerequisites

  • Python 3.8+ (Claude Code requires this anyway)
  • Git (for cloning)
  • Existing Claude Code usage (JSONL logs to parse)

Clone and Launch

Windows:

git clone https://github.com/phuryn/claude-usage
cd claude-usage
python cli.py dashboard

macOS / Linux:

git clone https://github.com/phuryn/claude-usage
cd claude-usage
python3 cli.py dashboard

That's it. No virtual environment. No pip install -r requirements.txt. The dashboard spins up at http://localhost:8080.

Initial Data Population

Before visualizations appear, scan your existing logs:

# macOS/Linux — use python3
python3 cli.py scan

This populates ~/.claude/usage.db from JSONL files in:

  • ~/.claude/projects/ (default Claude Code directory)
  • ~/Library/Developer/Xcode/CodingAssistant/ClaudeAgentConfig/projects/ (Xcode integration)

The scanner is incremental — future runs only process new or modified files.

Advertisement

Custom Configuration

Custom host/port (for remote access or port conflicts):

HOST=0.0.0.0 PORT=9000 python3 cli.py dashboard

Custom projects directory (non-standard Claude Code installation):

python3 cli.py scan --projects-dir /path/to/transcripts

Verification

After scanning, verify data ingestion:

python3 cli.py today    # Today's usage by model
python3 cli.py week     # Last 7 days with per-day breakdown
python3 cli.py stats    # All-time statistics

REAL Code Examples from the Repository

Example 1: Zero-Dependency Dashboard Server

The entire HTTP serving infrastructure, using only Python standard library:

# dashboard.py serves Chart.js visualizations via http.server
# No Flask, no FastAPI, no external dependencies

import http.server
import socketserver
import sqlite3
from pathlib import Path

# Configuration from environment variables with sensible defaults
HOST = os.environ.get('HOST', 'localhost')  # Bind address
PORT = int(os.environ.get('PORT', '8080'))  # Listening port

class DashboardHandler(http.server.SimpleHTTPRequestHandler):
    """Serves the single-page dashboard with embedded data queries."""
    
    def do_GET(self):
        # Route handling for API endpoints vs. static dashboard
        if self.path.startswith('/api/'):
            self._serve_api()
        else:
            self._serve_dashboard_html()
    
    def _serve_api(self):
        """Query SQLite and return JSON for Chart.js rendering."""
        conn = sqlite3.connect(Path.home() / '.claude' / 'usage.db')
        # ... query construction based on model filters from URL params

Why this matters: The http.server + socketserver combination eliminates entire categories of deployment complexity. No dependency conflicts, no security advisories for abandoned packages, no version pinning nightmares. For a local-only tool, this is engineering discipline — resisting the temptation to over-engineer.

Example 2: Incremental JSONL Scanner

The core data pipeline that makes repeated scans instantaneous:

# scanner.py — parses Claude Code's JSONL transcripts
# Tracks file state to avoid reprocessing unchanged sessions

import json
import sqlite3
from pathlib import Path

def scan_projects(projects_dir: Path, db_path: Path):
    """
    Incrementally scan JSONL files and update SQLite database.
    Only processes new or modified files on subsequent runs.
    """
    conn = sqlite3.connect(db_path)
    cursor = conn.cursor()
    
    # Ensure tracking table exists for incremental logic
    cursor.execute('''
        CREATE TABLE IF NOT EXISTS _file_state (
            path TEXT PRIMARY KEY,
            mtime REAL,  -- modification time for change detection
            size INTEGER
        )
    ''')
    
    for jsonl_file in projects_dir.rglob('*.jsonl'):
        stat = jsonl_file.stat()
        
        # Check if file was already processed and unchanged
        cursor.execute(
            'SELECT mtime, size FROM _file_state WHERE path = ?',
            (str(jsonl_file),)
        )
        row = cursor.fetchone()
        
        if row and row[0] == stat.st_mtime and row[1] == stat.st_size:
            continue  # Skip unchanged files — this is the performance win
        
        # Process new/changed file
        with open(jsonl_file, 'r') as f:
            for line in f:
                record = json.loads(line)
                if record.get('type') == 'assistant':
                    usage = record['message']['usage']
                    # Extract and store token metrics
                    cursor.execute('''
                        INSERT INTO usage_records 
                        (timestamp, model, input_tokens, output_tokens,
                         cache_creation_input_tokens, cache_read_input_tokens)
                        VALUES (?, ?, ?, ?, ?, ?)
                    ''', (
                        record['timestamp'],
                        record['message']['model'],
                        usage['input_tokens'],
                        usage['output_tokens'],
                        usage.get('cache_creation_input_tokens', 0),
                        usage.get('cache_read_input_tokens', 0)
                    ))
        
        # Update file state for next incremental run
        cursor.execute('''
            INSERT OR REPLACE INTO _file_state (path, mtime, size)
            VALUES (?, ?, ?)
        ''', (str(jsonl_file), stat.st_mtime, stat.st_size))
    
    conn.commit()

The performance insight: For developers with months of Claude Code history, full rescans would be punishing. The _file_state table with mtime/size comparison turns subsequent runs into sub-second operations. This is the difference between a tool you actually use and one you abandon after the first slow scan.

Example 3: CLI Entry Point with Command Routing

The unified interface that makes all functionality discoverable:

# cli.py — command-line interface with subcommand dispatch

import argparse
import sys
from pathlib import Path

def main():
    parser = argparse.ArgumentParser(
        description='Claude Code usage tracker and dashboard'
    )
    subparsers = parser.add_subparsers(dest='command', required=True)
    
    # scan: populate database from JSONL files
    scan_parser = subparsers.add_parser('scan', help='Scan JSONL and update database')
    scan_parser.add_argument(
        '--projects-dir',
        type=Path,
        help='Custom Claude projects directory (default: ~/.claude/projects/)'
    )
    
    # today: terminal summary for current day
    subparsers.add_parser('today', help="Show today's usage summary by model")
    
    # week: 7-day breakdown with per-day and by-model totals
    subparsers.add_parser('week', help='Show last 7 days usage breakdown')
    
    # stats: all-time aggregated statistics
    subparsers.add_parser('stats', help='Show all-time statistics')
    
    # dashboard: scan + serve browser visualization
    dashboard_parser = subparsers.add_parser('dashboard', help='Scan and open dashboard')
    # HOST and PORT handled via environment variables, not argparse
    # This allows easy containerization and systemd service files
    
    args = parser.parse_args()
    
    # Dispatch to appropriate handler
    if args.command == 'scan':
        from scanner import scan_projects
        projects_dir = args.projects_dir or (Path.home() / '.claude' / 'projects')
        scan_projects(projects_dir, Path.home() / '.claude' / 'usage.db')
    elif args.command == 'today':
        from reports import print_today_summary
        print_today_summary()
    # ... additional command handlers
    elif args.command == 'dashboard':
        from scanner import scan_projects
        from dashboard import serve_dashboard
        # Auto-scan before serving to ensure fresh data
        scan_projects(Path.home() / '.claude' / 'projects', 
                      Path.home() / '.claude' / 'usage.db')
        serve_dashboard()  # Blocks until Ctrl-C

if __name__ == '__main__':
    main()

Design philosophy: The argparse subcommand pattern mirrors familiar tools like git and docker↗ Bright Coding Blog. Environment variables for HOST/PORT instead of CLI flags enable standard deployment patterns — systemd units, Docker containers, and shell aliases all benefit from env-based configuration.


Advanced Usage & Best Practices

Automate Scanning with Cron/Systemd

Set up a systemd user timer to scan every 15 minutes, keeping your dashboard current without manual intervention:

# ~/.config/systemd/user/claude-usage-scan.timer
[Unit]
Description=Periodic Claude usage scan

[Timer]
OnBootSec=5min
OnUnitActiveSec=15min

[Install]
WantedBy=timers.target

Cache Efficiency Monitoring

Track your cache_read_input_tokens ratio. If cache reads are low relative to total inputs, your prompts aren't being reused effectively. Restructure to increase cache hits — the cost savings are massive ($0.30/MTok vs $3.00/MTok for sonnet cache reads vs. fresh inputs).

Model Mix Optimization

Use claude-usage data to enforce team policies: haiku for exploration (<$1/MTok input), sonnet for implementation, opus only for complex architectural decisions. The dashboard makes policy compliance visible.

Backup Your usage.db

The SQLite database at ~/.claude/usage.db is your historical record. Back it up — Claude Code's JSONL files may be pruned, but your analysis database persists.


Comparison with Alternatives

Feature claude-usage Anthropic Console Manual Log Parsing Third-Party Analytics
Local data, no cloud ✅ Yes ❌ Cloud-only ✅ Yes ❌ Usually cloud
Zero dependencies ✅ stdlib only N/A ❌ Custom scripts ❌ Often heavy SDKs
Real-time dashboard ✅ Auto-refresh ⚠️ Delayed ❌ None ✅ Varies
Cost estimation ✅ With cache breakdown ⚠️ Limited ❌ Manual calculation ⚠️ Approximate
Pro/Max progress bar ✅ Full picture ⚠️ Partial ❌ None ❌ No
Incremental updates ✅ Fast rescans N/A ❌ Full reparse N/A
Setup complexity ✅ Clone and run ✅ Web login ❌ Significant dev work ⚠️ API keys, auth
Privacy ✅ Fully local ❌ Data to Anthropic ✅ Local ❌ Third-party access

The verdict: Anthropic's console is fine for API users who don't mind cloud dependency. Manual parsing is flexible but expensive to maintain. Third-party tools introduce trust boundaries. claude-usage occupies the sweet spot: complete functionality, zero friction, total privacy.


FAQ

Q: Does claude-usage work with Claude Pro and Max subscriptions, or only API? A: All three. Claude Code writes local JSONL logs regardless of plan. Cost estimates use API pricing as a reference point; subscription users should treat these as comparative metrics, not literal bills.

Q: Will this slow down my Claude Code sessions? A: Zero impact. claude-usage reads logs after sessions complete. It never intercepts or modifies live Claude Code operations.

Q: Can I track usage across multiple machines? A: Not automatically — it's local-first by design. Sync ~/.claude/usage.db via your preferred method (Syncthing, Dropbox, git) for multi-machine visibility.

Q: What about Cowork sessions? A: Intentionally not captured. Cowork runs server-side without local JSONL transcripts. This is an Anthropic architectural limitation, not a claude-usage gap.

Q: How accurate are the cost estimates? A: Based on Anthropic's April 2026 API pricing. Actual subscription costs differ. Use estimates for trend analysis and comparison, not exact billing reconciliation.

Q: Can I export data for further analysis? A: Direct SQLite access at ~/.claude/usage.db. Query with any SQLite tool, export to CSV, connect to BI tools — the data is yours.

Q: Is there a Docker image? A: Not officially — the zero-dependency design makes it unnecessary. Clone and run anywhere Python 3.8+ exists.


Conclusion

claude-usage exposes what Anthropic leaves opaque: the real cost structure of your AI-assisted development. In an era where "unlimited" plans have invisible limits and API bills can surprise, financial transparency isn't a luxury — it's a competitive necessity.

The zero-dependency architecture is a masterclass in restrained engineering. No bloated framework, no external services, no trust expansion beyond your own machine. Just Python's standard library doing exactly enough, exactly where you need it.

If you're serious about Claude Code — whether solo developer optimizing personal spend or team lead managing collective burn — this tool belongs in your workflow. The five-minute setup pays dividends in awareness, optimization, and anxiety reduction.

Stop guessing. Start knowing.

👉 Get claude-usage now — clone it, scan your logs, and finally see the full picture of your Claude Code investment.


Created by The Product Compass Newsletter. MIT Licensed.

Advertisement

Commentaires 0

Aucun commentaire pour l'instant. Soyez le premier à réagir !

Laisser un commentaire

Advertisement