Plugins
Add your own segments.
A plugin reports data — a value, an optional maximum, maybe a label — and
this tool draws it. So your segment gets the same glyphs, the same
bar_size and the same
NO_COLOR handling as
everything else on the line, rather than each plugin reinventing bars and
colors slightly differently.
🧠 Opus 5·1M │ 📁 claude-status-line-go │ 🌿 main
🟡5h ████░░░░░░ 41% ↺ 3h2m │ CTX ███░░░░░░░ 32% │ 🎯 ███░░░░░░░ 31/100 │ $2.14
From a command
plugins: - name: issues command: >- printf '{"value":%s,"max":100}' "$(gh issue list --json number --jq 'length')" interval: 60s icon: "🎯" bar: true thresholds: - { at: 0, color: green } - { at: 40, color: yellow } - { at: 70, color: red }
A command never runs while the status line is drawing. Its result is
cached; a render reads that and, when it's older than
interval, hands the work to a detached process and draws
the stale value straight away. A 350 ms
gh call costs the line nothing — it just means the number
can be up to interval old.
thresholds is a list, and at is a lower bound
in percent. There's no invert flag: for a ramp where more is better,
write the colors the other way round.
From a file
plugins: - name: spec file: .claude/spec-state.json icon: "🧩" bar: true display: "{icon} {label} {bar} {value}/{max}" hide_when: zero # nothing left to do, so say nothing
Read straight off disk, so it costs nothing at all. This is the one to reach for when something already writes the data — a Claude Code hook firing on the event that changes it beats polling for it.
hide_when keeps counters out of the way when they've
nothing to say: zero when the value is 0,
full when it reaches its maximum.
What a slow command actually does
Five consecutive renders with a command that takes 800 ms, timed on a real terminal. The command never lands on the render path, so the cost of the status line doesn't move.
Cold
No cached value, so no segment. The render hands the command to a detached process and exits without waiting.
First value
The background run finished, so the cache has something to draw.
Fresh
Inside interval, so nothing is spawned at all — this is a file read and no more.
Stale
Past interval. The old value is drawn immediately and a refresh starts behind it — you never wait 800 ms for a number.
Caught up
The refresh landed, so the next render shows it. The trade is that a number can be up to interval old — never that the line is slow.
If the command fails, the last good value stays on screen rather than the segment vanishing. If it has never succeeded, there's simply nothing to draw.
A real one, start to finish
Commits you haven't pushed. No API tokens, no setup — it works in any git
repo, and hide_when: zero means it's invisible until you're
actually behind.
plugins: - name: unpushed command: >- printf '{"value":%s,"max":20,"label":"unpushed"}' "$(git log --oneline @{u}.. 2>/dev/null | wc -l)" interval: 30s icon: "⬆" bar: true hide_when: zero thresholds: - { at: 0, color: green } - { at: 25, color: yellow } - { at: 50, color: red }
🟡5h ░░░░░░░░░░ 0% │ CTX ░░░░░░░░░░ 0% │ ⬆ █░░░░░░░░░ 3/20 │ $0.00
🟡5h ░░░░░░░░░░ 0% │ CTX ░░░░░░░░░░ 0% │ $0.00
The second line is the same plugin after pushing: at zero it takes no space at all. Outside a git repo, or on a branch with no upstream, the count is zero and the segment stays hidden — no error, no noise.
When one doesn't show up
claude-status-line-go plugins
Claude Code discards this tool's stderr, so a plugin that fails has
nowhere to say so — it just doesn't appear. This prints each plugin's
source, cache age and the segment it renders.
plugins refresh runs the commands in the foreground and
shows you the error.
Cached values are per plugin and per project, so they build up as you
move between repos. Every background refresh prunes the ones that can't
matter any more — plugins you've removed, anything untouched for a
fortnight — and plugins clean does it on demand.
A plugin emits JSON on stdout —
{"value": 12, "max": 33, "label": "aplicar"}
— and bare text counts too, so echo "12 left"
is a valid plugin. Any key outside the contract is reachable as
{plugin.name.key}, which is how
one plugin reports several things at once.
Next
Not installed yet?
Plugins live in the same config file as everything else, so there's nothing extra to set up once the status line itself is running.
curl -fsSL https://okano.dev/claude-status-line-go/install.sh | sh