Building a Custom Claude Code Statusline
Building a Custom Claude Code Statusline
Who This Guide Is For
Software engineers who use build-cli regularly and want richer session information at a glance. You should be comfortable with a terminal and basic shell scripting. No prior experience customising Claude Code is required.
What You Will Learn
- How the Claude Code statusline works (JSON stdin → script → stdout)
- Two approaches: extending the existing bar vs replacing it from scratch
- Key JSON fields your script can consume
- How to install and test a custom statusline script
- How to troubleshoot common statusline issues
Note on the example script: The v1 guide referenced a downloadable
my-statusline.shscript file. That asset file requires a separate decision on how to host it in v2 (this is recorded as an open question for the Plan-04 editorial gate). In the meantime, this guide explains the anatomy of such a script in full so you can build your own.
Step-by-Step Instructions
Step 1: Understand How the Statusline Works
Every time Claude Code refreshes the bar, it pipes a JSON snapshot of the current session to your script on stdin. Your script reads that JSON, formats a line, and prints it. Whatever your script writes to stdout (first line) becomes the statusline.
A few things to know:
- ANSI colors and emoji are supported.
- Updates are debounced (~300 ms) — the script runs after each assistant message, after
/compact, and on a fixed timer if you setrefreshInterval. - If your script exits non-zero or prints nothing, the bar goes blank — fail gracefully.
- Keep it fast; a slow script delays every refresh.
The key JSON fields available to your script:
| Field | What it is |
|---|---|
model.display_name | The active model, e.g. Opus |
workspace.current_dir | Current working directory |
context_window.used_percentage | How full the context window is (0–100) |
cost.total_cost_usd | Estimated cost of the current session |
cost.total_lines_added | Lines of code added this session |
cost.total_lines_removed | Lines of code removed this session |
You can inspect the full payload at any time by piping a mock JSON blob to jq:
echo '{"context_window":{"used_percentage":95}}' | jq .Step 2: Choose Your Approach
Option A — Keep build-cli’s budget bar, just add to it
If you only want to add a small piece of your own information to the existing bar, call build-cli claude statusline from your own script and append your segment:
#!/bin/shmy_segment="my-custom-info"
bcli_out=$(build-cli claude statusline < /dev/null 2>/dev/null)
if [ -n "$bcli_out" ]; then echo "${bcli_out} | ${my_segment}"else echo "${my_segment}"fiThen tell build-cli not to overwrite your configuration on the next setup run:
build-cli config set statusline_disabled trueOption B — Build your own from scratch
Steps 3–4 below cover this approach. It still embeds the build-cli budget bar as one segment.
Step 3: Install Prerequisites
The script needs two common command-line tools:
jq— parses the JSON that Claude Code sendsgit— reads the current repo and branch
# macOS (Homebrew)brew install jq git
# Debian / Ubuntu / WSLsudo apt-get install -y jq gitVerify they are available:
jq --version && git --versionStep 4: Write and Install Your Script
Create your script at ~/.config/my-statusline.sh. A full script reads stdin, parses JSON fields with jq, renders a colored bar with ANSI escape sequences, and assembles the segments with dim | separators.
The key sections to implement:
- Read stdin and parse fields — read the whole JSON payload once, then extract fields with
jqusing// "default"fallbacks for missing data. - Context gauge — render a colored progress bar using 24-bit ANSI colors interpolated from green (empty context) through amber to red (full context).
- Threshold emoji —
🟢(plenty of room),⚡(working),🔥(getting full),🚨(critical). - Build-cli budget segment — call
build-cli claude statuslineand embed the output as a segment; skip cleanly when build-cli isn’t installed. - Cost, velocity, git, model — format
$2.14,+156 -23, repo/branch fromgit -C "$cwd", and🤖 Opus. - Assemble — join segments with dim
|separators, omitting empty segments.
Make the script executable:
chmod +x ~/.config/my-statusline.shStep 5: Point Claude Code at Your Script
First, stop build-cli from overwriting your configuration on future setup runs:
build-cli config set statusline_disabled trueThen edit ~/.claude/settings.json:
{ "statusLine": { "type": "command", "command": "~/.config/my-statusline.sh", "refreshInterval": 360 }}Restart Claude Code (close and reopen). The new bar should appear at the bottom.
Step 6: Test Without Restarting
Because the script reads JSON from stdin, you can feed it a mock payload and see the output immediately:
echo '{ "model": { "display_name": "Opus" }, "workspace": { "current_dir": "'"$PWD"'" }, "context_window": { "used_percentage": 31 }, "cost": { "total_cost_usd": 2.14, "total_lines_added": 156, "total_lines_removed": 23 }}' | ~/.config/my-statusline.shAdjust used_percentage to watch the gradient and emoji change.
Verification
Your custom statusline is working when:
- The test command in Step 6 prints a formatted bar without errors
- After restarting Claude Code, the custom bar appears at the bottom of the session window
build-cli doctorreports the statusline is enabled and the script exists
Next Steps
- See the ‘Installing build-cli’ guide if you haven’t set up build-cli yet
- See the ‘Your First Session with build-cli’ guide to get productive with build-cli
- Official docs: build-cli Statusline and Usage Tracking
Troubleshooting
The bar is blank. Your script exited non-zero or printed nothing. Run the test command in Step 6 directly to see the error. Make sure jq is installed and the script is executable.
build-cli claude setup overwrote my custom statusline. Run build-cli config set statusline_disabled true so setup leaves your ~/.claude/settings.json entry alone, then re-point it at your script.
The budget segment is missing. build-cli wasn’t found on your PATH, or you’re not logged in. Confirm with build-cli claude statusline < /dev/null. This segment is optional — the rest of the bar works without it.
Something’s off and I’m not sure what. Run build-cli doctor — it checks whether the statusline is enabled, whether the script exists, and whether ~/.claude/settings.json has a valid statusLine entry.
I want the default budget bar back. Run build-cli config set statusline_disabled false then build-cli claude setup to restore the defaults.