| name | hud |
| description | Install, customize, and manage the statusline HUD for Claude Code. Use when the user wants to: install the statusline on a new machine/node, change statusline colors or theme, adjust context tier thresholds, toggle statusline elements on/off, switch between profiles, or troubleshoot statusline display issues.
|
| user_invokable | true |
/hud — Statusline HUD Manager
Install, customize, or troubleshoot the statusline HUD (v18 — L2 git row redesigned: branch is the spine (bold light gray), worktree becomes a dim fork glyph, PR # rendered as a charcoal pill via cached gh, sync uses chevrons, conflicts surface as a red pill, detached HEAD shows @short-sha, sibling worktree count appears only from main repo. v17 extracted the Python body into statusline-hud.py so the .sh is a thin wrapper.) Three workflows:
Step 1: Determine Intent
Present the user with a choice using AskUserQuestion:
Question: "What would you like to do with the statusline?"
Header: "Action"
Options:
- Install — Set up the HUD on this machine (or reinstall from template)
- Customize — Change colors, theme, layout, or tier thresholds
- Troubleshoot — Fix display issues or verify configuration
Route to the corresponding workflow below.
Workflow 1: Install
For new machines, new nodes, or reinstalling from the golden template.
1a. Detect Platform
Check the OS:
- Windows (
win32) — Use statusline-hud.ps1
- Linux/macOS — Use
statusline-hud.sh
1b. Copy Script
Copy the appropriate template from this skill's assets/ folder to ~/.claude/:
- Windows: Copy
assets/statusline-hud.ps1 to ~/.claude/statusline-hud.ps1
- Linux/macOS: Copy BOTH files. Copy
assets/statusline-hud.py to ~/.claude/statusline-hud.py first, then copy assets/statusline-hud.sh to ~/.claude/statusline-hud.sh and chmod +x it. The .sh is a thin wrapper that execs the .py sibling — copying only the .sh produces FileNotFoundError: statusline-hud.py on every render.
1c. Configure settings.json
Read ~/.claude/settings.json. If a statusLine block already exists, ask before overwriting. Add or update:
Windows:
{
"statusLine": {
"type": "command",
"command": "powershell -NoProfile -ExecutionPolicy Bypass -File /c/Users/USERNAME/.claude/statusline-hud.ps1"
}
}
Replace USERNAME with the actual Windows username.
Critical Windows gotchas:
- Use forward slashes (
/c/Users/...) in the -File path. Claude Code invokes statusLine commands through Git Bash on Windows; bash strips unquoted backslashes, so C:\Users\USERNAME\... becomes C:UsersUSERNAME... (silent failure, nothing appears).
- Do not prefix with
chcp 65001 >nul &&. chcp is a CMD built-in and doesn't exist in Git Bash — the && short-circuits and powershell never runs. The .ps1 template sets UTF-8 encoding internally ([Console]::InputEncoding), so no prefix is needed.
Linux/macOS:
{
"statusLine": {
"type": "command",
"command": "~/.claude/statusline-hud.sh"
}
}
1d. Verify
Show the current statusLine config and confirm the script file exists at the configured path. If test-statusline.json exists in ~/.claude/, pipe it into the script to verify output.
Workflow 2: Customize
The main event. Uses an interactive playground for visual customization.
2a. Detect Current Configuration
Read the user's current script at ~/.claude/statusline-hud.{ps1|sh} to detect:
- Which theme is active (compare color values against the theme maps below)
- Any custom color overrides
- Current tier thresholds
- Bar width
2b. Generate Playground
- Read the golden playground template from
assets/statusline-playground.html
- Build an initial state object based on:
- The user's current configuration (from step 2a)
- Any specific request from the user (e.g., "I want Nord" →
{ theme: 'nord' })
- Inject the state by replacing
/*__INJECT__*/ null with the JSON state object
- Write to
/tmp/statusline-playground.html
- Open in browser:
open /tmp/statusline-playground.html (macOS) or use appropriate opener
Injection format — only include fields that differ from defaults:
const INJECTED = { theme: 'nord', tiers: { moderate: 40 } };
If the user has no specific request and is on the default Gold theme, skip injection entirely (the template uses Gold by default).
2c. User Explores
Tell the user: "I've opened the HUD Playground in your browser. You can:
- Pick a theme preset (Gold, Nord, Tokyo Night)
- Fine-tune individual colors by clicking the swatches
- Adjust context tier thresholds
- Toggle elements on/off
- See your changes live in the terminal preview
When you're happy, click Copy Prompt and paste it back here."
2d. Apply Changes
When the user pastes the prompt back, parse it and apply changes:
- Read the current script at
~/.claude/statusline-hud.{ps1|sh}
- For each color variable in the prompt, use Edit to update the corresponding line in the script
- If tier thresholds changed, update the threshold values in the script
- If bar width changed, update
bar_len in the script
- If elements are hidden, comment out or conditionally skip those elements
- Test with
test-statusline.json if available
- Show the user the result
Important: Only modify the specific lines that correspond to the user's choices. Do NOT rewrite the entire script.
Theme Reference
The playground includes three built-in themes. Each theme defines all 27 color variables:
| Element | Monochrome Gold (default) | Nord | Tokyo Night |
|---|
| Project name | 1;38;5;252 (bold light gray) | 1;38;5;110 (bold frost blue) | 1;38;5;141 (bold purple) |
| Model name | 38;5;146 (sage lavender) | 38;5;110 (frost) | 38;5;111 (blue) |
| Cost | 1;38;5;252 (bold light gray) | 38;5;222 (aurora yellow) | 38;5;222 (warm yellow) |
| Env WSL | 38;5;179 (muted gold) | 38;5;110 (frost blue) | 38;5;111 (blue) |
| Env SSH | 38;5;179 (muted gold) | 38;5;209 (nord orange) | 38;5;203 (pink-red) |
| Env Linux | 38;5;245 (gray) | 38;5;60 (nord gray) | 38;5;59 (dark gray) |
| Healthy tier | 1;38;5;252 (bold light gray) | 38;5;108 (nord green) | 38;5;114 (green) |
| Moderate tier | 1;38;5;252 (bold light gray) | 38;5;222 (nord yellow) | 38;5;221 (amber) |
| High tier | 38;5;179 (muted gold) | 38;5;209 (nord orange) | 38;5;208 (orange) |
| Critical tier | 1;38;5;167 (bold muted red) | 1;38;5;167 (bold nord red) | 1;38;5;203 (bold pink-red) |
| Line 2 dim | 38;5;239 (dark gray) | 38;5;60 (nord gray) | 38;5;59 (dark gray) |
| MCP/Plugins | 38;5;239 (dark gray) | 38;5;108 (nord green) | 38;5;78 (green) |
Full color mappings for all 27 variables are embedded in the playground HTML.
Nerd Font Icons
Requires JetBrainsMono Nerd Font v3.1+:
| Icon | Codepoint | Element |
|---|
| Brain | \uf490 | Opus model |
| Edit square | \uf044 | Sonnet model |
| Lightning bolt | \uf0e7 | Haiku model |
| Fire | \uf06d | Fable model |
| Folder-open | \uf07c | Project name |
| Dollar sign | \uf155 | Session cost |
| Ubuntu logo | \uf31b | WSL environment |
| Cloud | \uf0c2 | SSH environment |
| Linux penguin | \uf17c | Native Linux |
| Shield | \uf132 | Sandbox badge |
| Git branch | \ue725 | Branch name |
| Sitemap | \uf0e8 | MCP server count |
| Cubes | \uf1b3 | Plugin count |
| Headphones | \uf025 | Voice daemon |
Model-Specific Colors
These are hardcoded per-model and not affected by theme choice:
| Model | Color | Icon |
|---|
| Opus | 38;5;111 (blue) | Brain |
| Sonnet | Theme's model color | Pencil |
| Haiku | 38;5;108 (green) | Lightning bolt |
| Fable | 38;5;141 (purple) | Fire |
Workflow 3: Troubleshoot
Diagnose and fix statusline display issues.
3a. Check Configuration
- Read
~/.claude/settings.json — verify statusLine block exists and has correct format
- Check that the
command path points to an existing file
- Verify the script file has correct permissions (Linux: executable)
3b. Test Script
If ~/.claude/test-statusline.json exists:
- Pipe it into the script
- Check for errors (non-zero exit, stderr output)
- Check for encoding issues (garbled characters)
If test data doesn't exist, create a minimal test JSON:
{"model":{"display_name":"Test"},"workspace":{"project_dir":"/tmp/test"},"context_window":{"used_percentage":42,"context_window_size":200000},"cost":{"total_cost_usd":1.23}}
3c. Common Issues
| Symptom | Cause | Fix |
|---|
| No statusline visible | Missing or wrong path in settings.json | Verify path, run Install workflow |
FileNotFoundError: statusline-hud.py (Linux/macOS) | Only .sh was copied — the wrapper needs its .py sibling | Copy assets/statusline-hud.py to ~/.claude/statusline-hud.py. (The skill dir at ~/.claude/skills/statusline/assets/ already has it — cp ~/.claude/skills/statusline/assets/statusline-hud.py ~/.claude/statusline-hud.py recovers without re-running install.) |
HUD: python3 not found on PATH (Linux/macOS) | Fresh macOS or minimal container without Python 3 | Install Python 3.10+. macOS: xcode-select --install. Debian/Ubuntu: apt install python3. Alpine: apk add python3. |
| No statusline on Windows + nothing runs | Windows path uses \\ — Git Bash strips the backslashes silently | Switch to /c/Users/USERNAME/.claude/statusline-hud.ps1 (forward slashes) |
No statusline on Windows + chcp prefix present | chcp doesn't exist in Git Bash, && aborts before powershell | Remove the chcp 65001 >nul && prefix — the .ps1 sets UTF-8 internally |
| Garbled characters (Linux) | Terminal encoding mismatch | Verify LANG=en_US.UTF-8 |
| Colors not showing | Terminal doesn't support 256-color | Check $TERM value, try TERM=xterm-256color |
| Script error on startup | JSON parsing failure | Check script reads stdin correctly, test with piped JSON |
| "command not found" | Wrong shell or path | Verify powershell is on PATH (Windows) or #!/bin/bash + chmod +x (Linux) |
| Icons show as boxes/? | Missing Nerd Font | Install JetBrainsMono Nerd Font v3.1+, set as terminal font |
3d. Reset to Default
If the user wants to start fresh, offer to run the Install workflow to copy the template from assets/ (which overwrites the current script with the golden v16 version).
Reference
For the full list of JSON fields available in stdin data, see references/available-data.md in this skill folder.
Rules
- Never overwrite the user's script without asking — always confirm before writing
- Always test after changes — pipe test data through the modified script
- Preserve VPS-specific features in .sh — cache rate and model color are intentionally kept
- Use Edit, not Write — modify specific lines when customizing, don't rewrite the whole file
- Asset scripts are golden sources — these are the reset/install templates (v17), not the live scripts
- Nerd Font required — v8+ uses JetBrainsMono Nerd Font icons; without it, icons render as boxes
- MCP discovery — v9 reads
.mcp.json (project) + ~/.claude/settings.json (user) to show MCP server and plugin counts on line 2
- Voice daemon — Linux/macOS only (
.sh): queries /tmp/claude-voice.sock if present, shows headphones icon with play/pause/idle state and queue depth. No socket = no display = zero overhead. Not available in PS1 (Windows lacks Unix sockets)
- Memory pressure tracking (v16, Linux/.sh only) — memory segment surfaces three signals: RAM %, swap %, and
init.scope cgroup %. Worst-of-three drives color. Swap shown when >15%, scope when >50%. Pressure tiers are tighter than RAM tiers (WARN 40% / HIGH 70% / CRIT 85%) because swap thrash and cgroup pressure are leading indicators of WSL crashes, not trailing ones. Reads /proc/meminfo for RAM/swap and /sys/fs/cgroup/init.scope/memory.current|max for cgroup. Cgroup read silently skips if path is absent (non-systemd hosts)
- PS1/SH parity (v16) — Both scripts share the 3-line layout and identical features: monochrome gold theme, Nerd Font icons, 200K→full-window rescaling context bar, extended context badge, model-specific colors/icons/full name, sandbox (SBX) badge, git state line (branch, ahead/behind, modified/staged/untracked, worktree count with native + fallback detection), rate limits with adaptive ordering and reset timers, worktree session indicator, agent, output style, MCP and plugin counts. PS1 detects WIN/SSH; SH detects WSL/SSH/DKR/LNX. SH-exclusive: voice daemon (
/tmp/claude-voice.sock — Unix sockets) and memory pressure (/proc/meminfo + init.scope cgroup). Neither is feasible on Windows natively.
- L2 git row (v18) — Layout is
[branch] [wt-mark] · [PR pill] · [sync] · [dirty] · [conflict] · [siblings on main]. Order is fixed; segments collapse cleanly when zero/absent. Branch is the only thing that's always bright (bold 252). Everything else earns brightness when it has something to say. Worktree mark is a single dim fork glyph (\uf126). Wt-name surfaces in dim parens only when it diverges from the branch basename (the one case both names actually carry information). Sibling worktree count moves off L2 inside a worktree (it's noise from in-wt — you already know there are many) and reappears on main repo where the count is actionable.
- PR pill (v18) —
gh pr view --json number,state,isDraft cached for 5min in /tmp/statusline-pr-{md5(repo:branch)[:12]}.json. Negative results cached too, so non-PR branches don't pay the gh shellout on every render. Cache miss is bounded by 2s timeout. Only fires when the branch has an upstream (free check via @{u} from the existing ahead/behind rev-list). Pill colors: open = gold (179) on charcoal (236); merged = green (108) on charcoal + " merged" suffix; closed = red (167) on dark-red (52) + " closed"; draft = light gray (245) on charcoal + " draft". gh missing = silent skip — caches {} so we don't retry constantly.
- Conflict pill (v18) — count from
git diff --name-only --diff-filter=U. Rendered as red pill ( !N conflict) on dark-red bg. Most urgent state; positional, but the color does the work.
- Detached HEAD (v18) —
git rev-parse --abbrev-ref HEAD returns "HEAD" when detached. Spine becomes @<short-sha> instead of <icon> <branch>. PR fetch and upstream check both skip on detached.
- Icon roster (v18) — branch
\ue725 (dimmed); worktree \uf126 (git-fork — replaces \uf2d0 window for tighter "branched-off working copy" semantic); PR \uf407; ahead `\uf102` (chevron-up — replaces `\uf062` fat arrow); behind \uf103 (chevron-down); conflict \uf071 (warning triangle).
.sh is a wrapper around .py (v17) — the bash script is a 14-line dispatcher that execs statusline-hud.py. The Python body was extracted from an embedded python3 -c '...' heredoc after the bash/Python quoting boundary caused a runtime NameError regression. Install must copy both files on Linux/macOS, .py first; .sh alone produces FileNotFoundError. Wrapper fails soft when python3 is absent (exit 0, whitelisted stderr — see Troubleshoot row). Version lives in the .py header only.
- Any change to
statusline/assets/* must pass smoke CI — .github/workflows/smoke.yml pipes a dirty-state fixture through the .sh on every push touching the asset tree and asserts exit 0, stdout contains Opus, stderr empty or matches the python-missing guard. Mirror changes to Command Center's backend/assets/statusline/ after shared-skills smoke is green.