← Blog

Claude Code Statusline: Set Up a Custom Status Line

October 25, 2026

AI Coding

The Claude Code statusline is a row at the bottom of the terminal UI that shows whatever a script of yours prints. Claude Code pipes session data into that script as JSON, and you decide what to display: model, context usage, git branch, session cost, rate limits, or anything else you can compute.

You can set one up two ways:

  • The fast way: type /statusline followed by what you want, and Claude Code writes the script and updates your settings
  • The manual way: add a statusLine block to ~/.claude/settings.json that points at your own script

It runs locally and doesn't use API tokens. Below is how to set it up, every field your script can read, when it refreshes, and what to check when it shows up blank.

Set up a status line with /statusline

The quickest route is the built-in command. It takes plain-English instructions:

/statusline show model name and context percentage with a progress bar

Per the official status line docs, Claude Code generates a script in ~/.claude/ and updates your settings for you. Approve the file edits when it asks.

The same command removes it. Run /statusline delete, /statusline clear or /statusline remove it, or delete the statusLine field from your settings by hand.

Configure a custom status line manually

If you'd rather write the script yourself, add a statusLine field to your user settings (~/.claude/settings.json) or to a project's settings file:

{
  "statusLine": {
    "type": "command",
    "command": "~/.claude/statusline.sh",
    "padding": 2
  }
}

Each option does one job:

FieldWhat it does
typeAlways "command": run a shell command
commandA script path or an inline shell command
paddingOptional extra horizontal spacing, in characters. Defaults to 0
refreshIntervalOptional. Re-runs the command every N seconds on top of event updates. Minimum 1
hideVimModeIndicatorOptional. Hides the built-in -- INSERT -- text if your script shows vim mode itself

A minimal script

Save this as ~/.claude/statusline.sh. It uses jq to read the JSON, so install jq first if you don't have it:

#!/bin/bash
input=$(cat)

MODEL=$(echo "$input" | jq -r '.model.display_name')
DIR=$(echo "$input" | jq -r '.workspace.current_dir')
PCT=$(echo "$input" | jq -r '.context_window.used_percentage // 0' | cut -d. -f1)

echo "[$MODEL] ${DIR##*/} | ${PCT}% context"

Make it executable with chmod +x ~/.claude/statusline.sh. Claude Code reloads settings automatically, so the bar appears as soon as you save.

You don't need Bash. Python and Node.js work just as well, and both parse JSON without jq. On Windows, Claude Code runs the command through Git Bash if it's installed and PowerShell otherwise. Use forward slashes in the command path, because Git Bash eats unquoted backslashes and the script fails silently.

What JSON your script receives

Claude Code sends a JSON object on stdin every time it runs your command. These are the fields most people use:

FieldWhat it holds
model.id, model.display_nameThe current model
workspace.current_dir, workspace.project_dirCurrent directory, and the directory Claude Code was launched in
workspace.repo.owner, workspace.repo.nameRepo identity from the origin remote, when there is one
context_window.used_percentageShare of the context window in use, pre-calculated
context_window.context_window_sizeMax window in tokens: 200,000 by default, or 1,000,000 for extended-context models
cost.total_cost_usdEstimated session cost, computed client-side at list price
cost.total_duration_ms, cost.total_lines_addedWall-clock time and lines changed
rate_limits.five_hour.used_percentage, rate_limits.seven_day.used_percentageUsage of your 5-hour and 7-day limits
effort.level, fast_mode, thinking.enabledCurrent reasoning effort and mode flags
session_id, session_nameSession identifiers
pr.number, pr.review_stateOpen pull request for the current branch
vim.mode, agent.name, worktree.namePresent only when those features are in use

The docs also list prompt_cache statistics (hit ratio, whether the cache is warm, when it expires) and spend-limit fields for teams behind a Claude apps gateway. Several of those need a recent Claude Code version, so check the version note next to each field before you rely on it.

Fields that can be missing or null

This trips up most first scripts. Some fields are simply absent until they apply:

  • rate_limits only appears for Claude.ai Pro and Max subscribers (or behind a gateway with spend limits), and only after the first API response
  • vim, agent, pr and worktree only appear when that feature is active
  • context_window.used_percentage can be null early in a session, and current_usage is null again right after /compact

Always add a fallback. In jq that's // 0 for numbers or // empty to print nothing. The session cost also resets to zero when /clear starts a new session, and it's an estimate that may differ from your bill.

Why your context percentage disagrees with /context

used_percentage is calculated from input tokens only: fresh input plus cache writes plus cache reads. Output tokens don't count. The /context command also estimates messages added since the last response, so it can read higher until the next reply lands. If you compute the percentage yourself, use the same input-only formula. Our guide to Claude Code auto-compact explains what happens once that number gets high.

When the status line updates

The status line isn't a live ticker. Your script runs once at session start (including on resume), then again when:

  • A new assistant message arrives
  • /compact finishes
  • The permission mode or vim mode changes
  • You change the command in your settings
  • A rate-limit window or warm prompt cache reaches the time in the data your script last received
  • A refreshInterval timer fires, if you set one

Claude Code debounces updates at 300ms, so a burst of changes produces one run. If a new update fires while your script is still running, the old run is cancelled. Edits to the script itself show up on the next trigger.

That's why a clock in your status line looks frozen while Claude is idle. Set refreshInterval if you show time-based data, or if background subagents change git state while the main session waits.

Claude Code status line examples

Your script can print more than one line of plain text:

  • Multiple rows: each echo or print becomes its own line
  • Colors: ANSI escape codes such as \033[32m for green
  • Clickable links: OSC 8 escape sequences, in terminals that support them like iTerm2, Kitty and WezTerm. Terminal.app doesn't

A common two-line layout puts model, folder and git branch on top, and a color-coded context bar with cost and duration underneath (green under 70%, yellow to 89%, red above). The official docs include that exact script in Bash, Python and Node.js.

Cache slow commands

Your script runs often. git status in a big repo can make the bar lag. The docs' fix is to cache git output in a temp file for a few seconds, keyed by session_id. Don't key the cache on a process ID, because that changes on every run and defeats the cache.

Size output to the terminal

Claude Code captures your script's output instead of handing it the terminal, so tput cols won't work. Read the COLUMNS and LINES environment variables instead, and keep the line short so it doesn't wrap.

Test before you wire it up

Pipe fake JSON into the script and check the output:

echo '{"model":{"display_name":"Opus"},"workspace":{"current_dir":"/home/user/project"},"context_window":{"used_percentage":25},"session_id":"test"}' | ~/.claude/statusline.sh

Prebuilt community status lines

If you don't want to write a script, the docs point to two community projects. ccstatusline is an MIT-licensed configurable status line with themes and powerline support; you run its setup TUI with npx -y ccstatusline@latest. starship-claude renders the status line through the Starship prompt. Both are third-party, and both run code on every status line refresh, so read what they install.

Status line not showing? Common fixes

Work through these in order:

  1. The script isn't executable. Run chmod +x on it.
  2. It prints to stderr, or exits non-zero. Claude Code only displays output after the script exits with code 0.
  3. You haven't trusted the folder. Because statusLine runs a shell command, it follows the same workspace trust rule as hooks. Until you accept the trust dialog, it stays blank.
  4. Hooks are disabled. If disableAllHooks is true, only a managed statusLine runs. An organization setting allowManagedHooksOnly hides custom status lines the same way.
  5. Values show -- or are empty. Fields can be null before the first API response. Add fallbacks.
  6. Windows path problems. Use forward slashes in the command.

claude --debug logs your script's stderr on each run, which usually points straight at the problem.

FAQ

How do I add a status line in Claude Code?

Run /statusline with a description of what you want, or add a statusLine block with "type": "command" and a script path to ~/.claude/settings.json.

Where does the statusline config live?

In your user settings at ~/.claude/settings.json, or in a project's settings files if you want it per project.

Does the status line cost tokens?

No. It runs locally and doesn't consume API tokens.

Can the status line show my rate limits?

Yes, if you're on a Claude.ai Pro or Max plan. Read rate_limits.five_hour.used_percentage and rate_limits.seven_day.used_percentage, with a fallback for when they're absent.

Why does my status line clock not update?

Updates are event-driven. Add refreshInterval with a number of seconds to re-run the script on a timer.

Can subagents have their own status line?

Yes. A separate subagentStatusLine setting lets a script rewrite each subagent row in the agent panel.

How is this different from keyboard shortcuts or the footer hints?

The status line is your own script's output, shown in a row above Claude Code's built-in footer badges. With a custom status line set, Claude Code hides most of the footer's keyboard hints, such as "esc to interrupt."

The short version

A Claude Code status line is a script that reads JSON on stdin and prints a line or two. Start with /statusline, add fallbacks for fields that may be missing, cache anything slow, and trust the folder if it stays blank.

Getting a terminal setup like this exactly right is the kind of thing power users do once and then share. Taku is an AI-native desktop workspace where you can mirror an AI app, skill or workflow someone already got working and run it without rebuilding their environment first. Taku is in Beta, and the Mac app is available now.