STATUSLINE DOCS
Home Builder GitHub
DOCUMENTATION

Guide

Install, the four concepts that explain everything else, and the recipes people actually ask for. For the generated tables of every tile, fill, signal and edge, see REFERENCE.md.


Install

git clone https://github.com/Bravim-Ketan-Purohit/statusline
cd statusline
pnpm install && pnpm build

Check it renders before wiring anything up:

echo '{"model":{"display_name":"Opus 5"}}' \
  | COLUMNS=140 node packages/cli/dist/statusline.js render

Wire it into Claude Code

Design a bar in the builder, press Copy install, paste the command. Or by hand:

node packages/cli/dist/statusline.js import "$(cat my-config.b64)"

import patches ~/.claude/settings.json. It reads the existing file, changes only the statusLine key, and shows you a diff before writing. If something else already owns that key it stops and asks.

Wire it into tmux

node packages/cli/dist/statusline.js tmux-conf >> ~/.tmux.conf
tmux source-file ~/.tmux.conf

That snippet enables mouse mode and registers the click binding, so tiles with an action or drill become clickable.

If something's wrong

statusline doctor

It checks the config parses, the settings file points where you think, the daemon is running if any tile needs it, and every custom command is approved — and tells you the fix, not just the fault.


Four concepts

Everything else follows from these.

1. Tiles declare what they cost

A status line runs on every message. So each tile declares a tier, and nothing above T2 ever touches the render path.

TierCostExample
T0free — already on stdinmodel, cwd, cost
T1one local file readgit-branch, clock
T2a subprocess, cachedgit-diff, battery
T3sampled by the daemoncpu, memory, network
T4network, needs a credentialci, sentry-issues

T3 tiles render nothing unless statusline daemon is running. That's not a bug — sampling on render would make "CPU usage since last message" the metric, which is meaningless. Start it once:

statusline daemon &

2. Priority decides what survives

Terminals resize. Every tile carries a priority integer, and when the row won't fit the solver drops whole tiles, highest number first. It never wraps and never truncates mid-tile.

priority 1  ← last to go   (branch, context)
priority 9  ← first to go  (clock, battery)

Guaranteed monotonic: a narrower terminal never keeps more tiles.

3. Breakpoints inherit sparsely

Six by default — xs ≥0, sm ≥40, md ≥80, lg ≥120, xl ≥160, 2xl ≥220.

An override only records what *differs* from the next smaller breakpoint:

"responsive": {
  "priority": 3,
  "sm": { "compact": true },     // from 40 cols up: drop the label
  "md": { "compact": false }     // from 80 cols up: put it back
}
The trap. "md": {} means *inherit sm*, not *reset to default*. If everything looks compact at 200 columns, this is why.

4. Signals drive appearance

26 closed-enum signals. Bind one to a colour, a border, a blink, or to visibility:

"style": {
  "showOnlyWhen": [{ "signal": "ci.failing" }],   // invisible until it matters
  "rules": [{
    "signal": "ci.failing",
    "blink": { "target": "border", "color": "#ff5f5f", "hz": 2 },
    "bell": true
  }]
}

Later rules win, so layer a general rule then override it.


Recipes

Show CI only when it's broken

{ "type": "ci", "style": { "showOnlyWhen": [{ "signal": "ci.failing" }] } }

Costs zero columns on a good day.

Stop yourself running things against production

{ "type": "kube-context" }, { "type": "aws-profile" }, { "type": "protected-branch" }

The danger match is segment-based, so eks-prod-1 reddens and product-api doesn't. Add your own words under theme.dangerPatterns.

Warn before the context window runs out

{ "type": "context-bar", "style": { "rules": [
  { "signal": "context.above", "threshold": 75, "fg": "#e0a44a" },
  { "signal": "context.above", "threshold": 90, "fg": "#d9604e", "bell": true }
]}}

Rotate several low-value tiles through one slot

"rotation": [{ "tiles": ["verse", "track", "skills"], "every": "minute" }]

Three tiles, one tile's worth of columns. The choice comes from a clock bucket so it never flickers mid-session.

Make the whole bar flow

"theme": { "terminalFill": {
  "kind": "gradient", "mode": "plasma", "animated": true, "speed": 0.3,
  "stops": [{ "color": "#2b0b52", "pos": 0 }, { "color": "#7b2ff7", "pos": 1 }]
}}

In Claude Code this is a slow pulse — the refresh floor is one second. The web preview animates properly.

Add a tile that runs your own command

{ "type": "command", "props": { "argv": ["kubectl", "get", "po", "-o", "name"] } }

Argv array, never a shell string. Then approve it once:

statusline approve

Editing the command revokes the approval — that's the point.


Troubleshooting

SymptomCause
Bar is blankThe script exited non-zero. Run statusline render by hand and read stderr.
Metric tiles emptyThe daemon isn't running. statusline daemon &
Everything compact at wide widthsA sparse override — see concept 3.
A custom command does nothingNot approved. statusline approve
Powerline caps show as boxesNeeds a Nerd Font.
Overline ignoredYour terminal doesn't support it. It's dropped, not garbled.
tmux tiles not clickabletmux-conf snippet not sourced, or mouse mode off.
T4 tiles emptyNo credential. statusline creds set <name>

Deploying your own copy of the site

The repo builds a static site — landing page, docs and the builder:

pnpm build:site      # → dist-site/
pnpm preview:site    # → http://localhost:5000

On Vercel: import the repo and accept the detected settings. vercel.json already sets the build command, output directory and cache headers. No environment variables and no server runtime — it's fully static.

Demo video

The recordings are not in git — they'd add megabytes to every clone forever. They live on a GitHub Release instead, and the build rewrites the {{MEDIA}} token in the HTML to point at them.

pnpm media:publish     # uploads landing-kit/assets/video/*.mp4 to the release
pnpm media:check       # HEADs every URL the built site references

site.config.json is the single place that defines where media is served from, so moving to a real CDN later is a one-line change rather than a find-and-replace through the markup.

The build succeeds without the video present — which is what the Vercel checkout looks like, since the files are gitignored. Posters stay committed because they're what paints before the remote video arrives.


Reference

Generated from packages/core. Re-run node scripts/gen-reference.mjs after adding a tile, a fill mode, a signal or an edge style.

Tiles (68)

idtiercategoryname
aws-profile1environmentAWS profile
battery2environmentBattery
clock1environmentClock
cpu3environmentCPU usage
cwd0environmentWorking directory
disk3environmentDisk used
gcp-project4environmentGCP project
gpu3environmentGPU usage
hostname1environmentHostname
kube-context2environmentKubernetes context
load3environmentLoad average
memory3environmentMemory usage
network3environmentNetwork throughput
node-version1environmentNode version
python-version1environmentPython version
swap3environmentSwap in use
venv1environmentActive venv
vram3environmentVRAM usage
ci4gitCI status
gh-issues4gitOpen issues
gh-pr-counts4gitRepo PR counts
git-ahead-behind2gitAhead / behind
git-branch1gitGit branch
git-counts2gitGit file counts
git-diff2gitUncommitted diff
git-last-commit2gitLast commit age
git-sha2gitCommit SHA
git-stash2gitStash count
pr0gitBranch PR
protected-branch1gitProtected branch warning
repo-slug0gitRepo slug
worktree0gitWorktree
command2layoutCustom command
fill-band1layoutFill band
separator1layoutFlex separator
spacer1layoutSpacer
text1layoutCustom text
media-next1mediaNext track
media-play1mediaPlay / pause
media-prev1mediaPrevious track
media-vol-down1mediaVolume down
media-vol-up1mediaVolume up
now-playing2mediaNow playing
skills2personalSuggested skills
track1personalPlaylist track
verse1personalScripture verse
agent0sessionAgent
cc-version0sessionClaude Code version
context-bar0sessionContext window bar
context-pct0sessionContext percentage
cost0sessionSession cost
deploy-duration4sessionDeploy duration
deploy-status4sessionDeploy status
deploy-url4sessionPreview URL
effort0sessionThinking effort
five-hour-bar0session5h limit bar
linear-assigned4sessionLinear assigned
linear-review4sessionLinear in review
linear-started4sessionLinear in progress
linear-triage4sessionLinear triage queue
lines-changed0sessionLines added/removed
model0sessionModel
sentry-events4sessionSentry events 24h
sentry-issues4sessionSentry unresolved
session-duration0sessionSession duration
session-name0sessionSession name
seven-day0session7d limit
vim-mode0sessionVim mode

Fill modes (15)

modewhat it does
linearA straight ramp at any angle.
radialOut from an origin you can move.
conicSwept around the origin like a radar.
diamondManhattan distance; hard rhombic bands.
waveA ramp bent by a sine along the rows.
rippleConcentric rings travelling outward.
spiralConic and radial combined; it winds.
barberRepeating diagonal stripes that climb.
cometOne bright head with a trailing falloff.
scanA single band sweeping edge to edge.
plasmaSummed sines; the classic demoscene field.
pulseThe whole bar moves through the ramp at once.
breatheLike pulse but eased, so it swells.
rainbowIgnores the stops and rotates hue.
strobeSnaps between stops with no blend.

Signals (26)

Used by rules, hideWhen and showOnlyWhen. A signal whose data is absent always returns false, so a missing sampler never fires a threshold.

signalthresholdfires when
ci.failingThe latest run on this branch concluded in failure.
ci.passingThe latest run concluded successfully.
ci.runningA run is queued or in progress.
pr.approvedThe open PR is approved.
pr.changesA reviewer requested changes.
pr.pendingThe PR is open and awaiting review.
pr.openAny open PR exists for this branch.
git.conflictAt least one conflicted path.
git.dirtyfiles (default 1)Modified or untracked files above the count.
git.aheadcommits (default 1)Ahead of upstream by at least this many.
git.behindcommits (default 1)Behind by at least this many.
git.cleanNothing staged, modified, untracked or conflicted.
context.above% (default 80)Context window usage crosses this percentage.
fivehour.above% (default 80)The five-hour window crosses this percentage.
sevenday.above% (default 80)The seven-day window crosses this percentage.
cost.above$ (default 20)Session spend crosses this many dollars.
battery.below% (default 20)Battery drops under this percentage, unplugged.
review.waitingPull requests are awaiting your review.
cpu.above% (default 85)Sampled CPU crosses this percentage.
mem.above% (default 85)Memory in use crosses this percentage of total.
swap.aboveMB (default 512)Swap in use crosses this many megabytes.
disk.above% (default 90)Disk used crosses this percentage.
load.aboveload (default 8)One-minute load average crosses this value.
gpu.above% (default 90)GPU utilisation crosses this percentage.
vram.above% (default 90)VRAM in use crosses this percentage of total.
alwaysUnconditional; useful for a steady accent.

Border edges (7)

An edge is characters and costs columns, which the solver measures. A line (underline / overline) is SGR and costs none.

edgecolumnsnote
none0
thin2
block2
bracket2
round2
angle2
powerline2needs a Nerd Font

Targets

targetnote
Claude CodeCaptured stdout. Multi-row, OSC 8 links, no click.
tmuxOne line. Real click dispatch, no hyperlinks.
Web previewThe builder canvas. Everything works here.