Port the entire 2236-line bash statusline script to Rust. Implements all 25 sections, 3-phase layout engine (render, priority drop, flex/justify), file-based caching with flock, 9-level terminal width detection, trend sparklines, and deep-merge JSON config. Release binary: 864K with LTO. Render time: <1ms warm. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
802 lines
20 KiB
Markdown
802 lines
20 KiB
Markdown
# claude-statusline
|
|
|
|
A configurable, multi-line status line for Claude Code with priority-based flex layout, VCS auto-detection (git/jj), spacer-based positioning, custom command sections, and per-section formatting.
|
|
|
|
```
|
|
[Opus] | Anthropic | gitlore master* +1-0
|
|
[============----] 58% | $0.12 | +156 -23 | 14m | 7 tools (Edit)
|
|
```
|
|
|
|
## Quick Start
|
|
|
|
### Prerequisites
|
|
|
|
- **bash 4+** (macOS ships bash 3 — `brew install bash`)
|
|
- **jq** (`brew install jq` / `apt install jq`)
|
|
- **Claude Code** with status line support
|
|
|
|
### Install
|
|
|
|
```bash
|
|
git clone https://github.com/tayloreernisse/claude-statusline ~/projects/claude-statusline
|
|
cd ~/projects/claude-statusline
|
|
./install.sh
|
|
```
|
|
|
|
The installer creates two symlinks:
|
|
|
|
```
|
|
~/.claude/statusline.sh -> ~/projects/claude-statusline/statusline.sh
|
|
~/.claude/statusline.json -> ~/projects/claude-statusline/statusline.json
|
|
```
|
|
|
|
### Configure Claude Code
|
|
|
|
Add to `~/.claude/settings.json`:
|
|
|
|
```json
|
|
{
|
|
"statusLine": "~/.claude/statusline.sh"
|
|
}
|
|
```
|
|
|
|
Restart Claude Code to see the status line.
|
|
|
|
## How It Works
|
|
|
|
```
|
|
Claude Code (every ~300ms)
|
|
|
|
|
| pipes JSON to stdin
|
|
v
|
|
statusline.sh
|
|
|
|
|
+-- reads ~/.claude/statusline.json (config)
|
|
+-- parses stdin JSON (model, cost, context, etc.)
|
|
+-- caches expensive ops (VCS, beads, system load)
|
|
+-- resolves layout (preset or custom array)
|
|
+-- renders sections with ANSI colors
|
|
+-- applies priority-based flex layout
|
|
|
|
|
| stdout (ANSI-colored lines)
|
|
v
|
|
Claude Code renders status bar
|
|
```
|
|
|
|
The stdin JSON from Claude Code contains:
|
|
- `model` — current model info (id, display name)
|
|
- `cost` — accumulated cost, duration, lines changed, tool uses
|
|
- `context_window` — token counts, used percentage, cache stats
|
|
- `workspace` — project directory
|
|
- `version` — Claude Code version
|
|
- `output_style` — current output style
|
|
|
|
## Configuration Reference
|
|
|
|
Config lives at `~/.claude/statusline.json` (or set `CLAUDE_STATUSLINE_CONFIG` env var).
|
|
|
|
### Global Options
|
|
|
|
```json
|
|
{
|
|
"global": {
|
|
"separator": " | ",
|
|
"justify": "left",
|
|
"vcs": "auto",
|
|
"width_margin": 4,
|
|
"cache_dir": "/tmp/claude-sl-{session_id}"
|
|
}
|
|
}
|
|
```
|
|
|
|
| Option | Default | Description |
|
|
|--------|---------|-------------|
|
|
| `separator` | `" \| "` | Text between sections. In `left` mode, used as-is. In `spread`/`space-between`, the non-space characters (e.g. `\|`) stay as visual anchors with extra padding around them. |
|
|
| `justify` | `"left"` | How sections distribute across terminal width. See [Justify Modes](#justify-modes). |
|
|
| `width` | (auto) | Explicit terminal width in columns. If omitted, auto-detection walks the process tree to find an ancestor with a real TTY, falling back to `stty` via `/dev/tty`, `COLUMNS`, `tput cols`, or 120. |
|
|
| `width_margin` | `4` | Columns to subtract from the detected width. Accounts for terminal multiplexer borders (Zellij/tmux) or Claude Code UI chrome that reduce the actual visible area. |
|
|
| `vcs` | `"auto"` | VCS detection: `auto`, `git`, `jj`, `none` |
|
|
| `cache_dir` | `/tmp/claude-sl-{session_id}` | Cache directory template. `{session_id}` is replaced at runtime. |
|
|
|
|
### Layout System
|
|
|
|
The `layout` field controls which sections appear and on which lines.
|
|
|
|
**Using a preset:**
|
|
```json
|
|
{ "layout": "standard" }
|
|
```
|
|
|
|
**Using a custom layout:**
|
|
```json
|
|
{
|
|
"layout": [
|
|
["model", "provider", "project", "spacer", "vcs"],
|
|
["context_bar", "cost", "duration"]
|
|
]
|
|
}
|
|
```
|
|
|
|
Each inner array is one line. Section IDs in the array are rendered left-to-right, separated by the global separator.
|
|
|
|
### Spacer Sections
|
|
|
|
Use `spacer` (or `_spacer1`, `_spacer2`, etc. for multiple spacers) as a virtual section that expands to fill remaining width. This pushes sections apart without using `justify: "spread"`.
|
|
|
|
```json
|
|
{
|
|
"layout": [
|
|
["model", "provider", "spacer", "vcs"]
|
|
]
|
|
}
|
|
```
|
|
|
|
Output (80 columns):
|
|
```
|
|
[Opus] | Anthropic master* +1-0
|
|
```
|
|
|
|
Spacers have `flex: true` by default and suppress the separator on adjacent sides. Use multiple unique spacer IDs (`_spacer1`, `_spacer2`) if you need more than one on a line.
|
|
|
|
### Built-in Presets
|
|
|
|
**standard** (2 lines):
|
|
```
|
|
Line 1: model | provider | project | spacer | vcs
|
|
Line 2: context_bar | cost | lines_changed | duration | tools
|
|
```
|
|
|
|
**dense** (1 line):
|
|
```
|
|
Line 1: model | provider | project | vcs | context_bar | cost | duration
|
|
```
|
|
|
|
**verbose** (3 lines):
|
|
```
|
|
Line 1: model | provider | project | vcs | beads
|
|
Line 2: context_bar | tokens_raw | cache_efficiency | cost | cost_velocity
|
|
Line 3: lines_changed | duration | tools | turns | load | version
|
|
```
|
|
|
|
You can define custom presets in the `presets` object and reference them by name.
|
|
|
|
### Section Configuration
|
|
|
|
Each section supports these common properties:
|
|
|
|
```json
|
|
{
|
|
"enabled": true,
|
|
"priority": 1,
|
|
"flex": false,
|
|
"min_width": 0,
|
|
"prefix": "",
|
|
"suffix": "",
|
|
"pad": 0,
|
|
"align": "left",
|
|
"color": "dim"
|
|
}
|
|
```
|
|
|
|
| Property | Type | Description |
|
|
|----------|------|-------------|
|
|
| `enabled` | boolean | Whether the section renders at all |
|
|
| `priority` | 1/2/3 | Display priority (see Flex Layout below) |
|
|
| `flex` | boolean | Whether section expands to fill remaining width |
|
|
| `min_width` | integer | Minimum character width |
|
|
| `prefix` | string | Text prepended to section output |
|
|
| `suffix` | string | Text appended to section output |
|
|
| `pad` | integer | Pad output to this minimum width |
|
|
| `align` | `left`/`right`/`center` | Alignment within padded width |
|
|
| `color` | color name | Override the section's color (see [Color Names](#color-names))
|
|
|
|
### Per-Section Formatting Examples
|
|
|
|
**Add brackets around the project name:**
|
|
```json
|
|
{
|
|
"sections": {
|
|
"project": { "prefix": "[", "suffix": "]" }
|
|
}
|
|
}
|
|
```
|
|
Output: `[myproject]`
|
|
|
|
**Right-align cost in a fixed-width column:**
|
|
```json
|
|
{
|
|
"sections": {
|
|
"cost": { "pad": 8, "align": "right" }
|
|
}
|
|
}
|
|
```
|
|
Output: ` $0.12` (padded to 8 chars)
|
|
|
|
**Override a section's default color:**
|
|
```json
|
|
{
|
|
"sections": {
|
|
"duration": { "color": "cyan" }
|
|
}
|
|
}
|
|
```
|
|
|
|
## Flex Layout Deep Dive
|
|
|
|
### Priority Drop
|
|
|
|
When a line is wider than the terminal:
|
|
|
|
1. Drop `priority: 3` sections, right-to-left
|
|
2. Still too wide? Drop `priority: 2`, right-to-left
|
|
3. `priority: 1` sections never drop
|
|
|
|
**Example at 120 columns** (everything fits):
|
|
```
|
|
[Opus] | Anthropic | gitlore | master* | [======----] 58% | $0.12 | +156 -23 | 14m | 7 tools
|
|
```
|
|
|
|
**Same content at 80 columns** (priority 3 dropped, priority 2 trimmed):
|
|
```
|
|
[Opus] | gitlore | master* | [======----] 58% | $0.12
|
|
```
|
|
|
|
### Flex Expansion
|
|
|
|
If a section has `flex: true` and there's remaining width after rendering all sections, the flex section expands to fill the gap. For `context_bar`, this means a wider progress bar. For spacers, they expand to push adjacent sections apart. For other sections, it pads with spaces.
|
|
|
|
One flex section per line wins. Spacers take priority over non-spacer flex sections.
|
|
|
|
**80 columns with flex context_bar:**
|
|
```
|
|
[Opus] | gitlore | master* | [================----] 58% | $0.12
|
|
```
|
|
|
|
**80 columns with spacer (pushes VCS to right):**
|
|
```
|
|
[Opus] | gitlore master* +1-0
|
|
```
|
|
|
|
### Justify Modes
|
|
|
|
The `global.justify` setting controls how sections distribute across the full terminal width. This is independent of priority drop — sections are dropped first if needed, then the remaining sections are distributed.
|
|
|
|
**`"left"` (default)** — Pack sections left with fixed-width separators. Use `flex: true` on a section to fill remaining space.
|
|
```
|
|
[Opus] | Anthropic | gitlore | master*
|
|
```
|
|
|
|
**`"spread"`** — Distribute extra space evenly into all gaps. The separator's visible characters (e.g. `|`) stay as anchors, padded with spaces on both sides. Every line fills the full terminal width.
|
|
```
|
|
[Opus] | Anthropic | gitlore | master*
|
|
```
|
|
|
|
**`"space-between"`** — Same distribution as `spread` for terminal output (first section starts at column 0, last section ends at the terminal edge).
|
|
|
|
When justify is `"spread"` or `"space-between"`, the `flex` property on individual sections is ignored — the entire line spreads instead of one section expanding.
|
|
|
|
The separator character still matters: `" | "` produces gaps like ` | `, while `" :: "` produces ` :: `, and `" "` (pure spaces) produces invisible gaps.
|
|
|
|
## Section Reference
|
|
|
|
### model
|
|
**Source:** stdin JSON `model.display_name` or parsed from `model.id`
|
|
|
|
Shows the current model name in bold brackets. Falls back to parsing "Opus"/"Sonnet"/"Haiku" from the model ID.
|
|
|
|
```
|
|
[Opus]
|
|
```
|
|
|
|
### provider
|
|
**Source:** pattern match on `model.id`
|
|
|
|
Detects the API provider from the model identifier.
|
|
|
|
| Pattern | Provider |
|
|
|---------|----------|
|
|
| `us.anthropic.*`, `anthropic.*` | Bedrock |
|
|
| `*@YYYYMMDD` | Vertex |
|
|
| `claude-*` | Anthropic |
|
|
|
|
Empty if provider can't be determined.
|
|
|
|
### project
|
|
**Source:** `basename` of `workspace.project_dir`
|
|
|
|
Shows the current project directory name.
|
|
|
|
### vcs
|
|
**Source:** git/jj CLI (cached)
|
|
|
|
Auto-detects VCS by checking for `.jj/` first, then `.git/`. Override with `vcs.prefer`.
|
|
|
|
```json
|
|
{
|
|
"vcs": {
|
|
"prefer": "auto",
|
|
"show_ahead_behind": true,
|
|
"show_dirty": true,
|
|
"ttl": { "branch": 3, "dirty": 5, "ahead_behind": 30 }
|
|
}
|
|
}
|
|
```
|
|
|
|
**git output:** `master* +1-0` (branch, dirty indicator, ahead/behind)
|
|
|
|
**jj output:** `feature-branch*` (bookmark or short change ID, dirty indicator)
|
|
|
|
Each piece has its own cache TTL — branch name barely changes, dirty status changes often, ahead/behind is expensive.
|
|
|
|
### beads
|
|
**Source:** `br` CLI (cached)
|
|
|
|
Shows current in-progress bead and ready count. Requires `br` to be installed.
|
|
|
|
```json
|
|
{
|
|
"beads": {
|
|
"show_wip": true,
|
|
"show_ready_count": true,
|
|
"ttl": 30
|
|
}
|
|
}
|
|
```
|
|
|
|
```
|
|
br-47 wip | 3 ready
|
|
```
|
|
|
|
### context_bar
|
|
**Source:** `context_window.used_percentage`
|
|
|
|
Visual progress bar of context window usage with color thresholds.
|
|
|
|
```json
|
|
{
|
|
"context_bar": {
|
|
"flex": true,
|
|
"bar_width": 10,
|
|
"thresholds": { "warn": 50, "danger": 70, "critical": 85 }
|
|
}
|
|
}
|
|
```
|
|
|
|
| Range | Color |
|
|
|-------|-------|
|
|
| 0-49% | Green |
|
|
| 50-69% | Yellow |
|
|
| 70-84% | Red |
|
|
| 85%+ | Bold Red |
|
|
|
|
### context_usage
|
|
**Source:** `context_window.total_input_tokens`, `total_output_tokens`, `max_tokens`, `used_percentage`
|
|
|
|
Shows context usage as "used/total" (e.g., `125k/200k`). The "used" part is colored based on thresholds, while "total" is always dim.
|
|
|
|
```json
|
|
{
|
|
"context_usage": {
|
|
"enabled": true,
|
|
"thresholds": { "warn": 50, "danger": 70, "critical": 85 }
|
|
}
|
|
}
|
|
```
|
|
|
|
Output: `125k/200k` (green when below 50%, yellow 50-69%, red 70-84%, bold red 85%+)
|
|
|
|
If `max_tokens` is not provided in the input, it's calculated from the percentage.
|
|
|
|
### tokens_raw
|
|
**Source:** `context_window.total_input_tokens`, `total_output_tokens`
|
|
|
|
Raw token counts in human-readable format.
|
|
|
|
```json
|
|
{ "tokens_raw": { "format": "{input}in/{output}out" } }
|
|
```
|
|
|
|
```
|
|
115kin/8.5kout
|
|
```
|
|
|
|
### cache_efficiency
|
|
**Source:** `cache_read_input_tokens`, `cache_creation_input_tokens`
|
|
|
|
Percentage of cache reads vs total cache operations.
|
|
|
|
```
|
|
cache:33%
|
|
```
|
|
|
|
### cost
|
|
**Source:** `cost.total_cost_usd`
|
|
|
|
Accumulated session cost with color thresholds.
|
|
|
|
```json
|
|
{
|
|
"cost": {
|
|
"thresholds": { "warn": 0.25, "danger": 0.50, "critical": 1.00 }
|
|
}
|
|
}
|
|
```
|
|
|
|
### cost_velocity
|
|
**Source:** cost / duration
|
|
|
|
Cost per minute of session time.
|
|
|
|
```
|
|
$0.08/m
|
|
```
|
|
|
|
### token_velocity
|
|
**Source:** tokens / duration
|
|
|
|
Total tokens (input + output) consumed per minute. Useful for understanding how fast you're burning through context.
|
|
|
|
```
|
|
14.5ktok/m
|
|
```
|
|
|
|
In narrow terminals, abbreviated to `14.5kt/m`.
|
|
|
|
### lines_changed
|
|
**Source:** `cost.total_lines_added`, `total_lines_removed`
|
|
|
|
```
|
|
+156 -23
|
|
```
|
|
|
|
Green for additions, red for removals.
|
|
|
|
### duration
|
|
**Source:** `cost.total_duration_ms`
|
|
|
|
Human-readable session duration: `14m`, `1h23m`, `45s`.
|
|
|
|
### tools
|
|
**Source:** `cost.total_tool_uses`, `cost.last_tool_name`
|
|
|
|
```json
|
|
{
|
|
"tools": {
|
|
"show_last_name": true,
|
|
"ttl": 2
|
|
}
|
|
}
|
|
```
|
|
|
|
```
|
|
7 tools (Edit)
|
|
```
|
|
|
|
### turns
|
|
**Source:** `cost.total_turns`
|
|
|
|
```
|
|
12 turns
|
|
```
|
|
|
|
### load
|
|
**Source:** system load average (macOS: `sysctl`, Linux: `/proc/loadavg`)
|
|
|
|
```json
|
|
{ "load": { "ttl": 10 } }
|
|
```
|
|
|
|
```
|
|
load:2.1
|
|
```
|
|
|
|
### version
|
|
**Source:** `version` from stdin JSON
|
|
|
|
```
|
|
v1.0.80
|
|
```
|
|
|
|
### time
|
|
**Source:** `date` command
|
|
|
|
```json
|
|
{ "time": { "format": "%H:%M" } }
|
|
```
|
|
|
|
### output_style
|
|
**Source:** `output_style.name`
|
|
|
|
Shows the current Claude Code output style (e.g., "learning", "concise").
|
|
|
|
### hostname
|
|
**Source:** `hostname -s`
|
|
|
|
Short hostname of the machine.
|
|
|
|
## Custom Commands
|
|
|
|
Add custom sections that execute shell commands and display the result.
|
|
|
|
```json
|
|
{
|
|
"custom": [
|
|
{
|
|
"id": "ollama",
|
|
"label": "ollama",
|
|
"command": "pgrep -x ollama >/dev/null && echo 'up' || echo 'down'",
|
|
"ttl": 30,
|
|
"priority": 3,
|
|
"color": {
|
|
"match": { "up": "green", "down": "dim" }
|
|
}
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
Then reference by `id` in any layout line:
|
|
|
|
```json
|
|
{ "layout": [["model", "project", "ollama"]] }
|
|
```
|
|
|
|
### Custom Command Fields
|
|
|
|
| Field | Required | Default | Description |
|
|
|-------|----------|---------|-------------|
|
|
| `id` | yes | — | Unique identifier, used in layout arrays |
|
|
| `label` | no | same as `id` | Display prefix before the value |
|
|
| `command` | yes | — | Shell command. stdout is captured. |
|
|
| `ttl` | no | 30 | Cache TTL in seconds |
|
|
| `priority` | no | 2 | Display priority (1/2/3) |
|
|
| `flex` | no | false | Expand to fill remaining width |
|
|
| `min_width` | no | 4 | Minimum character width |
|
|
| `color.match` | no | — | Map output values to color names |
|
|
| `default_color` | no | — | Fallback color when `color.match` doesn't match |
|
|
| `prefix` | no | — | Text prepended to output |
|
|
| `suffix` | no | — | Text appended to output |
|
|
| `pad` | no | — | Pad output to this minimum width |
|
|
| `align` | no | `left` | Alignment within padded width (`left`/`right`/`center`) |
|
|
|
|
### Color Names
|
|
|
|
Available colors: `red`, `green`, `yellow`, `blue`, `magenta`, `cyan`, `white`, `dim`, `bold`.
|
|
|
|
These work in three places:
|
|
- `sections.<name>.color` — override a built-in section's color
|
|
- `custom[].color.match` — map output values to colors
|
|
- `custom[].default_color` — default color for custom commands (use instead of `color` to avoid conflict with `color.match`)
|
|
|
|
### Recipe Ideas
|
|
|
|
**Dev server status:**
|
|
```json
|
|
{
|
|
"id": "devserver",
|
|
"command": "curl -so /dev/null http://localhost:3000 && echo 'up' || echo 'down'",
|
|
"ttl": 10,
|
|
"priority": 3,
|
|
"color": { "match": { "up": "green", "down": "red" } }
|
|
}
|
|
```
|
|
|
|
**Disk usage:**
|
|
```json
|
|
{
|
|
"id": "disk",
|
|
"label": "disk",
|
|
"command": "df -h / | awk 'NR==2{print $5}'",
|
|
"ttl": 120,
|
|
"priority": 3
|
|
}
|
|
```
|
|
|
|
**CI status (via gh):**
|
|
```json
|
|
{
|
|
"id": "ci",
|
|
"label": "CI",
|
|
"command": "gh run list --limit 1 --json conclusion -q '.[0].conclusion' 2>/dev/null || echo '?'",
|
|
"ttl": 60,
|
|
"priority": 3,
|
|
"color": { "match": { "success": "green", "failure": "red", "?": "dim" } }
|
|
}
|
|
```
|
|
|
|
**Ollama status:**
|
|
```json
|
|
{
|
|
"id": "ollama",
|
|
"label": "ollama",
|
|
"command": "pgrep -x ollama >/dev/null && echo 'up' || echo 'down'",
|
|
"ttl": 30,
|
|
"priority": 3,
|
|
"color": { "match": { "up": "green", "down": "dim" } }
|
|
}
|
|
```
|
|
|
|
**Docker status:**
|
|
```json
|
|
{
|
|
"id": "docker",
|
|
"label": "docker",
|
|
"command": "docker info >/dev/null 2>&1 && echo 'up' || echo 'down'",
|
|
"ttl": 60,
|
|
"priority": 3,
|
|
"color": { "match": { "up": "green", "down": "dim" } }
|
|
}
|
|
```
|
|
|
|
## Caching
|
|
|
|
Expensive operations (VCS commands, beads queries, custom commands, system load) are cached in files under the cache directory.
|
|
|
|
### How It Works
|
|
|
|
1. Each cached value has a key (e.g., `vcs_branch`) and a TTL in seconds
|
|
2. On first call, the command runs and its stdout is written to `$CACHE_DIR/$key`
|
|
3. On subsequent calls within the TTL, the cached file is read instead
|
|
4. After TTL expires, the command runs again
|
|
|
|
### Cache Location
|
|
|
|
Default: `/tmp/claude-sl-{session_id}/`
|
|
|
|
The `{session_id}` template variable is replaced with the script's PID. Configure via `global.cache_dir`.
|
|
|
|
### TTLs by Section
|
|
|
|
| Section | Key | Default TTL |
|
|
|---------|-----|-------------|
|
|
| vcs (branch) | `vcs_branch` | 3s |
|
|
| vcs (dirty) | `vcs_dirty` | 5s |
|
|
| vcs (ahead/behind) | `vcs_ab` | 30s |
|
|
| beads (wip) | `beads_wip` | 30s |
|
|
| beads (ready) | `beads_ready` | 30s |
|
|
| load | `load` | 10s |
|
|
| custom commands | `custom_{id}` | per-command `ttl` |
|
|
|
|
## Troubleshooting
|
|
|
|
### Script doesn't run
|
|
|
|
- Check the shebang: `head -1 ~/.claude/statusline.sh` should be `#!/usr/bin/env bash`
|
|
- Verify it's executable: `ls -la ~/.claude/statusline.sh` (should show `-rwxr-xr-x`)
|
|
- Fix: `chmod +x ~/.claude/statusline.sh`
|
|
- Verify jq is installed: `which jq`
|
|
- Test manually: `echo '{}' | ~/.claude/statusline.sh`
|
|
|
|
### No output / blank status line
|
|
|
|
- Test with mock data: `echo '{"model":{"id":"claude-opus-4-5-20251101","display_name":"Opus"},"cost":{"total_cost_usd":0.05}}' | ~/.claude/statusline.sh`
|
|
- Check config is valid JSON: `jq . ~/.claude/statusline.json`
|
|
- Check symlinks: `ls -la ~/.claude/statusline.sh ~/.claude/statusline.json`
|
|
|
|
### Stale data
|
|
|
|
- VCS branch stuck? TTL is 3s by default. Increase: `sections.vcs.ttl.branch`
|
|
- Clear cache: `rm -rf /tmp/claude-sl-*/`
|
|
|
|
### Performance
|
|
|
|
The script runs every ~300ms. Most sections are free (parsed from stdin JSON). Expensive sections:
|
|
|
|
| Section | Cost | Mitigation |
|
|
|---------|------|-----------|
|
|
| vcs | git/jj subprocess | Cached with per-field TTLs |
|
|
| beads | br subprocess | 30s TTL |
|
|
| load | sysctl/proc read | 10s TTL |
|
|
| custom | arbitrary command | User-configured TTL |
|
|
|
|
If status line feels sluggish, increase TTLs or disable expensive sections.
|
|
|
|
## Provider Detection
|
|
|
|
The `provider` section detects the API provider from the model ID:
|
|
|
|
| Model ID Pattern | Detected Provider |
|
|
|-----------------|-------------------|
|
|
| `us.anthropic.claude-*` | Bedrock |
|
|
| `anthropic.claude-*` | Bedrock |
|
|
| `claude-*-*@20251101` | Vertex |
|
|
| `claude-opus-4-5-20251101` | Anthropic (direct) |
|
|
|
|
Detection is pure pattern matching on `model.id` — no credentials or API calls involved.
|
|
|
|
## Config Validation
|
|
|
|
A JSON Schema is provided at `schema.json` for editor autocomplete and validation.
|
|
|
|
**VSCode:** Add to your `statusline.json`:
|
|
```json
|
|
{
|
|
"$schema": "./schema.json",
|
|
"version": 1
|
|
}
|
|
```
|
|
|
|
**CLI validation (with ajv):**
|
|
```bash
|
|
npx ajv validate -s schema.json -d statusline.json
|
|
```
|
|
|
|
## Terminal Width Detection
|
|
|
|
Claude Code runs the status line script without a TTY, which makes detecting the terminal width non-trivial. The detection priority is:
|
|
|
|
1. **`global.width`** in config — explicit override
|
|
2. **`CLAUDE_STATUSLINE_WIDTH`** env var
|
|
3. **Process tree walk** — finds an ancestor process with a real TTY and runs `stty size` on it
|
|
4. **`stty size < /dev/tty`** — works on some systems
|
|
5. **`COLUMNS`** env var
|
|
6. **`tput cols`**
|
|
7. **Fallback: 120**
|
|
|
|
After detection, `global.width_margin` (default: 4) is subtracted to account for terminal multiplexer borders or UI chrome.
|
|
|
|
## Environment Variables
|
|
|
|
| Variable | Description |
|
|
|----------|-------------|
|
|
| `CLAUDE_STATUSLINE_CONFIG` | Override config file path |
|
|
| `CLAUDE_STATUSLINE_WIDTH` | Override terminal width (second priority after `global.width`) |
|
|
| `COLUMNS` | Standard terminal width (lower priority) |
|
|
|
|
## CLI Flags
|
|
|
|
The script supports several flags for development and debugging:
|
|
|
|
```bash
|
|
# Test your config with mock data (no Claude Code needed)
|
|
./statusline.sh --test
|
|
|
|
# Get path to JSON schema for IDE autocomplete
|
|
./statusline.sh --config-schema
|
|
|
|
# Debug internal state (width detection, theme, VCS, etc.)
|
|
./statusline.sh --dump-state
|
|
|
|
# Show help
|
|
./statusline.sh --help
|
|
```
|
|
|
|
### --test Mode
|
|
|
|
Renders the status line with realistic mock data. Useful for:
|
|
- Validating config changes without restarting Claude Code
|
|
- Rapid iteration on layout and colors
|
|
- Debugging section visibility
|
|
|
|
### --dump-state Mode
|
|
|
|
Outputs internal computed state as JSON:
|
|
```json
|
|
{
|
|
"terminal": {"detected_width": 178, "effective_width": 174, "width_tier": "wide"},
|
|
"responsive": {"enabled": true, "layout": "verbose"},
|
|
"theme": "dark",
|
|
"vcs": "git",
|
|
"paths": {"config": "~/.claude/statusline.json", "cache_dir": "/tmp/claude-sl-abc123"}
|
|
}
|
|
```
|
|
|
|
## Examples
|
|
|
|
The `examples/` directory contains ready-to-use configurations:
|
|
|
|
| File | Description |
|
|
|------|-------------|
|
|
| `dense.json` | Single-line layout with compact context bar |
|
|
| `verbose.json` | Three-line layout with all metrics |
|
|
| `custom-commands.json` | Custom Ollama and Docker status indicators |
|
|
|
|
Copy an example to your config:
|
|
```bash
|
|
cp examples/verbose.json ~/.claude/statusline.json
|
|
```
|
|
|
|
## License
|
|
|
|
MIT
|