New: SEO Blog Writer, a readable, checked blog post for your site every week. Pay once, download straight away.

See it
AI Skill Up
Browse skills

How the Claude Code status line works, and how to set one up

What the Claude Code status line is, the JSON it receives, when it refreshes and why tput cols lies to it. A working setup in settings.json, start to finish.

The status line is the row Claude Code draws under your prompt. It is not a fixed widget: it is whatever a script of yours prints. Claude Code runs the script, hands it a JSON description of the session on standard input, and shows the output. That one idea explains every question people have about it.

Setting one up

The quick way is the /statusline command, which takes a description in plain words and writes a script into ~/.claude/ for you. The manual way is one field in ~/.claude/settings.json:

{
  "statusLine": {
    "type": "command",
    "command": "bash ~/.claude/my-statusline.sh",
    "padding": 0,
    "refreshInterval": 30
  }
}

padding adds horizontal spacing and defaults to 0. refreshInterval re-runs the command every N seconds, with a minimum of 1; leave it out and the line updates only on events. Anything that shows a clock or a countdown needs it, or an idle session shows a stale time.

What the script receives

The JSON on standard input carries, among other things:

FieldWhat it is
model.display_nameThe model, as a name you would show
workspace.current_dirThe folder the session is in
context_window.used_percentageHow full the context window is, already calculated
context_window.context_window_size200,000 tokens by default, or 1,000,000 with extended context
rate_limits.five_hour, rate_limits.seven_dayEach with used_percentage and resets_at in Unix epoch seconds
output_style.nameThe active output style

Some fields are missing at the start. used_percentage can be null early in a session, and rate_limits appears only for claude.ai Pro and Max subscribers, only after the first reply, with each window able to be absent on its own. A script that assumes a field exists prints garbage on the first turn, so read every one with a fallback, for example jq -r '.rate_limits.five_hour.used_percentage // empty'.

When it runs

  • Once when a session starts or resumes.
  • When a new assistant message arrives, when /compact finishes, and when the permission mode or vim mode changes.
  • When a rate-limit window it last saw reaches its resets_at time.
  • Every refreshInterval seconds, if you set one.

Updates are debounced at 300ms, and if a new one arrives while your script is still running, Claude Code cancels the old run. So the script has to be fast: a status line that shells out to a slow command simply never finishes.

The width trap

The mistake nearly every hand-written status line makes is sizing itself with tput cols. Claude Code captures the output instead of attaching the script to your terminal, so tput cannot see the real width and guesses. Read COLUMNS instead: Claude Code sets it, and LINES, before every run. A line that ignores this wraps to two rows in a narrow window, which pushes everything else down.

Colour and more than one line

ANSI escape codes work, if the terminal supports them, and each line the script prints becomes its own row. Note one side effect before you add a status line: with a custom one configured, Claude Code stops showing most of the footer's keyboard hints, such as esc to interrupt.

If you would rather not write and maintain the script, Capsule Status Line is ours: context, the 5-hour limit and the weekly limit as capsules with the exact reset time inside, the folder and branch, three themes, and it reads COLUMNS to stay on one line. It installs as a skill, like any other in how to install Claude Code skills.

Questions

Where do I configure the Claude Code status line?

In the statusLine field of ~/.claude/settings.json, or of a project's settings. Set type to command and command to a script or an inline shell command. padding and refreshInterval are optional.

Does a status line cost tokens?

No. It runs locally on your machine and does not consume API tokens. Claude Code runs your script and shows whatever it prints.

Why does my status line not fit the terminal width?

Claude Code captures the script's output rather than connecting it to the terminal, so tput cols cannot see the real size. Read the COLUMNS environment variable instead, which Claude Code sets before each run.

Or skip the afternoonand drop one in.