00 open-source mqtt publisher

Claude Code usage,
piped into Home Assistant

ccusage-mqtt watches Claude Code's local session files and the Anthropic rate-limit headers, then publishes 15 sensors to MQTT — auto-discovered into a single Home Assistant device with a pre-built Lovelace dashboard. No API key. Pro/Max + Enterprise.

$ git clone https://github.com/george-vice/ccusage-mqtt && cd ccusage-mqtt && pipx install . && ./setup.sh ⌘C TO COPY
built by george jeng · inspired by clawdmeter · mit licensed
live · sensor.claude_code_usage.mood demo
idle
< 0.10 %/min
◉ NOW
normal
< 0.20 %/min
◉ NOW
active
< 0.33 %/min
◉ NOW
heavy
≥ 0.33 %/min
◉ NOW
burn rate · 4min smoothed 0.264%/min
5h window 42.0%~220min to cap
─── ◆ ─── ◆ ─── ◆ ───

Four things that make it click.

Designed to slot into a homelab in under five minutes and disappear into your dashboard from there.

F.01

Mood at a glance

Burn-rate sensor classifies your session into idle / normal / active / heavy — same thresholds as Clawdmeter.

shared firmware constants
F.02

15 sensors out of the box

5h + 7d utilization, burn rate, mood, time-to-limit, tokens, spend. Auto-discovered into one HA device.

mqtt discovery built in
F.03

No API key

Reads the OAuth token Claude Code already stored at ~/.claude/.credentials.json. Zero extra setup.

oauth, not api keys
F.04

Lovelace dashboard included

Drop the included YAML into Home Assistant's Raw configuration editor and the sensors light up a card with mood, gauges, burn rate, and tokens — instantly.

ready-to-paste yaml below
─── ◆ ─── ◆ ─── ◆ ───

15 sensors, three sources, one device.

MQTT topics use the sensor IDs below (e.g. claude_code_usage/session_pct/state). HA derives entity IDs from the friendly name, so session_pct becomes sensor.claude_code_usage_session. The included YAML uses those entity IDs directly.

// anthropic api

06 · 60s refresh

From the anthropic-ratelimit-unified-* response headers on every probe. Pro/Max returns 5h-* + 7d-*; Enterprise returns overage-* instead — the parser handles both schemas transparently.

session_pct
%
Current 5-hour rate-limit window utilization. On Enterprise, overage-allowance utilization instead.
session_reset_minutes
min
How long until the current window resets. Counts down in real time.
session_status
enum
allowed / limited / unknown — whether the current window is in good standing.
weekly_pctPRO/MAX
%
7-day window utilization. Pro/Max only — null on Enterprise.
weekly_reset_minutesPRO/MAX
min
Countdown to 7d window reset. Pro/Max only.
weekly_statusPRO/MAX
enum
7d window status. Pro/Max only.

// ccusage cli

02 · 30s refresh

Local Claude Code session JSONLs parsed by ccusage.

tokens_used
tokens
Total tokens (input + output + cache create + cache read) consumed in the current 5h block.
spend_so_far_usd
USD
Estimated cost of the current 5h block from ccusage's per-model pricing table.

// metadata

01
account
text
Optional label, defaults to "default". Attached as an attribute on every other sensor too.

// derived locally

06 · computed

Computed from the inputs above on every publish cycle.

burn_rate_pct_per_min
%/min
Rate of change of session_pct, smoothed over a 4-minute ring buffer.
mood
enum
idle / normal / active / heavy bucket. Pro/Max uses the burn-rate %/min thresholds from Clawdmeter; Enterprise falls back to tokens/hour thresholds since overage_utilization stays 0 until you exceed base allocation.
time_to_limit_minutes
min
Projected minutes until session_pct reaches 100% at the current burn rate.
block_elapsed_pct
%
How far through the current 5h block you are, time-wise.
tokens_per_hour
tokens/h
Average token consumption rate so far in the current block.
spend_per_hour_usd
USD/h
Same as above but in dollars, rounded to cents.

Mood thresholds (Pro/Max)

Borrowed verbatim from the Clawdmeter firmware so the two agree if you run both. Burn rate is %-of-window per minute. Enterprise plans don't expose 5h/7d utilization, so mood falls back to tokens/hour thresholds — default boundaries 500 · 2 500 · 10 000.

< 0.10
idle
< 0.20
normal
< 0.33
active
≥ 0.33
heavy
─── ◆ ─── ◆ ─── ◆ ───

Up in five lines.

Needs Python 3.12+ and Node.js — the publisher shells out to the ccusage CLI. Then it's just systemd.

~/homelab — ccusage-mqtt — zsh 80x24
# one-time, globally $npm install -g ccusage added 84 packages in 2.1s   # clone + install the publisher $git clone https://github.com/george-vice/ccusage-mqtt.git $cd ccusage-mqtt && pipx install .   # interactive: broker + mqtt creds $./setup.sh broker → 192.168.1.20:1883 wrote .env ✓   $ccusage-mqtt [+] mqtt connected · 15 sensors discovered [+] publishing every 30s

Then run it on boot

Drop into a systemd user unit — there's a template in the README. For Home Assistant, grab the ready-to-paste Lovelace YAML on the dashboard page.

  1. Add the unit. Copy ccusage-mqtt.service from the README to ~/.config/systemd/user/.
  2. Enable + start. systemctl --user enable --now ccusage-mqtt.
  3. Paste the YAML. Open HA → Raw configuration editor → drop in the snippet from the dashboard section below.
  4. Done. Sensors auto-discover within seconds and the dashboard fills in.
python 3.12+ node.js mqtt broker home assistant
─── ◆ ─── ◆ ─── ◆ ───

A drop-in Home Assistant dashboard.

Mood at a glance, current 5h / 7d gauges, burn rate, time-to-limit, tokens used + spend — all auto-wired the moment HA discovers the device.

  • Mood + gauges up top — current state, 5h utilization, 7d utilization (Pro/Max), all visible at a glance.
  • Burn-rate timeline — 24h history graph so you can see your hot hours.
  • Pixel-art Clawd — picture-entity card keyed on the mood sensor, sprites from claudepix.
  • Matches Clawdmeter's data shape — if you also run the ESP32 desk dashboard, the two are interchangeable.
  • Yaml below — paste it into Settings → Dashboards → ⋮ → Raw configuration editor and you're done.
● home assistant live
ccusage-mqtt Lovelace dashboard
lovelace.yaml — paste into Raw configuration editor ⌘A then ⌘C
title: CCusage
views:
  - title: Usage
    path: usage
    type: sections
    max_columns: 1
    sections:
      - type: grid
        cards:
          - type: heading
            heading: Claude Code Usage
            heading_style: title
            icon: mdi:robot-outline
          - type: conditional
            conditions:
              - condition: state
                entity: sensor.claude_code_usage_mood
                state: idle
            card:
              type: iframe
              url: >-
                https://claudepix.vercel.app/animations/idle_breathe.html?speed=1
              aspect_ratio: 100%
              grid_options:
                columns: 12
                rows: 4
          - type: conditional
            conditions:
              - condition: state
                entity: sensor.claude_code_usage_mood
                state: normal
            card:
              type: iframe
              url: >-
                https://claudepix.vercel.app/animations/idle_look_around.html?speed=1
              aspect_ratio: 100%
              grid_options:
                columns: 12
                rows: 4
          - type: conditional
            conditions:
              - condition: state
                entity: sensor.claude_code_usage_mood
                state: active
            card:
              type: iframe
              url: https://claudepix.vercel.app/animations/work_coding.html?speed=1
              aspect_ratio: 100%
              grid_options:
                columns: 12
                rows: 4
          - type: conditional
            conditions:
              - condition: state
                entity: sensor.claude_code_usage_mood
                state: heavy
            card:
              type: iframe
              url: https://claudepix.vercel.app/animations/work_think.html?speed=1
              aspect_ratio: 100%
              grid_options:
                columns: 12
                rows: 4
          - type: tile
            entity: sensor.claude_code_usage_session
            name: Session %
          - type: tile
            entity: sensor.claude_code_usage_weekly
            name: Weekly %
          - type: tile
            entity: sensor.claude_code_usage_mood
            name: Mood
          - type: tile
            entity: sensor.claude_code_usage_burn_rate
            name: Burn rate
          - type: tile
            entity: sensor.claude_code_usage_time_to_limit
            name: Time to limit
          - type: tile
            entity: sensor.claude_code_usage_session_resets_in
            name: Session resets in
          - type: tile
            entity: sensor.claude_code_usage_weekly_resets_in
            name: Weekly resets in
          - type: tile
            entity: sensor.claude_code_usage_session_status
            name: Session status
          - type: tile
            entity: sensor.claude_code_usage_weekly_status
            name: Weekly status
          - type: tile
            entity: sensor.claude_code_usage_block_elapsed
            name: Block elapsed
          - type: tile
            entity: sensor.claude_code_usage_tokens_used
            name: Tokens used
          - type: tile
            entity: sensor.claude_code_usage_tokens_per_hour
            name: Tokens / hour
          - type: tile
            entity: sensor.claude_code_usage_spend_so_far
            name: Spend so far
          - type: tile
            entity: sensor.claude_code_usage_spend_per_hour
            name: Spend / hour