The Claude Code Statusline I Actually Read (and the Fields I Deleted)
A config field log: the exact Claude Code statusline I run in 2026, the four fields that earn their place, the ones I deleted, and why the bar sometimes shows up empty.

On this page
Quick Answer
A Claude Code statusline is a shell script you point to from the statusLine field in ~/.claude/settings.json. Claude Code pipes JSON session data to it on stdin after every assistant message and prints whatever the script returns as a persistent bar at the bottom of the terminal. As of July 2026 the field actually worth showing is context-window usage (context_window.used_percentage), not session cost. Below is the config I have run for months, field by field, what I turned off, and the three reasons the bar sometimes shows up empty.
I ignored the statusline for my first few months in Claude Code. It looked like terminal jewelry. Then I lost a long session to a
/compact I did not see coming, watched the model quietly forget a decision we had settled forty messages earlier, and realized the one number that would have warned me had been available the whole time. I just was not displaying it. So this is a config deep dive, not a showcase. Here is the exact setup, why each field survived, and the reasons the bar goes blank.
The config, minus the ceremony
The whole thing is two parts: a statusLine block in settings and a script.
// ~/.claude/settings.json
{
"statusLine": {
"type": "command",
"command": "~/.claude/statusline.sh",
"padding": 2
}
}
type is always "command". command is a path to a script or an inline shell command. padding (default 0) adds horizontal indent, nothing more. There is also an optional refreshInterval (minimum 1 second) for when you show a clock or a value that changes while the session sits idle. I leave it unset because the event-driven updates are enough. The official statusline docs spell out the full stdin JSON schema if you want every available field.
Claude Code runs the script after each new assistant message, after /compact finishes, when the permission mode changes, and when vim mode toggles, all debounced at 300ms. If an update fires while your script is still running, the in-flight run is cancelled, so keep the script cheap. Do not shell out to anything slow.
If you would rather not hand-write it, /statusline takes plain-English instructions and generates the script plus the settings entry for you. I started there, then trimmed it down, the same way I trimmed the handful of commands I actually kept.
My script reads the JSON once and prints one line:
#!/usr/bin/env bash
input=$(cat)
model=$(echo "$input" | jq -r '.model.display_name')
ctx=$(echo "$input" | jq -r '.context_window.used_percentage // 0')
dir=$(echo "$input" | jq -r '.workspace.current_dir' | xargs basename)
branch=$(git -C "$(echo "$input" | jq -r '.cwd')" branch --show-current 2>/dev/null)
printf '%s %s%%ctx %s' "$model" "$ctx" "$dir"
[ -n "$branch" ] && printf ' (%s)' "$branch"
Four fields. Everything below is the argument for why those four and not the dozen the plugins ship with.
What each field earned its place
Context usage (context_window.used_percentage). This is the only field I would call non-negotiable. It predicts when the model starts dropping earlier context and when a /compact is about to reshape the session. Watching it climb past 70 percent changes what I do next: I stop feeding it new files and start closing the loop. Everything else on the bar is nice to have. This one is load-bearing.
Model (model.display_name). I run more than one model in a day and they are not interchangeable for the task in front of me. Showing the display name means I never send a throwaway refactor to the expensive model, or a delicate migration to the cheap one, by accident. Cheap insurance.
Directory (workspace.current_dir). I keep several worktrees open at once. The basename of the working dir is the fastest way to answer "which checkout am I actually in" before I run something destructive. The full path is on cwd if you prefer it.
Git branch. Not from the JSON, from
git branch --show-current. The statusline is already running a script, so reading the branch is free, and "which branch is this session on" is the second question after "which directory." I gate it with 2>/dev/null so non-repo directories print nothing instead of an error.
What I deleted
Session cost (cost.total_cost_usd). I ran it for a week. The number is estimated client-side and, as the docs say plainly, may differ from your actual bill. As a live figure it did nothing but make me anxious mid-task, and it never once changed a decision. When I want real spend I open the dashboard, not a bar that ticks every message. Gone.
Lines added and removed (cost.total_lines_added, cost.total_lines_removed). A vanity metric. git diff --stat tells me the same thing at the one moment I care, which is review time, not continuously. Cut.
Duration (cost.total_duration_ms). A running session timer is a distraction dressed up as productivity. Cut.
Emoji and heavy color. Early on I color-coded everything with ANSI codes (\033[32m and friends, which the terminal has to support). A bar that is all color carries no signal. I kept exactly one threshold: the context percentage turns amber past 70 and red past 90. The rest stays plain. Signal comes from contrast, and you only get contrast if most of the bar is quiet. This is the same instinct behind most of what I do here: the setup gets better when things come off it, not on.
When "claude code statusline not showing" bites
This is a top related search for a reason. Three causes cover almost every case I have hit or been asked about:
- The script is not executable, or the path is wrong. An inline
commandruns without a chmod, but a script path needschmod +x ~/.claude/statusline.shand an absolute or~-anchored path. A relative path resolved from the wrong directory prints nothing. jqis not installed. Most example scripts, mine included, pipe throughjq. If it is missing, every field expands to empty and you get a blank or half-blank bar with no error at all. Runjq --versionfirst.- You edited the script and expected it live. Edits do not appear until the next interaction triggers an update, so send a message. And if the script errors, Claude Code shows nothing rather than a stack trace, so test it in isolation:
echo '{"model":{"display_name":"Test"},"context_window":{"used_percentage":42}}' | ~/.claude/statusline.sh.
On Windows the other common "not showing" report is a bash script called directly from PowerShell. Run it through WSL, or use an inline command that does not assume a POSIX shell.
ccstatusline vs ccusage vs fifteen lines of bash
There is a real ecosystem here now. ccstatusline is a highly customizable formatter with a config UI plus git and token widgets. ccusage ships a statusline mode built around real-time usage tracking. Both are good, and if you want a menu instead of a script, reach for them.
I do not, and the reason is not purity. A statusline is the one piece of my setup I want to understand completely, because it is on screen constantly and it shapes my behavior every single message. Fifteen lines of bash I wrote myself means I know exactly what each field is, why it is there, and what to cut the day it stops earning its place. A plugin is the right call when you want breadth. A hand-rolled script is the right call when you want to be able to delete things without asking permission.
That is the whole setup. Steal the four fields, ignore the rest, and turn off anything you cannot articulate a reason for.
Sources
- Claude Code docs, "Customize your status line" (
code.claude.com/docs/en/statusline), July 2026: settings schema, stdin JSON fields, and update timing. ccstatusline(github.com/sirmalloc/ccstatusline), 2026.ccusagestatusline guide (ccusage.com/guide/statusline), 2026.
Written by
M. PatelBackend dev. Writes when something breaks. Currently shipping a B2B agent product with one cofounder.
Frequently asked questions
Why is my Claude Code statusline not showing?
Three usual causes in 2026: the script is not executable or the path is wrong (run chmod +x and use an absolute or ~-anchored path), jq is not installed so every field expands to empty, or you edited the script and it has not refreshed yet (it updates on the next interaction, not instantly). Test it by echoing sample JSON into the script directly.
What data can a Claude Code statusline show?
Claude Code sends JSON on stdin with fields including model.display_name, workspace.current_dir, cwd, session_id, version, output_style.name, the cost.* values (total_cost_usd, total_duration_ms, total_lines_added), and context_window.used_percentage. The context percentage is the most useful for day-to-day work.
How do I show token or context usage in the statusline?
Read context_window.used_percentage from the stdin JSON in your script. That single number tells you how full the context window is and when a /compact is likely, which is more actionable than session cost.
Should I use a plugin like ccstatusline or write my own script?
A plugin such as ccstatusline or ccusage is best if you want breadth and a config UI. A hand-written script of a dozen lines is best if you want to understand and prune every field yourself. Both read the same JSON that Claude Code pipes in on stdin.
How often does the Claude Code statusline update?
After each assistant message, after /compact finishes, on a permission-mode change, and on a vim-mode toggle, all debounced at 300ms. Add a refreshInterval (minimum 1 second) only for time-based values like a clock.
Keep reading
Three things I deleted from my Claude Code setup this month (and one I almost did)
A short, honest June 2026 retro on what got cut from a working Claude Code config: the custom statusline, the over-engineered MCP wrapper, the autosave permission. Plus the one thing I almost killed and why I kept it.
I Built 20 Claude Code Commands. I Use Four.
A field note on Claude Code commands: which custom slash commands actually earned their place, which I deleted, and the 2026 question the listicles skip, when a command should have been a skill.
Claude Code plan mode: when it earns its place (2026)
A field note on Claude Code plan mode after months of daily use: when it saves me, when I skip it, three failure modes the listicles miss, and the exact habit I built around it.


