Issue 00 · Autumn 2026日本語 · RSS
AgentKoji

How to Set Up the Claude Code Status Line

Claude Code's status line runs your script and batches updates at 300ms. How to configure it, what JSON the script receives, and a working bash + jq script.

TL;DR

  • The status line shows whatever your script prints; Claude Code sends session data to it as JSON on stdin.
  • Configure it with /statusline in plain language, or add a statusLine block (type, command, padding, refreshInterval) to your settings.
  • Useful fields include model.display_name, workspace.current_dir, cost.total_cost_usd (a local estimate) and context_window.used_percentage.

The status line is a row at the bottom of Claude Code that shows the output of a script you write. Claude Code sends session data to the script as JSON on stdin and displays whatever the script prints to stdout. This guide covers how to configure it, the JSON the script receives, when it updates, a minimal script, a few extras, and what to check when nothing shows up. In our test environment (macOS, Claude Code 2.1.306, jq 1.7.1, on 2026-10-22), we piped dummy JSON into the script and checked its output. We didn’t watch it render inside a Claude Code session (not run).

Two ways to configure it

The first is the /statusline command. Describe what you want in plain language, and Claude Code writes a script into ~/.claude/ and updates your settings. To remove it, ask with something like /statusline delete.

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

The second is to add a statusLine block to your settings yourself, in user settings (~/.claude/settings.json) or project settings:

{
  "statusLine": {
    "type": "command",
    "command": "~/.claude/statusline.sh",
    "padding": 2,
    "refreshInterval": 5
  }
}
KeyWhat it does
typeSet to "command"
commandA script path, or an inline shell command
paddingExtra horizontal spacing in characters. Defaults to 0
refreshIntervalRe-runs the command every N seconds on top of event-driven updates. Minimum 1. Leave it unset to run only on events

Source: https://code.claude.com/docs/en/statusline (checked 2026-10-22)

For where settings files live and which one wins, see Claude Code settings.json Permissions: A Cheat Sheet.

The JSON your script receives

These are the fields you’ll use most. There are more in the docs.

FieldContents
model.id, model.display_nameCurrent model ID and display name
workspace.current_dirCurrent working directory; cwd holds the same value
workspace.project_dirDirectory where Claude Code was launched
cost.total_cost_usdEstimated session cost in USD, computed locally at list price. May differ from your bill
cost.total_duration_msSession wall-clock time in milliseconds
cost.total_lines_added, cost.total_lines_removedLines added and removed
context_window.used_percentageContext usage, calculated from input tokens only
context_window.context_window_sizeContext window size in tokens
rate_limits.five_hour.used_percentageShare of the 5-hour limit used
rate_limits.seven_day.used_percentageShare of the 7-day limit used
session_id, versionSession ID and Claude Code version

Some fields are null until the first API response arrives, so give them a fallback such as jq’s // 0. rate_limits appears only for claude.ai Pro and Max subscribers, or behind a Claude apps gateway that sets a spend limit, and only after the session’s first API response. Each window can be absent on its own, so use // empty in jq to print nothing when it’s missing.

Source: https://code.claude.com/docs/en/statusline (checked 2026-10-22)

When it updates

The script runs once when a session starts, including on resume. After that it runs again when:

Updates are debounced at 300ms, so rapid changes batch into one run. A change to command skips the debounce and runs right away. If a new update fires while the script is still running, the in-flight run is cancelled. The status line runs locally and doesn’t use API tokens.

Source: https://code.claude.com/docs/en/statusline (checked 2026-10-22)

A minimal script

This one prints model | directory | git branch | context usage:

#!/bin/bash
# ~/.claude/statusline.sh: model | directory | git branch | context
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')
BRANCH=$(git -C "$DIR" branch --show-current 2>/dev/null)
echo "[$MODEL] ${DIR##*/} | ${BRANCH:-no git} | ctx ${PCT}%"

Make it executable with chmod +x ~/.claude/statusline.sh. We made a dummy repository at /tmp/todo-app, switched it to the branch feature/due-dates, and piped in JSON pointing at it:

$ echo '{"model":{"display_name":"Sonnet"},"workspace":{"current_dir":"/tmp/todo-app"},"context_window":{"used_percentage":23}}' | ~/.claude/statusline.sh
[Sonnet] todo-app | feature/due-dates | ctx 23%

With used_percentage set to null it printed ctx 0%. Pointed at /tmp, which isn’t a git repository, it printed no git. All exited 0. A current_dir written as a ~/projects/todo-app string printed no git, because git -C doesn’t expand the tilde.

We also tried timing 10 runs in a row, but our test machine was busy with other work that day and the numbers swung widely, so we don’t quote them here. The practical point stands: a slow script blocks the status line from updating until it finishes, and an update that arrives while it is still running cancels it, so keep the script fast.

Extras

Keep heavy work out of the script. The docs note that git status and git diff can be slow in large repositories, and show an example that caches git output in a temp file for 5 seconds. Name the cache file per session using session_id; process IDs change on every run and won’t work.

Source: https://code.claude.com/docs/en/statusline (checked 2026-10-22)

Not the same as output styles

An output style is a set of instructions that changes Claude’s role, tone and response format for a whole session. It changes how Claude answers, not what appears at the bottom of the screen. The status line JSON does include the current style’s name as output_style.name, so you can display it.

Sources: https://code.claude.com/docs/en/output-styles and https://code.claude.com/docs/en/statusline (checked 2026-10-22)

When nothing shows up

SymptomWhat to check
Nothing appearsThe script is executable (chmod +x), it prints to stdout rather than stderr, and it produces output when you run it by hand
It goes blankA non-zero exit code or empty output isn’t displayed
Blank in a new folderThe status line doesn’t run until you accept the workspace trust dialog
Shows -- or empty valuesSome fields are null before the first response; add a fallback like // 0
Still stuckclaude --debug logs the script’s stderr

Source: https://code.claude.com/docs/en/statusline (checked 2026-10-22)

In our runs, the script with its execute bit removed failed with Permission denied and exit 126. With jq removed from PATH, it printed jq: command not found to stderr, then a broken line, [] | no git | ctx %, and exited 0. Without jq, you get no error, just a garbled status line. Many script problems here share causes with hooks; see Claude Code Hooks Not Working? A Checklist.

Summary