claude-hud is a real-time statusline HUD for Claude Code. It runs as the
Claude Code statusline subprocess on every prompt, parses the JSON Claude Code
writes to its stdin, and prints a colourised, terminal-aware multi-line view of
the current session: model and provider, context-window usage, project path,
git status, configuration counts (CLAUDE.md / rules / MCPs / hooks), running
tools, sub-agents, todos, weekly and 5-hour rate-limit usage, optional Claude
Code version, optional approximate RAM use, optional cost estimation, optional
session token totals, and an optional user-defined custom line.
It is distributed exclusively as a Claude Code plugin through the Claude
Code plugin marketplace — there is no npm install path, no global binary, and
no Node service. You install it through Claude Code itself, then run a setup
slash command that wires the compiled dist/index.js into Claude Code's user
settings.json as the statusLine command.
This guide covers installation, every option that surfaces in the HUD, the common configuration recipes, and the rough edges to avoid.
1. Quick Start
claude-hud ships through Claude Code's plugin marketplace. Once you have
Claude Code installed (Node 18+ on the host, version 2.0+ recommended), three
slash commands inside Claude Code give you a working HUD in under a minute.
Tip
The marketplace install is the only supported install path. There is no
npm install -g claude-hud, no Homebrew formula, and no standalone binary — if a tutorial points you to npm, ignore it and follow the steps below.
Install in three slash commands
Inside Claude Code:
/plugin marketplace add jarrodwatts/claude-hud
/plugin install claude-hud
/claude-hud:setup
/claude-hud:setup is shipped by the plugin (its source lives at
commands/setup.md). It writes a dynamic, version-resolving statusline command
into your Claude Code user settings.json and prints a one-time confirmation
line. After it finishes, the HUD takes over your Claude Code statusline on the
next prompt.
What you should see
After setup, the next time Claude Code redraws its statusline you'll see something like the expanded layout (default):
[Opus 4.6] my-repo git:(main*)
Context █████████░ 43% │ Usage 5h ████░░░ 38%
2 CLAUDE.md │ 7 rules │ 4 MCPs │ 2 hooks
◐ Read: src/index.ts │ ✓ Bash ×4 │ ✓ Edit ×2
▸ Wire up the statusline (3/8)
Each line above is one of claude-hud's eight rendering elements (project,
context, usage, memory, environment, tools, agents, todos). Lines
suppress themselves cleanly when they have nothing to show — for example, the
todos line stays hidden until Claude Code emits a TodoWrite tool call.
Sanity-check it ran
claude --version
2.1.81
If Claude Code is on PATH, claude-hud will pick up its version when
display.showClaudeCodeVersion is enabled. Versions older than 2.0 may not
emit the JSON shape claude-hud expects from stdin and will fall back to a
sparser HUD.
Note
The HUD renders only on Claude Code prompts — it has no daemon, no separate CLI, and no log file. Everything you see is computed fresh from the JSON Claude Code passes to its statusline subprocess, plus a couple of mtime-keyed caches under
~/.claude/plugins/claude-hud/.
What to try next
- Section 2 walks through every supported install path, including offline / forked-marketplace installs.
- Section 3 lists every configuration key and its default.
- Section 4 covers the eight HUD elements, when each one renders, and how to turn them on or off.
- Section 5 is a recipe book: enable cost estimation, switch to Chinese, reorder lines, customise colours, etc.
2. Installation
Prerequisites
| Requirement | Minimum | Recommended | Notes |
|---|---|---|---|
| Claude Code | 2.0+ | 2.1.6+ | Native context percentage (used_percentage in stdin) requires 2.1.6+ |
| Node.js | 18.0.0 | 20 LTS or 22 LTS | The plugin is shipped as compiled JS; package.json declares "engines": {"node": ">=18.0.0"} |
| Terminal | Any | Truecolor + UTF-8 | Wide-character / emoji rendering and 256-color / hex colors require a modern terminal |
| OS | macOS, Linux, Windows | macOS or Linux | Windows works (Windows 11 issues exist; see Troubleshooting); macOS may require Claude Code restart after first install |
Important
claude-hudis a Claude Code plugin. It is NOT published to npm. Trying to runnpm install -g claude-hudwill fail with a 404 from the registry. The only supported distribution channel is the Claude Code plugin marketplace.
Method 1 — Marketplace install (recommended)
This is the only path the maintainer publishes. From a Claude Code session:
/plugin marketplace add jarrodwatts/claude-hud
/plugin install claude-hud
/claude-hud:setup
What each command does:
/plugin marketplace add jarrodwatts/claude-hud— registers the GitHub repo as a marketplace source for your local Claude Code./plugin install claude-hud— clones the published plugin into your Claude Code plugin directory (~/.claude/plugins/claude-hud/by default, or$CLAUDE_CONFIG_DIR/plugins/claude-hud/ifCLAUDE_CONFIG_DIRis set)./claude-hud:setup— writes the statusline wiring into your usersettings.json. The wiring is dynamic — it resolves to the currently installed plugin version at each invocation, so plugin upgrades take effect without rerunning setup.
After these three commands the next Claude Code prompt will redraw the
statusline using claude-hud's output.
Method 2 — Verify install location
If /claude-hud:setup ran but you don't see the HUD, confirm the plugin
landed where Claude Code expects:
ls -la ~/.claude/plugins/claude-hud/dist/index.js
-rw-r--r-- 1 you staff ... index.js
If you've set CLAUDE_CONFIG_DIR to a non-default location, swap the path:
ls -la "$CLAUDE_CONFIG_DIR/plugins/claude-hud/dist/index.js"
claude-hud resolves its plugin directory through getHudPluginDir(), which
honours CLAUDE_CONFIG_DIR consistently across all caches (transcript, config,
version, speed). If CLAUDE_CONFIG_DIR is set but doesn't exist or is the
wrong path, no errors surface — the HUD simply renders without cached data.
Method 3 — Pinning a forked marketplace
Power users can fork the repo, point Claude Code at the fork, and ship local patches before they're merged upstream:
/plugin marketplace add yourusername/claude-hud
/plugin install claude-hud
/claude-hud:setup
Setup must be re-run if you change the install location or upgrade across a
breaking config-shape change (rare — the plugin auto-migrates legacy layout
strings, see Section 3).
Removing claude-hud
There is no dedicated uninstall command. To stop the HUD without removing
the plugin, edit ~/.claude/settings.json and delete or comment out the
statusLine entry. To remove the plugin entirely:
/plugin uninstall claude-hud
Warning
If you remove the plugin without first clearing the
statusLineentry fromsettings.json, Claude Code will try to spawn a missing binary on every prompt and silently render an empty statusline. Always editsettings.jsonafter/plugin uninstall.
Verifying the install
A clean install should respond to a manual stdin smoke test. From the plugin directory:
echo '{"model":{"display_name":"Opus"},"context_window":{"current_usage":{"input_tokens":45000},"context_window_size":200000},"transcript_path":"/tmp/test.jsonl"}' | node dist/index.js
[Opus] █░░░░░░░░░ 23%
This is exactly the same harness npm run test:stdin exercises during
development. If it prints a single [Opus] ... 23% line, the install is
healthy.
3. Configuration
claude-hud reads its config from a single file:
~/.claude/plugins/claude-hud/config.json
(or $CLAUDE_CONFIG_DIR/plugins/claude-hud/config.json when the env var is
set). The file is plain JSON. If it doesn't exist, defaults from
DEFAULT_CONFIG are used. If it exists but is malformed, the entire defaults
table is silently substituted — there is no startup error.
Tip
Every key is optional. You can write only the keys you want to change; the merge logic in
mergeConfig()fills in everything else and clamps invalid values back to the default rather than crashing.
Top-level keys
| Key | Type | Default | What it does |
|---|---|---|---|
language |
'en' | 'zh' |
'en' |
Translates labels (Context, Usage, Weekly, Approx RAM, rules, hooks, Cost, Est., resets, resets in, in, cache, out, tok/s, Limit reached, All todos complete, init messages). |
lineLayout |
'expanded' | 'compact' |
'expanded' |
Expanded prints each element on its own line. Compact crushes everything onto a single session line. Activity lines (tools/agents/todos) always render below. |
showSeparators |
boolean | false |
Inserts a dim ───── line between header lines and the activity lines. |
pathLevels |
1 | 2 | 3 |
1 |
How many trailing path segments to print for the project label (my-repo vs parent/my-repo vs grand/parent/my-repo). |
elementOrder |
HudElement[] |
[project, context, usage, memory, environment, tools, agents, todos] |
The order lines render in. Unknown items are dropped, duplicates are de-duped, empty/invalid arrays fall back to the default order. |
gitStatus |
object | see below | Git branch / dirty / ahead-behind / file-stats settings. |
display |
object | see below | The 30-key display flag bag. |
colors |
object | see below | ANSI overrides per category. |
gitStatus keys
| Key | Type | Default | What it does |
|---|---|---|---|
enabled |
boolean | true |
Master toggle. When false, no git fork-execs run at all. |
showDirty |
boolean | true |
Append * to the branch name when the worktree has uncommitted changes. |
showAheadBehind |
boolean | false |
Show ↑N / ↓N next to the branch from git rev-list --left-right --count @{upstream}...HEAD. |
showFileStats |
boolean | false |
Show modified/added/deleted/untracked counts (compact) or a per-file diff line (expanded), driven by git status --porcelain and git diff --numstat HEAD. |
pushWarningThreshold |
number | 0 |
Colour ↑N yellow once your local branch is N or more commits ahead of upstream. 0 disables. |
pushCriticalThreshold |
number | 0 |
Colour ↑N red once you're N or more commits ahead. 0 disables. |
display keys
| Key | Type | Default | What it does |
|---|---|---|---|
showModel |
boolean | true |
Print the [Opus 4.6] model badge. |
showProject |
boolean | true |
Print the project path label (and OSC-8 hyperlink it to file:// in expanded mode). |
showContextBar |
boolean | true |
Show the unicode context-usage bar (█████░░░). |
contextValue |
'percent' | 'tokens' | 'remaining' | 'both' |
'percent' |
Format of the value to the right of the bar — 43%, 87k/200k, 57%, or 43% (87k/200k). |
showConfigCounts |
boolean | false |
Print 2 CLAUDE.md │ 7 rules │ 4 MCPs │ 2 hooks on the environment line. |
showCost |
boolean | false |
Print session cost — uses cost.total_cost_usd from stdin if Claude Code provides it (Cost $1.23), otherwise falls back to a model-priced estimate from accumulated session tokens (Est. $1.23). Suppressed for non-Anthropic providers (Bedrock). |
showDuration |
boolean | false |
Print the session duration as ⏱️ 1h 17m. |
showSpeed |
boolean | false |
Print recent output speed as out: 18.4 tok/s using a 2-second sliding window. |
showTokenBreakdown |
boolean | true |
At ≥85% context, append (in: 87k, cache: 23k) to the context line. |
showUsage |
boolean | true |
Print the 5-hour and (when over sevenDayThreshold) weekly rate-limit windows. |
usageBarEnabled |
boolean | true |
Render the usage values with bars rather than just percentages. |
showTools |
boolean | false |
Show the most recent running tools and a top-4 frequency tally of completed tools. |
showAgents |
boolean | false |
Show running and recently completed sub-agents (Task / Agent tool uses). |
showTodos |
boolean | false |
Show the current in_progress todo + (completed/total) count, or "All todos complete" when finished. |
showSessionName |
boolean | false |
Print the slug or /rename custom title for the current Claude Code session. |
showClaudeCodeVersion |
boolean | false |
Run claude --version (cached, mtime-keyed) and print CC v2.1.81. |
showMemoryUsage |
boolean | false |
Add an "Approx RAM" line to expanded layout (uses /usr/bin/vm_stat on macOS, os.totalmem/os.freemem elsewhere). Suppressed in compact layout. |
showSessionTokens |
boolean | false |
Add a Tokens 110k (in: 87k, out: 12k, cache: 11k) line totalling all assistant-message usage in the transcript. |
showOutputStyle |
boolean | false |
Append style: <name> to the environment line if Claude Code's outputStyle is set in settings.json or settings.local.json. |
autocompactBuffer |
'enabled' | 'disabled' |
'enabled' |
When enabled, the context bar reflects Claude Code's autocompact buffer (~16.5% of the window, scaled by raw usage). When disabled, the bar shows raw input/cache usage with no buffer. Ignored if Claude Code 2.1.6+ supplies a native percentage — the native value always wins. |
usageThreshold |
number | 0 |
Hide the usage line until either window is at this percent (e.g. 30 to declutter when fresh). |
sevenDayThreshold |
number | 80 |
Only show the weekly window once it crosses this percent. |
environmentThreshold |
number | 0 |
Hide the environment line until total CLAUDE.md + rules + MCPs + hooks is at least this many. |
modelFormat |
'full' | 'compact' | 'short' |
'full' |
full: raw Claude Code display name. compact: strip a trailing (... context) suffix. short: also strip a leading Claude . |
modelOverride |
string ≤80 chars | '' |
If non-empty, replaces the model badge text entirely. |
customLine |
string ≤80 chars | '' |
Static text appended after duration/cost/extras. Empty disables it. |
colors keys
Each value is one of: a named preset (dim, red, green, yellow,
magenta, cyan, brightBlue, brightMagenta), a 256-color index 0-255,
or a hex string #rrggbb. Anything else falls back to the default.
| Key | Default | Used for |
|---|---|---|
context |
green |
Context bar (under 70%). |
usage |
brightBlue |
Usage bar (under 75%). |
warning |
yellow |
Context bar 70–84% and ↑N over pushWarningThreshold. |
usageWarning |
brightMagenta |
Usage bar 75–89%. |
critical |
red |
Context ≥85%, usage ≥90%, ↑N over pushCriticalThreshold, "Limit reached" badge. |
model |
cyan |
Model badge [Opus 4.6]. |
project |
yellow |
Project path. |
git |
magenta |
git:( and ). |
gitBranch |
cyan |
Branch name and ahead/behind. |
label |
dim |
All "Usage", "Context", "Weekly", "5h", count labels, etc. |
custom |
208 (Claude orange) |
The customLine text. |
Minimal annotated config example
{
"language": "en",
"lineLayout": "expanded",
"pathLevels": 2,
"gitStatus": {
"enabled": true,
"showAheadBehind": true,
"showFileStats": true,
"pushWarningThreshold": 5,
"pushCriticalThreshold": 20
},
"display": {
"showConfigCounts": true,
"showTools": true,
"showAgents": true,
"showTodos": true,
"showCost": true,
"showDuration": true,
"showClaudeCodeVersion": true,
"showSessionTokens": true,
"modelFormat": "compact",
"contextValue": "both"
},
"colors": {
"model": "#7B68EE",
"project": 214,
"custom": "brightMagenta"
}
}
Note
Configuration changes take effect on the next Claude Code prompt — no reload command. The mtime-keyed config-counts cache also auto-invalidates when the underlying CLAUDE.md / settings.json files change.
Legacy layout migration
mergeConfig() understands the v0.0.x string layout: "default" and
layout: "separators", and the third-party object form
layout: { lineLayout, showSeparators, pathLevels }. They are translated to
lineLayout / showSeparators / pathLevels on load and the legacy layout
key is dropped from the merged config. You don't need to migrate by hand.
4. Core Usage
claude-hud has one job: every time Claude Code calls its statusline command,
read JSON from stdin, parse the active transcript JSONL file, run a handful of
fast probes (git, config-counts, optional claude --version, optional memory),
and print between one and a dozen styled lines. There are no other commands,
no daemon, and no UI — everything is driven by Claude Code itself. This
section walks through what each line shows, when it appears, and the
conditions you'll see colour or visibility change.
Layouts
The lineLayout setting picks one of two top-level rendering paths.
Expanded (default)
Each enabled element renders on its own line, in elementOrder:
[Opus 4.6] my-repo git:(main*)
Context █████████░ 43%
Usage ████░░ 38%
Approx RAM █████░░ 52% 8.2 GB / 16.0 GB (52%)
2 CLAUDE.md │ 7 rules │ 4 MCPs │ 2 hooks
◐ Read: src/index.ts │ ✓ Bash ×4
▸ Wire up the statusline (3/8)
When the terminal is wide enough, the context and usage lines are merged
on a single line (the renderer detects when they're adjacent in
elementOrder and tries the combined width first). When that combined line
won't fit, they fall back to two separate lines.
Compact
Everything before the activity lines is squashed onto one big session line
joined by |:
[Opus 4.6] █████████░ 43% | my-repo git:(main*) | 2 CLAUDE.md | 7 rules | Usage ████░░ 38% | ⏱️ 1h 17m
◐ Read: src/index.ts │ ✓ Bash ×4
▸ Wire up the statusline (3/8)
Activity lines (tools, agents, todos) always render below the header
in either layout. Each compact line is wrapped to terminal width with grapheme
awareness (emoji, CJK, ANSI escapes are accounted for) — when a segment can't
fit, it is truncated with ... and the wrap point prefers | separators
so model badges aren't split.
Tip
If the compact layout looks identical to expanded after upgrading from v0.0.11, see Troubleshooting (issues #408 and #412) — there's a known regression in v0.0.12 where compact may behave like expanded in some session shapes.
Element walkthrough
project
The first element in the default order. Renders the model badge, the project
folder name (last pathLevels segments of the cwd Claude Code reports),
optional git block, optional session name, optional Claude Code version,
optional --extra-cmd label, optional speed, optional duration, optional cost
estimate, optional custom line. The project name is wrapped in an OSC-8
hyperlink to file://<cwd> and the git branch is hyperlinked to the GitHub
branch URL when origin is a GitHub remote.
context
The context-usage line (Context █████████░ 43%). Uses Claude Code's native
context_window.used_percentage field when present (Claude Code 2.1.6+) for
parity with /context. Otherwise falls back to summing
input_tokens + cache_creation_input_tokens + cache_read_input_tokens over
context_window_size, optionally adding the autocompact buffer (~16.5% of the
window, scaled by raw usage so it doesn't fire on a fresh /clear).
Color thresholds: green under 70%, yellow 70–84%, red 85%+. At 85% or above,
showTokenBreakdown appends (in: 87k, cache: 23k) so you can see why you're
near the cap.
usage
The 5-hour and weekly rate-limit windows. Driven by stdin.rate_limits.five_hour
and stdin.rate_limits.seven_day. Each window has a used_percentage and a
resets_at epoch-seconds value. Color thresholds for the usage bar: brightBlue
under 75%, brightMagenta 75–89%, red 90%+. When either window hits 100% the line
collapses to ⚠ Limit reached (resets 1h 23m).
By default the weekly window stays hidden until it crosses
sevenDayThreshold (default 80%). Set usageThreshold if you want to hide
the whole line under a certain percentage.
Note
Both windows must be present in stdin for both to render. If only the weekly window is provided, it shows alone with the
Weeklylabel.
memory
Approximate RAM usage. Suppressed in compact layout regardless of
showMemoryUsage — it is intentionally only computed when the user is in
expanded layout AND has opted in. macOS uses /usr/bin/vm_stat to derive a
realistic figure (active + wired pages × page size); other platforms use
os.totalmem() / os.freemem().
environment
The 2 CLAUDE.md │ 7 rules │ 4 MCPs │ 2 hooks line. The counts are computed
by countConfigs():
- CLAUDE.md count — every
CLAUDE.md,CLAUDE.local.md, or.claude/CLAUDE.md/.claude/CLAUDE.local.mdfound in user scope (under~/.claude/or$CLAUDE_CONFIG_DIR) and project scope (under the cwd Claude Code reports). - Rules count — every
*.mdfile recursively under~/.claude/rules/and<cwd>/.claude/rules/. - MCPs count — every server name in
~/.claude/settings.json,~/.claude.json,<cwd>/.mcp.json,<cwd>/.claude/settings.json,<cwd>/.claude/settings.local.json, minus anything indisabledMcpServers/disabledMcpjsonServers. User and project scopes are counted separately — a server namedgitin both scopes counts as 2. - Hooks count —
Object.keys(config.hooks).lengthsummed across user and projectsettings.json/settings.local.json.
Results are cached at ~/.claude/plugins/claude-hud/config-cache/<sha256>.json
keyed by the cwd and Claude config dir, with mtime+size sentinels for every
relevant file and rule directory. The cache invalidates instantly when any of
those files change.
If showOutputStyle is on, style: <name> is appended (the value comes from
the outputStyle string in settings.json / settings.local.json).
tools
Up to two most-recent running tools (yellow ◐ ToolName: target) followed
by the top-4 most frequently used completed tools (green ✓ ToolName ×N).
Targets are extracted per tool name: Read/Write/Edit show the file path
(truncated to ≈20 chars, backslashes normalised to forward slashes), Glob
and Grep show the pattern, Bash shows the first 30 chars of the command.
agents
Up to three sub-agents (Task / Agent tool uses) — running first, then the
two most recently completed. Each line: ◐ <type> [<model>]: <description> (<elapsed>). Elapsed time auto-formats as <1s, Ns, Nm Ms, Nh Mm.
todos
Driven by Claude Code's TodoWrite, TaskCreate, and TaskUpdate tool
invocations, with a content-based reverse map so an in-progress task survives
a TodoWrite rewrite that re-orders the list. The line shows the current
in-progress item plus (N/M). When everything is completed the line
flips to ✓ All todos complete (M/M). Hides itself when the todo list is
empty.
--extra-cmd user-defined extra label
Pass a shell command that returns a JSON object { "label": "..." } and
claude-hud will run it (3-second timeout, 10KB max stdout, 50-char max
label after sanitising ANSI/control/bidi characters) and append the result
to the project line. Wire it in by editing the statusLine command in
~/.claude/settings.json:
{
"statusLine": {
"type": "command",
"command": "node ~/.claude/plugins/claude-hud/dist/index.js --extra-cmd 'echo {\\\"label\\\":\\\"build:passing\\\"}'"
}
}
Caution
The command runs through your shell as your user. It's intentional user input — don't paste an
--extra-cmdsomeone else gave you without reading it first.
Internationalisation
Set language: "zh" to switch every label and status string to Simplified
Chinese (label.context → 上下文, status.limitReached → 已达上限,
etc.). English is the only other supported locale. Keys missing from the
target locale fall back to English, then to the raw key name.
Warning
Issue #448 reports that the
session-tokensline still emits English labels (tok:/in:/out:/cache:) whenlanguage: "zh". If full Chinese coverage matters, leaveshowSessionTokensoff until a fix lands.
5. Common Tasks
This section is a recipe book — pick the goal, copy the JSON snippet into
~/.claude/plugins/claude-hud/config.json, save, and the next prompt picks
it up.
Recipe — Show everything (kitchen-sink config)
{
"lineLayout": "expanded",
"showSeparators": true,
"pathLevels": 2,
"gitStatus": {
"enabled": true,
"showDirty": true,
"showAheadBehind": true,
"showFileStats": true,
"pushWarningThreshold": 3,
"pushCriticalThreshold": 10
},
"display": {
"showModel": true,
"showProject": true,
"showContextBar": true,
"contextValue": "both",
"showConfigCounts": true,
"showCost": true,
"showDuration": true,
"showSpeed": true,
"showTokenBreakdown": true,
"showUsage": true,
"showTools": true,
"showAgents": true,
"showTodos": true,
"showSessionName": true,
"showClaudeCodeVersion": true,
"showMemoryUsage": true,
"showSessionTokens": true,
"showOutputStyle": true,
"modelFormat": "compact"
}
}
Recipe — Minimal (just model + context + git)
{
"lineLayout": "compact",
"display": {
"showConfigCounts": false,
"showUsage": false,
"showTools": false,
"showAgents": false,
"showTodos": false,
"showDuration": false,
"showTokenBreakdown": false
}
}
Recipe — Custom element order (todos at the top, hide environment)
{
"elementOrder": ["todos", "tools", "agents", "project", "context", "usage"],
"display": {
"showTodos": true,
"showTools": true,
"showAgents": true
}
}
memory and environment are still rendered if they appear in the order
array — drop them entirely to hide them. Unknown elements are silently
discarded; if the array ends up empty after validation, the default order
is restored.
Recipe — Cost-conscious power user
{
"display": {
"showCost": true,
"showSessionTokens": true,
"showSpeed": true,
"showDuration": true,
"showClaudeCodeVersion": true
}
}
showCost prefers Claude Code's native cost.total_cost_usd (label: Cost)
when present; otherwise it estimates from accumulated session tokens with the
built-in pricing table (label: Est.). The pricing table covers Opus 4 / 4.x,
Sonnet 4 / 3.7 / 3.5, and Haiku 3.5 — newer Anthropic models without an entry
will silently disable cost (issue #452).
Recipe — Hide noise until usage matters
{
"display": {
"usageThreshold": 50,
"sevenDayThreshold": 75,
"environmentThreshold": 5
}
}
The usage line stays hidden until either window reaches 50%, the weekly sub-window unlocks at 75%, and the environment line waits until total CLAUDE.md+rules+MCPs+hooks ≥ 5.
Recipe — Color customisation (Claude orange theme)
{
"colors": {
"model": "#FF8C00",
"project": "#FFB06A",
"context": "#5BA85B",
"warning": "#E0B040",
"critical": "#D44545",
"git": "magenta",
"gitBranch": "#FFB06A",
"custom": 208
}
}
Hex values must be #rrggbb; 3-letter shorthand is rejected. Numeric values
must be integers in 0-255 (256-color palette). Invalid values silently
fall back to defaults.
Recipe — Switch to Chinese labels
{
"language": "zh"
}
Recipe — Disabled autocompact buffer (raw context %)
{
"display": {
"autocompactBuffer": "disabled"
}
}
Useful if you're on Claude Code <2.1.6 and want the bar to track only
input/cache tokens, no margin for autocompact. On 2.1.6+ this flag is
moot — the native used_percentage always wins.
Recipe — Custom static label
{
"display": {
"customLine": "ENV=staging"
}
}
Limited to 80 characters. Anything longer is truncated by mergeConfig().
Recipe — Run a custom probe via --extra-cmd
{
"statusLine": {
"type": "command",
"command": "node ~/.claude/plugins/claude-hud/dist/index.js --extra-cmd 'echo {\\\"label\\\":\\\"v$(git describe --tags --abbrev=0)\\\"}'"
}
}
(That snippet goes in ~/.claude/settings.json, not in claude-hud's
config.json.) The command must print a single JSON object with a label
string. Output is sanitised — ANSI escapes, control characters, and bidi
overrides are stripped before display.
6. Troubleshooting
Common failure modes, with diagnostic steps and the GitHub issue numbers when there's an active discussion.
Diagnostic decision tree
- Nothing appears in the statusline at all.
Check
~/.claude/settings.jsonhas astatusLineentry. Re-run/claude-hud:setupif it's missing. - Statusline text is blank but Claude Code is otherwise fine.
Set
DEBUG=claude-hudin your environment and run a smoke test withnpm run test:stdinfrom the plugin directory. Check stderr for[claude-hud:*]messages. - HUD wraps onto many lines or shows odd widths. See "Status line wraps to multiple lines" below — likely the terminal-width fallback is firing.
- HUD shows but never updates. Confirm Claude Code itself is at 2.0+. Older Claude Code releases may not redraw the statusline on every prompt.
Error: HUD wraps to multiple lines / UNKNOWN_TERMINAL_WIDTH = 40 fallback fires
Cause: claude-hud is launched as a statusline subprocess with stdout
piped (so process.stdout.columns is undefined) AND stderr is also not a
TTY AND the COLUMNS environment variable is unset. The renderer falls
back to UNKNOWN_TERMINAL_WIDTH = 40, which is way too narrow for a real
HUD and causes the lines to wrap.
Solution:
- Run setup again — newer setup scripts can inject a
COLUMNS=$(tput cols)prefix into the statusline command. - Manually edit
~/.claude/settings.jsonand prependCOLUMNS=$(tput cols)to thestatusLine.commandvalue. - As a workaround, narrow the displayed elements (
showTools: false,showConfigCounts: false) until the wrap goes away.
Prevention: Tracked as issues #436, #437, #416. If you're on a fresh plugin install and still see this, file a follow-up against #416.
Error: HUD disappears entirely after the first message on Windows
Cause: Open issue #401 — under specific Claude Code + Windows Terminal combinations the statusline subprocess output is lost after the first prompt.
Solution: Restart Claude Code; if the regression returns, downgrade Claude Code or claude-hud to a known-good combination. Track #401 for an upstream fix.
Prevention: Use Windows Terminal Preview or WSL when possible.
Error: statusLine not working in VS Code
Cause: Issue #447 — VS Code's integrated Claude Code extension may not
read or surface the configured statusline. This is a Claude Code/VS Code
integration limitation, not a claude-hud bug.
Solution: Use the standalone Claude Code CLI in an external terminal (iTerm, Terminal, Windows Terminal, etc.) to see the HUD.
Prevention: Treat the VS Code extension as best-effort for statusline plugins until upstream Claude Code closes #447.
Error: macOS — HUD doesn't appear after install
Cause: Issue #375 — On macOS, Claude Code may need to be fully restarted
(not just reloaded) for the new statusline command to be picked up. The
plugin's init message even calls this out:
[claude-hud] Note: On macOS, you may need to restart Claude Code for the HUD to appear.
Solution: Quit Claude Code via the system menu (or cmd-q), confirm the
process is fully gone (ps aux | grep claude), then relaunch.
Prevention: After running /claude-hud:setup, expect to restart Claude
Code on macOS the first time.
Error: Cost line silently disappears
Cause: Issue #452 — When Claude Code reports a model that isn't in the
built-in pricing table (e.g. Haiku 4.5), estimateSessionCost() returns
null and renderCostEstimate() renders nothing.
Solution: Wait for an upstream pricing-table update, or pin
display.modelOverride so the badge name doesn't depend on Anthropic's
display label.
Prevention: This is a known gap; the project tracks new model entries through #452.
Error: Compact layout has no effect / matches expanded
Cause: Open issues #408 and #412 — the v0.0.12 implementation of the compact layout regressed against v0.0.11 in some configurations.
Solution: Until a fix lands, either pin to v0.0.11 (/plugin install claude-hud@0.0.11) or stay on lineLayout: "expanded". The session line
in compact mode is also affected by issue #379 (closed) where it could
wrap onto two lines.
Prevention: Track #412 for the canonical fix.
Error: git: renamed files show no line-diff annotation
Cause: Issue #450 — git diff --numstat HEAD reports the destination
path for renames, but the porcelain status output may show
old -> new. The matcher in applyLineDiffsToFiles() looks up by the
destination path, so renames work, but if the rename uses a similarity
threshold that triggers a different path representation the line diff is
dropped.
Solution: Treat missing line-diff on renamed files as cosmetic for now. Track #450.
Prevention: Disable showFileStats if it's important the diff numbers
match exactly.
Error: TodoWrite with duplicate content drops TaskUpdate
Cause: Issue #454 — When two todo entries share the exact same content
string, the content-based reverse map in processEntry() for TodoWrite
maps both task IDs to the same index. A subsequent TaskUpdate for the
second one updates the first instead.
Solution: Avoid duplicate todo content strings in your prompts. There's no user-side workaround inside the HUD itself.
Prevention: Track #454 for the upstream fix.
Error: Version cache never invalidates when Claude Code updates in-place
Cause: Issue #429 — getClaudeCodeVersion() keys its cache on the
binary path + mtime. If Claude Code's installer overwrites the file but
preserves the mtime (e.g. an in-place atomic replace that copies metadata),
the cache is hit and CC v... shows the old version.
Solution: Touch the binary (touch "$(which claude)") or delete
~/.claude/plugins/claude-hud/.claude-code-version-cache.json to force a
re-probe.
Prevention: Track #429 for an upstream cache-key fix.
Error: Setup script doesn't inject COLUMNS
Cause: Issue #416 — older builds of commands/setup.md write the
statusline command without a COLUMNS=$(tput cols) prefix, leaving the
HUD to fall back to UNKNOWN_TERMINAL_WIDTH = 40.
Solution: Either re-install the latest plugin version (which fixes the
setup template) or manually edit ~/.claude/settings.json and prepend
COLUMNS=$(tput cols) to the statusline command.
Prevention: Always run the most recent /claude-hud:setup after a
plugin upgrade.
Error: Empty config.json crashes nothing — but my changes are ignored
Cause: Malformed JSON in config.json is caught silently by
loadConfig()'s try / catch, and defaults are returned. Your changes
will be ignored if the file isn't valid JSON.
Solution: Validate with jq . ~/.claude/plugins/claude-hud/config.json
or python -m json.tool ~/.claude/plugins/claude-hud/config.json. Fix the
syntax error and try again.
Prevention: Use a JSON-aware editor; the file is small enough that proofreading by eye works.
Debugging — DEBUG=claude-hud
Set the environment variable DEBUG=claude-hud (or DEBUG=*) and the
plugin will write namespaced messages to stderr:
[claude-hud:config]— config-counts read failures (file permissions, invalid JSON insettings.json).[claude-hud:context]— whenautocompactBuffer: disabledis active, shows the raw vs buffered percent.[claude-hud:extra-cmd]—--extra-cmdparse / execution failures.
Stderr is connected to the real terminal even when stdout is piped, so these messages are visible in the Claude Code session you're using.
Warning
Don't ship
DEBUG=claude-hudin your daily statusline command — it writes to stderr on every prompt, which is fine but noisy. Use it only while debugging.
7. FAQ
Q: How do I install claude-hud?
Inside Claude Code, run /plugin marketplace add jarrodwatts/claude-hud,
then /plugin install claude-hud, then /claude-hud:setup. There is no
npm install -g claude-hud — that command will fail with a 404 because
the package is intentionally not published to npm.
Q: How do I update to the latest version? (issue #431)
Run /plugin marketplace update then /plugin install claude-hud to fetch
the latest published version. The statusline command in settings.json
resolves the plugin version dynamically, so you don't need to re-run
/claude-hud:setup after a routine upgrade.
Q: Is there a Codex/Cursor/Aider equivalent? (issue #215)
The maintainer has discussed a codex-hud but no public release exists at
the time of this guide. Each Claude Code-style tool would need its own
adapter to translate that tool's status JSON into the StdinData shape
claude-hud consumes.
Q: Why does the cost line sometimes show Cost and sometimes Est.?
Cost means Claude Code itself reported cost.total_cost_usd over stdin —
that's the authoritative number. Est. means claude-hud computed the cost
from accumulated session tokens × an internal pricing table. They should
agree closely for supported Anthropic models; estimates are unavailable for
Bedrock and unknown new models.
Q: Does claude-hud send my data anywhere?
No. There are no network calls. The plugin reads from local files
(transcript JSONL, ~/.claude/CLAUDE.md, etc.) and Claude Code's stdin,
runs git, claude --version, and vm_stat (macOS only) as subprocesses,
and writes only to its own caches under ~/.claude/plugins/claude-hud/.
Q: Where are caches stored?
| Cache | Path under plugin dir |
|---|---|
| Config counts | config-cache/<sha256>.json |
| Transcript parse | transcript-cache/<sha256>.json |
| Claude Code version | .claude-code-version-cache.json |
| Output speed | .speed-cache.json |
The plugin dir is ~/.claude/plugins/claude-hud/ by default, or
$CLAUDE_CONFIG_DIR/plugins/claude-hud/ when set. All caches are
mtime-keyed and fail open — write failures are non-fatal and read failures
fall back to a fresh compute.
Q: How do I reset the configuration to defaults?
Delete ~/.claude/plugins/claude-hud/config.json. The next prompt will
load DEFAULT_CONFIG and the file isn't recreated automatically.
Q: Can I reorder lines?
Yes — set elementOrder to any permutation of project, context,
usage, memory, environment, tools, agents, todos. Unknown
items are silently dropped; an empty or all-invalid array falls back to
the default order.
Q: Why is Approx RAM missing in compact layout?
It's intentionally suppressed in compact layout. Memory rendering is only
attempted when lineLayout === "expanded" and display.showMemoryUsage
is true. Switch to expanded layout to see it.
Q: Why is the context % different from /context?
It shouldn't be on Claude Code 2.1.6+ — claude-hud uses the native
used_percentage Claude Code emits over stdin so the bar matches /context
exactly. On older Claude Code releases the buffered fallback adds a small
margin (~16.5% of the window, scaled by raw usage) to account for the
autocompact buffer; set display.autocompactBuffer: "disabled" to see the
raw input/cache total instead.
Q: Are there hooks I can plug into?
claude-hud doesn't expose a plugin API. The closest extension point is
--extra-cmd "..." which runs an arbitrary user command (3s timeout,
10KB stdout) and prints the returned label. Anything more sophisticated
requires forking the plugin and adding your own line renderer.
Q: Does it work with non-Anthropic providers (Bedrock, Vertex)?
Partly. The model badge picks up Bedrock model IDs and renders them as
Claude <Family> <Version>. Cost estimation, the usage line, and the
five-hour / weekly windows are intentionally suppressed for Bedrock — those
metrics aren't available from Bedrock's response shape.
Q: How do I switch to Chinese labels?
Set language: "zh" in config.json. Note that the session-tokens line
still leaks English labels in v0.0.12 (issue #448) — leave
showSessionTokens: false if you need fully Chinese output.
Q: Where does 1M context come from?
It's the literal display name Claude Code sends in model.display_name
(e.g. "Opus 4.6 (1M context)"). Set modelFormat: "compact" to strip
the parenthetical, or modelFormat: "short" to also drop the leading
Claude .
Q: Can I show only the weekly window?
Set display.usageThreshold: 0 (default) and display.sevenDayThreshold: 0. Both windows render together by default; the weekly sub-window only
shows once it crosses sevenDayThreshold (default 80). To suppress the
five-hour window entirely, you'd need to fork — there's no config flag for
five-hour-only suppression in v0.0.12.
Q: How do I hide the dirty * next to my git branch?
Set gitStatus.showDirty: false. The branch will still render; only the
dirty marker is suppressed. To hide the entire git block, set
gitStatus.enabled: false.
Q: What happens on a brand-new Claude Code install with no config files?
countConfigs() returns zeros across the board, the environment line
suppresses itself (no totals to show), and the HUD renders only the
elements that have data. There is no first-run wizard.
Q: Where can I see the full source?
github.com/jarrodwatts/claude-hud. The plugin is MIT-licensed.