# claude-hud User Guide

`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:

```text
/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):

```text
[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

```bash
claude --version
```

```text
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.

### Method 1 — Marketplace install (recommended)

This is the only path the maintainer publishes. From a Claude Code session:

```text
/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:

```bash
ls -la ~/.claude/plugins/claude-hud/dist/index.js
```

```text
-rw-r--r--  1 you  staff  ...  index.js
```

If you've set `CLAUDE_CONFIG_DIR` to a non-default location, swap the path:

```bash
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:

```text
/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:

```text
/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:

```bash
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
```

```text
[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:

```text
~/.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

```json
{
  "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`:

```text
[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 ` | `:

```text
[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`:

```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)

```json
{
  "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)

```json
{
  "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)

```json
{
  "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

```json
{
  "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

```json
{
  "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)

```json
{
  "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

```json
{
  "language": "zh"
}
```

### Recipe — Disabled autocompact buffer (raw context %)

```json
{
  "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

```json
{
  "display": {
    "customLine": "ENV=staging"
  }
}
```

Limited to 80 characters. Anything longer is truncated by `mergeConfig()`.

### Recipe — Run a custom probe via --extra-cmd

```json
{
  "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](https://github.com/jarrodwatts/claude-hud).
The plugin is MIT-licensed.

---

_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. Unofficial; not affiliated with or reviewed by the project._
