{"slug": "an-xbar-plugin-that-displays-your-current-claude-code-usage-on-your-mac-s", "title": "An xbar plugin that displays your current Claude Code usage on your Mac's toolbar", "summary": "This article describes a Python plugin for xbar, a macOS toolbar utility, that displays a user's daily Claude Code token usage. The script fetches usage statistics by running the `npx cusage@latest -j` command and formats the token count with human-readable suffixes like \"K\" or \"M\". If data is unavailable or an error occurs, the toolbar shows an error message or \"0 tokens\" for no usage.", "body_md": "claude_tokens.5m.py\n\n      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.\n      \nLearn more about bidirectional Unicode characters\n\n \n    Show hidden characters\n\n#!/usr/bin/env python3\n\n# <xbar.title>Claude Token Usage</xbar.title>\n\n# <xbar.version>v1.0</xbar.version>\n\n# <xbar.author>Preslav Rachev</xbar.author>\n\n# <xbar.desc>Shows today's Claude Code token usage in the Mac toolbar</xbar.desc>\n\nimport json\n\nimport subprocess\n\nimport os\n\nimport glob\n\nfrom datetime import datetime\n\nfrom typing import Any\n\ndef format_number(num):\n\n    \"\"\"Formats a number into a human-readable string with K/M suffixes.\"\"\"\n\n    if num >= 1000000:\n\n        return f\"{num / 1000000:.1f}M\"\n\n    if num >= 1000:\n\n        return f\"{num / 1000:.1f}K\"\n\n    return str(num)\n\ndef get_ccusage_data() -> dict[str, Any]:\n\n    \"\"\"Fetches Claude Code usage statistics using the `npx ccusage@latest -j` command.\"\"\"\n\n    try:\n\n        # Set up environment with common paths for xbar\n\n        env = os.environ.copy()\n\n        # Add common Node.js paths to ensure npx is found\n\n        common_paths = [\n\n            \"/usr/local/bin\",\n\n            \"/usr/bin\",\n\n            \"/bin\",\n\n            \"/opt/homebrew/bin\",  # Homebrew on Apple Silicon\n\n            os.path.expanduser(\"~/.nvm/versions/node/*/bin\"),  # NVM paths\n\n            os.path.expanduser(\"~/node_modules/.bin\"),  # Local node modules\n\n        ]\n\n        # Expand glob patterns and filter existing paths\n\n        expanded_paths = []\n\n        for path in common_paths:\n\n            if \"*\" in path:\n\n                expanded_paths.extend(glob.glob(path))\n\n            elif os.path.exists(path):\n\n                expanded_paths.append(path)\n\n        # Add to PATH if not already present\n\n        current_path = env.get(\"PATH\", \"\")\n\n        for path in expanded_paths:\n\n            if path not in current_path:\n\n                current_path = f\"{path}:{current_path}\"\n\n        env[\"PATH\"] = current_path\n\n        # Try running npx from PATH\n\n        result = subprocess.run(\n\n            [\"npx\", \"ccusage@latest\", \"-j\"],\n\n            capture_output=True,\n\n            text=True,\n\n            timeout=30,\n\n            check=False,\n\n            env=env,\n\n        )\n\n        if result.returncode == 0:\n\n            return json.loads(result.stdout)\n\n        return {\n\n            \"error\": f\"Command failed with code {result.returncode}\",\n\n            \"stderr\": result.stderr,\n\n            \"stdout\": result.stdout,\n\n        }\n\n    except subprocess.TimeoutExpired:\n\n        return {\"error\": \"Command timed out after 30 seconds\"}\n\n    except json.JSONDecodeError as e:\n\n        return {\"error\": f\"JSON decode error: {e}\", \"stdout\": result.stdout}\n\n    except FileNotFoundError:\n\n        return {\"error\": \"npx command not found - Node.js may not be installed\"}\n\ndef main():\n\n    \"\"\"Main function to fetch and display Claude Code usage statistics.\"\"\"\n\n    # Get today's date in YYYY-MM-DD format\n\n    today = datetime.now().strftime(\"%Y-%m-%d\")\n\n    # Get usage data\n\n    data = get_ccusage_data()\n\n    if not data or (isinstance(data, dict) and \"error\" in data):\n\n        print(\"⚠️ Error\")\n\n        print(\"---\")\n\n        if isinstance(data, dict) and \"error\" in data:\n\n            print(f\"Error: {data['error']}\")\n\n            if \"stderr\" in data:\n\n                print(f\"Stderr: {data['stderr']}\")\n\n            if \"stdout\" in data:\n\n                print(f\"Stdout: {data['stdout']}\")\n\n        else:\n\n            print(\"Failed to fetch usage data\")\n\n        return\n\n    # Find today's usage\n\n    today_usage = None\n\n    for day in data.get(\"daily\", []):\n\n        if day.get(\"date\") == today:\n\n            today_usage = day\n\n            break\n\n    if not today_usage:\n\n        print(\"📊 0 tokens\")\n\n        print(\"---\")\n\n        print(\"No usage today\")\n\n        return\n\n    # Display today's token count in toolbar\n\n    total_tokens = today_usage.get(\"totalTokens\", 0)\n\n    total_cost = today_usage.get(\"totalCost\", 0)\n\n    print(f\"📊 {format_number(total_tokens)}\")\n\n    print(\"---\")\n\n    print(f\"Today's Usage ({today})\")\n\n    print(f\"Total Tokens: {format_number(total_tokens)}\")\n\n    print(f\"Input: {format_number(today_usage.get('inputTokens', 0))}\")\n\n    print(f\"Output: {format_number(today_usage.get('outputTokens', 0))}\")\n\n    print(f\"Cache Creation: {format_number(today_usage.get('cacheCreationTokens', 0))}\")\n\n    print(f\"Cache Read: {format_number(today_usage.get('cacheReadTokens', 0))}\")\n\n    print(f\"Cost: ${total_cost:.2f}\")\n\n    print(\"---\")\n\n    # Show total usage\n\n    totals = data.get(\"totals\", {})\n\n    print(\"Total Usage (All Time)\")\n\n    print(f\"Total Tokens: {format_number(totals.get('totalTokens', 0))}\")\n\n    print(f\"Total Cost: ${totals.get('totalCost', 0):.2f}\")\n\nif __name__ == \"__main__\":\n\n    main()", "url": "https://wpnews.pro/news/an-xbar-plugin-that-displays-your-current-claude-code-usage-on-your-mac-s", "canonical_source": "https://gist.github.com/preslavrachev/61aa5ea90d28bcb489f65d072f9f2d94", "published_at": "2025-07-18 07:38:49+00:00", "updated_at": "2026-05-23 00:05:35.955894+00:00", "lang": "en", "topics": ["developer-tools", "artificial-intelligence", "large-language-models"], "entities": ["Claude Code", "Preslav Rachev", "Mac", "npx", "Homebrew", "NVM", "Node.js"], "alternates": {"html": "https://wpnews.pro/news/an-xbar-plugin-that-displays-your-current-claude-code-usage-on-your-mac-s", "markdown": "https://wpnews.pro/news/an-xbar-plugin-that-displays-your-current-claude-code-usage-on-your-mac-s.md", "text": "https://wpnews.pro/news/an-xbar-plugin-that-displays-your-current-claude-code-usage-on-your-mac-s.txt", "jsonld": "https://wpnews.pro/news/an-xbar-plugin-that-displays-your-current-claude-code-usage-on-your-mac-s.jsonld"}}