Who this is for and what you will get
This guide is for people who already use Claude Code and want a persistent line at the bottom of the terminal with the model, the working directory, context usage or session cost. By the end you will have a small status line script connected to Claude Code's settings, you will know which values you can display, and you will know where to look when the bar stays blank.[1]
What the status line is
The status line is a customizable bar at the bottom of the Claude Code interface. It runs a shell script that you configure. Claude Code passes session data to the script as JSON on stdin, and whatever the script prints to stdout appears in the bar.[1]
The bar sits on its own row above the built-in footer badges and does not replace them. Once a custom status line is configured, though, most of the footer's keyboard hints are hidden, including esc to interrupt.[1]
Before you start
You need Claude Code installed. The example script uses jq, a command-line JSON parser that you may have to install. If you prefer Python or Node.js, both can parse JSON with their built-in libraries and need nothing extra.[1]
Windows users should read the path rules in the common problems section before writing the command value.
Set up the status line
- Let Claude Code write it. Run
/statuslinewith a description of what you want:
/statusline show model name and context percentage with a progress barThe command generates a script in ~/.claude/ and updates your settings. If Claude Code asks you to approve a file edit, approve it.[1]
- Or write the script yourself. Save the following as
~/.claude/statusline.sh. It reads the JSON from stdin, usesjqto pull out the model name, the directory and the context percentage, and prints a single line.[1]
#!/bin/bash
# Read JSON data that Claude Code sends to stdin
input=$(cat)
# Extract fields using jq
MODEL=$(echo "$input" | jq -r '.model.display_name')
DIR=$(echo "$input" | jq -r '.workspace.current_dir')
# The "// 0" provides a fallback if the field is null
PCT=$(echo "$input" | jq -r '.context_window.used_percentage // 0' | cut -d. -f1)
# Output the status line - ${DIR##*/} extracts just the folder name
echo "[$MODEL] 📁 ${DIR##*/} | ${PCT}% context"- Make the script executable:
chmod +x ~/.claude/statusline.sh- Tell Claude Code to run it by adding this to
~/.claude/settings.json:
{
"statusLine": {
"type": "command",
"command": "~/.claude/statusline.sh"
}
}Claude Code reloads settings on its own, and the script runs as soon as you save the file.[1]
For a manual setup you can also add the optional padding field. It adds horizontal space in characters on top of the interface's built-in spacing, and it defaults to 0. Because it stacks on the built-in spacing, it controls relative indentation rather than the distance from the edge of the terminal.[1]
{
"statusLine": {
"type": "command",
"command": "~/.claude/statusline.sh",
"padding": 2
}
}If you would rather keep command as a one-line command than a script file, a jq expression works as well. This example prints the model name and the context percentage:
{
"statusLine": {
"type": "command",
"command": "jq -r '\"[\\(.model.display_name)] \\(.context_window.used_percentage // 0)% context\"'"
}
}When the bar updates
The script runs once when a session starts or resumes. It runs again after a new assistant message, after /compact finishes, when the permission mode changes, when Vim mode toggles, and when you change the command setting. Claude Code debounces updates at 300 milliseconds, so a burst of changes produces a single run. If a new update arrives while the script is still running, Claude Code cancels the running script.[1]
For values that change with time, such as a clock, set refreshInterval to a number of seconds. The minimum is 1. The timer also keeps data current while the main session is idle, for example while it waits for background subagents.[1]
The status line runs locally and does not consume API tokens. It hides briefly while the help menu or a permission prompt is open.[1]
Data you can display
The JSON includes the model (model.display_name), the working directory (workspace.current_dir), context usage (context_window.used_percentage), session cost (cost.total_cost_usd), session duration (cost.total_duration_ms), the session ID and the transcript path, among other fields.[1]
used_percentage counts input tokens only: input, cache creation and cache reads. Output tokens are left out. If you compute the figure yourself from current_usage, use the same formula so the numbers match.[1]
The /context command can show a higher number than the status line. The status line uses the counts from the last API response, while /context adds an estimate for messages added since then. The two agree again after the next response.[1]
Rate-limit fields appear only for claude.ai Pro, Max and Ultra subscribers, and only after the first API response in a session. The five-hour and seven-day windows can be missing independently, so read them with fallbacks, for example jq -r '.rate_limits.five_hour.used_percentage // empty'.[1]
Prompt cache fields such as warm, ttl and hit_ratio also appear after the main conversation's first API response. Requests made by subagents are not counted in them.[1]
Layout and links
Each echo or print produces its own row, so a script can display several lines. ANSI color codes work where the terminal supports them, for example \033[32m for green.[1]
Clickable links use OSC 8 escape sequences. They need a terminal such as iTerm2, Kitty or WezTerm, and Terminal.app does not support them.[1]
The script's output is captured rather than sent straight to the terminal, so tput cols cannot report the width. Read the COLUMNS and LINES environment variables instead; Claude Code sets them before it runs the script.[1]
Tips for writing the script
Keep the script fast. A slow script blocks updates, and if a new update arrives while it is still running, the running script is cancelled. Once it works, test it by hand with mock JSON input before you wire it into settings.[1] A script that exits with a non-zero code, or prints nothing, leaves the bar blank.[1]
For values that change with time, set refreshInterval. Without it, the bar updates only at the events listed earlier.[1]
Limits and common problems
- The bar stays blank. Check that the script is executable, that it writes to stdout, and that it runs by hand. A non-zero exit code or empty output leaves the bar blank. The bar also stays blank until you accept the workspace trust dialog for the folder, because
statusLineexecutes a shell command.[1] - Debug script errors. Run
claude --debugto log the script's stderr on every invocation, and its exit code on the first invocation in a session.[1] - Keep the script fast. A slow script blocks updates. Test it with mock input before you wire it into settings.[1]
- Windows paths. Git Bash treats unquoted backslashes as escape characters, so the command fails without a visible error. Write paths with forward slashes. A PowerShell script can be run with
powershell -NoProfile -File C:/Users/username/.claude/statusline.ps1.[1]
Next step
The full field list, the details of the prompt cache statistics, and more examples such as git status, cost tracking, progress bars and rate limits are in Anthropic's Claude Code documentation.[1]
Sources
- 1Customize your status lineAnthropic Claude Code docs
Cite this page: Customizing the Claude Code status line. TellWorld, https://www.tellworld.net/practice/practice-claude-code-statusline. Updated 2026-11-14