A small, dependency-free CLI for inspecting Claude Code's statusLine JSON payload, with currency conversion, cost tracking, and an HTML dashboard.
Project description
statusline-toolkit
A small, dependency-free Python CLI for Claude Code's statusLine
JSON payload. Prints a color-coded one-line summary, with optional currency
conversion, cost tracking, and an HTML dashboard — all local, all plain
JSON files you own.
[Claude Sonnet 5] (my-project) [####------] 42% | $0.1234 (~Rp 2.011) | +156/-23 | 45s | $9.87/hr | 5h: 24% 7d: 41%
Works identically on Linux, macOS, and Windows. MIT licensed.
Contents
- Quick start
- Usage
- Reading the summary line
- Installing as your Claude Code status line
- Currency conversion
- Cost tracking: history, stats, and a dashboard
- Personal defaults file
- Plugin segments
- Project layout
- Tests
- Troubleshooting
Quick start
Requires Python 3.9+ (python3 on Linux/macOS, py on Windows). Two ways to get it:
# Option A: pip/pipx, no clone needed
pipx install git+https://github.com/gungunfebrianza/statusline-toolkit.git
statusline-toolkit --setup
# Option B: clone and run directly — no install step at all
git clone https://github.com/gungunfebrianza/statusline-toolkit.git
cd statusline-toolkit
python statusline_toolkit.py --input sample_statusline_data.json --idr
python statusline_toolkit.py --setup
Both are equivalent — it's zero-dependency either way. The rest of this
README uses python statusline_toolkit.py ...; swap in statusline-toolkit
... if you installed via pip/pipx.
Usage
# Live: pipe whatever JSON Claude Code sends on stdin
some_producer_of_json | python statusline_toolkit.py
# Offline: inspect a saved payload
python statusline_toolkit.py --input sample_statusline_data.json --all # full JSON
python statusline_toolkit.py --input sample_statusline_data.json --list # just the field names
python statusline_toolkit.py --input sample_statusline_data.json --field cost.total_cost_usd
# Currency conversion (any ISO 4217 code)
python statusline_toolkit.py --input sample_statusline_data.json --currency EUR
# No colors (for logging, or a terminal that mangles ANSI)
python statusline_toolkit.py --input sample_statusline_data.json --no-color
Flag reference
| Flag | Description |
|---|---|
-i, --input PATH |
Read the JSON payload from a file instead of stdin. |
-a, --all |
Print the entire payload as formatted JSON. |
-l, --list |
List every available field path, without values. |
-f, --field DOT.PATH |
Print just this field; repeatable. |
--currency CODE |
Show cost converted to CODE (e.g. EUR, JPY, IDR). |
--idr |
Shorthand for --currency IDR (backward compatible). |
--rate RATE |
Override the conversion rate for this run only. |
--rate-file PATH |
Use a different exchange-rate file. |
--no-color |
Disable ANSI colors (also honors NO_COLOR). |
--width N |
Override the detected terminal width for adaptive layout. |
--no-adapt |
Never drop segments to fit the width — always the full line. |
--setup |
Install as your Claude Code statusLine, then exit. |
-y, --yes |
With --setup, skip the overwrite confirmation. |
--settings-file PATH |
With --setup, target a different settings.json. |
--track |
Record this session's cost to history, for --stats/--dashboard. |
--stats |
Print a cost report from tracked history, then exit. |
--by-project / --by-model |
With --stats, group by project/model instead of day. |
--history-file PATH |
Use a different history file. |
--dashboard |
Render an HTML usage dashboard from tracked history, then exit. |
--dashboard-file PATH |
Where to write the dashboard (default: next to the history file). |
--open |
With --dashboard, open it in your browser. |
--config PATH |
Use a different personal defaults file. |
--plugins-dir PATH / --no-plugins |
Custom plugin directory / skip loading plugins. |
--version |
Print the version and exit. |
Run --help any time for the same reference from the source.
Reading the summary line
[Claude Sonnet 5] (my-project) [####------] 42% | $0.1234 (~Rp 2.011) | +156/-23 | 45s | $9.87/hr | 5h: 24% 7d: 41%
| Segment | Meaning |
|---|---|
[Claude Sonnet 5] |
Model name. |
(my-project) |
Current project folder — helps tell sessions apart. |
[####------] 42% |
Context window used, color-coded green→amber→red. |
$0.1234 (~Rp 2.011) |
USD cost, plus a converted estimate if --currency/--idr is passed. |
+156/-23 |
Lines added/removed, colored git-style (green/red). |
45s |
Session duration. |
$9.87/hr |
Burn rate — cost extrapolated to an hourly pace (a derived number, not a raw field). |
5h: 24% 7d: 41% |
5-hour / 7-day rate-limit usage. |
Any segment just disappears if the payload doesn't have that data — nothing errors.
Colors blend smoothly from green (low) to amber to red (high) on
terminals with 24-bit color support, and fall back to plain green/yellow/red
otherwise. --no-color or NO_COLOR=1 turns all of it off.
Adaptive width: if the full line wouldn't fit your terminal, the least
essential segments drop first — rate limits, then burn rate, duration,
lines, project, currency — until it fits, or down to just
[model] [bar] % | $cost if space is very tight. Use --width N to set
the width explicitly (handy since Claude Code runs this headless, so
there's often nothing real to detect) or --no-adapt to always print the
full line.
Installing as your Claude Code status line
python statusline_toolkit.py --setup # default: IDR
python statusline_toolkit.py --setup --currency EUR # a different currency
python statusline_toolkit.py --setup --currency EUR --track # also track cost history
This detects your OS and writes a statusLine entry into
~/.claude/settings.json, backing up any existing config first. It's
idempotent (safe to re-run) and asks before overwriting a different
statusLine (skip with -y). Restart Claude Code afterward to see it
take effect.
Currency conversion
exchange_rate.json holds manually maintained rates you control — no
network calls, no API keys:
{
"rates": { "IDR": 16300, "EUR": 0.92 },
"updated_at": "2026-07-06"
}
Add a currency to rates and pass --currency CODE, or use
--currency CODE --rate <value> for a one-off conversion without
touching the file. If a currency isn't configured, the script tells you
exactly what to add rather than guessing. If updated_at is over 30 days
old, you'll get a one-line reminder to refresh it.
(Older single-currency files — {"usd_to_idr": 16300, ...} — still work unchanged.)
Cost tracking: history, stats, and a dashboard
--track records each session's cost to usage_history.json (keyed by
session, so re-renders don't double-count). Then:
python statusline_toolkit.py --input sample_statusline_data.json --track
python statusline_toolkit.py --stats # grouped by day
python statusline_toolkit.py --stats --by-project # or by project / --by-model
python statusline_toolkit.py --dashboard --open # visual HTML report
--stats prints a per-group cost/session breakdown with a grand total.
--dashboard renders the same data as a self-contained HTML file — summary
cards plus cost-by-day/project/model bar charts, no JS framework, no CDN,
light/dark aware — and only opens a browser if you pass --open.
Everything here is opt-in and local: nothing is tracked or rendered unless
you ask, and usage_history.json is plain JSON you can inspect or delete
anytime.
Personal defaults file
Tired of retyping the same flags? Put them in
~/.claude/statusline-toolkit.json:
{
"currency": "EUR",
"track": true,
"width": 100
}
Every key is optional and mirrors a CLI flag (no_color, by_project,
by_model, no_adapt, rate_file, history_file, plugins_dir,
no_plugins are all supported too). CLI flags always override the
file. Use --config PATH for a different file (e.g. separate
personal/work profiles).
Plugin segments
Add your own segment (git branch, whatever) without touching the script:
drop a .py file into ~/.claude/statusline-plugins/ defining one function.
# ~/.claude/statusline-plugins/git_branch.py
import subprocess
def segment(data: dict, use_color: bool) -> str | None:
cwd = data.get("workspace", {}).get("current_dir") or data.get("cwd")
try:
branch = subprocess.run(
["git", "branch", "--show-current"], cwd=cwd, capture_output=True, text=True, timeout=1,
).stdout.strip()
except Exception:
return None
return f"({branch})" if branch else None
The filename becomes the segment's name; return None/"" to hide it for
a render. An optional PRIORITY: int (default 0) controls drop order
among plugins — but plugin segments always drop before any built-in one.
A broken plugin (syntax error, exception, bad return type) is silently
skipped, never crashes the statusline. Disable loading with
--no-plugins, or point elsewhere with --plugins-dir.
Security note: a plugin is a regular Python file that runs with full permissions on every render — there's no sandboxing. Only put plugins in this folder that you wrote yourself or fully trust, the same way you'd treat any script before running it. Never copy a plugin from an untrusted source without reading it first.
Project layout
| File | Purpose |
|---|---|
statusline_toolkit.py |
The CLI, including the --setup installer. |
exchange_rate.json |
Your USD→currency rates. |
sample_statusline_data.json |
Example payload for trying the tool offline. |
test_statusline_toolkit.py |
Unit tests. |
CHANGELOG.md |
What changed, release by release. |
LICENSE |
MIT license. |
pyproject.toml |
Packaging metadata, for pip/pipx install. |
.github/workflows/test.yml |
CI: runs the test suite on Linux/macOS/Windows for every push and PR. |
usage_history.json, usage_dashboard.html, settings.json.bak, and
~/.claude/statusline-toolkit.json are all generated on demand — not
part of a fresh checkout, safe to delete anytime.
Tests
python -m unittest test_statusline_toolkit.py -v
Standard library unittest only — no test runner to install.
Troubleshooting
"No input JSON received" / "Input is not valid JSON"
Pass --input sample_statusline_data.json (or your own file), or pipe
valid JSON into stdin.
Colors look garbled, or the gradient looks banded instead of smooth
Your terminal doesn't support ANSI/truecolor — use --no-color, or run in
a modern terminal (Windows Terminal, a current PowerShell, most
Linux/macOS terminal apps).
Windows: "python is not recognized..."
Use the py launcher instead (py statusline_toolkit.py ...), or
reinstall Python with "Add python.exe to PATH" checked.
`--setup` didn't seem to take effect
Restart Claude Code — statusLine config is only read at session start.
Check ~/.claude/settings.json for a statusLine block pointing at
statusline_toolkit.py.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file statusline_toolkit-1.0.0.tar.gz.
File metadata
- Download URL: statusline_toolkit-1.0.0.tar.gz
- Upload date:
- Size: 22.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
27ccffafc8226c9c431c87cc9179a8a26cf1116708ab75b3faeb701ff50fc13e
|
|
| MD5 |
2bed805f24ae64a054b9db5eab44df55
|
|
| BLAKE2b-256 |
d86af2eff742c3db5f4eaae17cb81e4386ef8e54358ed703e17a3ddcf19ddf9d
|
File details
Details for the file statusline_toolkit-1.0.0-py3-none-any.whl.
File metadata
- Download URL: statusline_toolkit-1.0.0-py3-none-any.whl
- Upload date:
- Size: 21.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
670a64501d762ae03af1d275958a168791e1a258b3811f083a764c1f3a040265
|
|
| MD5 |
bf535896b469b5d030517b7d0971a0ca
|
|
| BLAKE2b-256 |
2759504d82ff82af977a422a1060e3829d3723f9ff70e612a925bffb98cf456b
|