Jesse A. Green / notebook

Live demo: the DocCompiler guide library as a static, read-only snapshot (October 2026). No backend, no accounts, nothing to submit.

claude-hud User Guide

Generated April 2026 from jarrodwatts/claude-hud at 64a8099

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

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-hud is a Claude Code plugin. It is NOT published to npm. Trying to run npm install -g claude-hud will fail with a 404 from the registry. The only supported distribution channel is the Claude Code plugin marketplace.

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:

  1. /plugin marketplace add jarrodwatts/claude-hud — registers the GitHub repo as a marketplace source for your local Claude Code.
  2. /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/ if CLAUDE_CONFIG_DIR is set).
  3. /claude-hud:setup — writes the statusline wiring into your user settings.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 statusLine entry from settings.json, Claude Code will try to spawn a missing binary on every prompt and silently render an empty statusline. Always edit settings.json after /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 Weekly label.

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.md found in user scope (under ~/.claude/ or $CLAUDE_CONFIG_DIR) and project scope (under the cwd Claude Code reports).
  • Rules count — every *.md file 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 in disabledMcpServers / disabledMcpjsonServers. User and project scopes are counted separately — a server named git in both scopes counts as 2.
  • Hooks count — Object.keys(config.hooks).length summed across user and project settings.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-cmd someone 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-tokens line still emits English labels (tok:/in:/out:/cache:) when language: "zh". If full Chinese coverage matters, leave showSessionTokens off 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

  1. Nothing appears in the statusline at all. Check ~/.claude/settings.json has a statusLine entry. Re-run /claude-hud:setup if it's missing.
  2. Statusline text is blank but Claude Code is otherwise fine. Set DEBUG=claude-hud in your environment and run a smoke test with npm run test:stdin from the plugin directory. Check stderr for [claude-hud:*] messages.
  3. HUD wraps onto many lines or shows odd widths. See "Status line wraps to multiple lines" below — likely the terminal-width fallback is firing.
  4. 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:

  1. Run setup again — newer setup scripts can inject a COLUMNS=$(tput cols) prefix into the statusline command.
  2. Manually edit ~/.claude/settings.json and prepend COLUMNS=$(tput cols) to the statusLine.command value.
  3. 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 in settings.json).
  • [claude-hud:context] — when autocompactBuffer: disabled is active, shows the raw vs buffered percent.
  • [claude-hud:extra-cmd] — --extra-cmd parse / 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-hud in 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.