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.

Open issues, via a plugin

🧠 Opus 5·1M │ 📁 claude-status-line-go │ 🌿 main

🟡5h ████░░░░░░ 41% ↺ 3h2mCTX ███░░░░░░░ 32%🎯 ███░░░░░░░ 31/100$2.14

From a command

claude-status-line.yaml
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

claude-status-line.yaml
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.

1 · 4 ms · (nothing)

Cold

No cached value, so no segment. The render hands the command to a detached process and exits without waiting.

2 · 5 ms · 🧩 █░░░░░░░░░ 1/10

First value

The background run finished, so the cache has something to draw.

3 · 3 ms · 🧩 █░░░░░░░░░ 1/10

Fresh

Inside interval, so nothing is spawned at all — this is a file read and no more.

4 · 5 ms · 🧩 █░░░░░░░░░ 1/10

Stale

Past interval. The old value is drawn immediately and a refresh starts behind it — you never wait 800 ms for a number.

5 · 5 ms · 🧩 ██░░░░░░░░ 2/10

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.

claude-status-line.yaml
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 }
Three commits behind, then in sync

🟡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

← Back to the overview