How PixerBar works

Claude Code lets a status line be any command. It runs the command, hands it a blob of JSON on stdin, and prints whatever comes back. PixerBar is one bash script that reads that JSON and prints five rows of half-block characters — a sprite, coloured by what the JSON said.

Installing

You need bash and jq (brew install jq on macOS, apt install jq on Debian/Ubuntu), a terminal with 24-bit colour, and Claude Code. On Windows, run it inside Git Bash or WSL. Pick whichever of the three routes matches how much you like piping things into shells:

Route 1 — the one-liner

Build a skin in the studio and copy its install command:

curl -fsSL 'https://pixerbar.dev/i/<your-skin>' | bash

The URL carries the entire skin, so the script that comes back is self-contained — it makes no further network requests and installs nothing but itself. The -f matters: if the link is bad the server answers 400, curl passes nothing to bash, and nothing runs.

Route 2 — read it first recommended if you don't pipe strangers into bash

# download, read, then run — same bytes, two steps
curl -fsSL 'https://pixerbar.dev/i/<your-skin>' -o pixerbar-install.sh
less pixerbar-install.sh     # every line it will run, sprite included
bash pixerbar-install.sh

Opening the same URL in a browser shows the identical script as plain text. Add --dry-run to see the plan without writing a byte.

Route 3 — no network execution at all

git clone https://github.com/ke11/pixerbar
cd pixerbar
bash runtime/install.sh --skin skins/clawd.sh   # or a .sh downloaded from the studio

The studio's download .sh button hands you the skin as a file; this route never executes anything a web server produced.

What every route does

  • ~/.claude/pixerbar/pixerbar.sh — the status line script
  • ~/.claude/pixerbar/skins/<name>.sh — your skin
  • sets statusLine in ~/.claude/settings.json — after copying the file to ~/.claude/pixerbar/backups/, and remembering any status line you already had
  • runs a doctor pass and names anything wrong

Never sudo, never outside ~/.claude, no telemetry, re-running is safe. Then open a new Claude Code session and the sprite appears.

Managing it afterwards

… | bash -s -- --uninstall   # put back the status line you had before
… | bash -s -- --doctor      # why is the bar blank?
… | bash -s -- --list        # skins you have installed
… | bash -s -- --use clawd   # switch the active skin
… | bash -s -- --dry-run     # print the plan, write nothing

The flags work identically on a downloaded copy: bash pixerbar-install.sh --uninstall. Uninstall restores your previous statusLine exactly; the backups folder survives it on purpose.

What the sprite is telling you

StateComes fromLooks like
Idlethe transcript has not changed for 8 secondsparks on the last frame, perfectly still
Workingthe transcript was written to just nowwalks the beat frames
Fast modefast mode is on while workingalternates the two frames the skin nominates
Contextcontext_window.used_percentagethe body reddens bottom-up, one pixel row per tenth
Uncommitted workgit status --porcelain is not emptythe skin's own git pixels turn cream
Five hoursrate_limits.five_hour.used_percentagea separate column beside the sprite, green through red
idlenothing happening
workingwalks poses 1–4, one step per run
fastalternates poses 1 and 3
context50% of the window used
100% — the gauge fills every row
gituncommitted work in the tree
5-hour30% — green, its own column
60% — amber
95% — red
all at onceworking, full context, dirty, 5h nearly gone

Two things that never change

The mark is always five rows. Whatever the sprite is doing inside it, the canvas is the same height, so the interface above the status line never jumps.

An empty cell is U+2800, not a space. A leading space gets trimmed somewhere between the script and the screen, and the row snaps left. A braille blank occupies a cell and is not whitespace.

The skin format

A skin is a shell file the runtime sources. Nine variables, two of them arrays of digit strings. It is meant to be readable and hand-editable — the studio is a convenience, not a requirement.

W
sprite columns, 8 to 40. The canvas is W+2: the sprite, a blank gap, the tick.
NFRAMES
beat frames, 2 to 8. There is always one more frame than this — the idle pose.
SKIN_BASE
the creature's own colour.
SKIN_GAUGE
the context gauge. Choose it against the base, not from the source art.
SKIN_CREAM
what the git pixels turn when the worktree is dirty.
SKIN_INK2/3/4
accent ink: colours the gauge and the git mask both leave alone.
FAST_A / FAST_B
the pair fast mode alternates. Pick the two frames furthest apart.
DIRTY
10 rows of 0 and 1: which pixels answer to git.
FRAMES
(NFRAMES+1)×10 rows of digits 0–4, each exactly W wide.

Digits in FRAMES are not a bitmask. 0 is off, 1 is the body — the part the gauge and the git mask act on — and 2, 3 and 4 select accent inks, which they leave alone.

When the bar is blank

Almost always workspace trust. A status line is gated by it exactly like hooks are, keyed by the exact absolute path with no inheritance from parent folders — and when a folder is not trusted the bar is empty with no error anywhere. Claude Code asks once per folder; answer yes and it appears.

After that: jq missing, or refreshInterval not set to 1 — without it the sprite only moves when something else happens, which looks like a bug and is not one. Run the install line with --doctor and it checks all of these.