How to set up a Claude Code status line

The status line is the bar at the bottom of Claude Code. Each time it refreshes, Claude Code runs your shell script, sends it a JSON snapshot on stdin, and shows whatever the script prints. Start with a fast path, or skip to wiring a script by hand.

Updated 2026-09-23

The fast paths

Run /statusline

Inside Claude Code, describe what you want, like /statusline show model, directory, and context usage. It writes the script to ~/.claude/ and updates your settings. Done.

Copy from the gallery

Every config shows exactly what it renders before you install it. Browse Claude Code status lines.

Wire up a script by hand

Save a script to ~/.claude/statusline.sh, make it executable (chmod +x ~/.claude/statusline.sh), and point the statusLine setting in ~/.claude/settings.json at it:

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

Claude Code reloads settings on its own. The status line appears on your next message. Two optional fields: padding adds horizontal space so the line isn't flush with the edge, and refreshInterval re-runs the script every N seconds if you show a clock or other live data. The official docs list the rest.

The JSON your script receives

Your script gets one JSON object on stdin per update. This is a real payload, the same one this site uses to render every gallery preview:

{
  "session_id": "b8e1c0d2-4a6f-4e2a-9c1b-3f5d7a9e2c10",
  "transcript_path": "/home/user/.claude/projects/app/transcript.jsonl",
  "cwd": "/home/user/app",
  "model": {
    "id": "claude-opus-4-8",
    "display_name": "Opus 4.8"
  },
  "effort": {
    "level": "high"
  },
  "thinking": {
    "enabled": true
  },
  "workspace": {
    "current_dir": "/home/user/app",
    "project_dir": "/home/user/app",
    "repo": {
      "host": "github.com",
      "owner": "acme",
      "name": "app"
    },
    "added_dirs": []
  },
  "version": "2.1.155",
  "cost": {
    "total_cost_usd": 0.41,
    "total_duration_ms": 612000,
    "total_api_duration_ms": 48000,
    "total_lines_added": 128,
    "total_lines_removed": 34
  },
  "context_window": {
    "context_window_size": 200000,
    "used_percentage": 22,
    "remaining_percentage": 78,
    "total_input_tokens": 44000,
    "total_output_tokens": 1400,
    "current_usage": {
      "input_tokens": 37000,
      "output_tokens": 1400,
      "cache_creation_input_tokens": 5000,
      "cache_read_input_tokens": 2000
    }
  },
  "exceeds_200k_tokens": false,
  "rate_limits": {
    "five_hour": {
      "used_percentage": 26,
      "resets_at": 1782007620
    },
    "seven_day": {
      "used_percentage": 7,
      "resets_at": 1782176400
    }
  },
  "output_style": {
    "name": "default"
  },
  "pr": {
    "number": 1287,
    "url": "https://github.com/acme/app/pull/1287"
  }
}

Most scripts only need a few fields: model.display_name, workspace.current_dir, context_window.used_percentage, and cost.total_cost_usd. Each rate_limits window has a usage percentage and a resets_at unix timestamp. The gallery collects configs that show token usage, usage limits, and git status.

The rest of that payload, field by field, as this site sends it:

session_id
UUID for this Claude Code session. Always present in gallery renders.
transcript_path
Path to the session transcript. This site fixtures it when a script reads the file.
cwd
Mirrors workspace.current_dir. Always present.
model
id and display_name. Gallery previews cover Opus, Sonnet, Haiku, and Fable.
effort
Reasoning effort. Absent on some models, including Haiku in these fixtures.
thinking
Whether extended thinking is on. Gallery scenarios cover both.
workspace
current_dir, project_dir, optional repo, git_worktree, and added_dirs.
version
Claude Code version string this site renders against.
cost
Running session cost, duration, and line counts. total_cost_usd is the usual display field.
context_window
Token usage. used_percentage is null at the start of a fresh session.
exceeds_200k_tokens
Boolean for the 200k token threshold.
rate_limits
five_hour and seven_day windows with used_percentage and resets_at. May be absent or partial.
output_style
Named output style, usually default.
pr
Optional PR number, url, and review_state. Git itself is not in the payload.

A minimal working script

Three fields, one jq call each:

#!/bin/bash
input=$(cat)
model=$(jq -r '.model.display_name' <<<"$input")
dir=$(jq -r '.workspace.current_dir' <<<"$input")
pct=$(jq -r '.context_window.used_percentage // 0' <<<"$input")
echo "[$model] ${dir##*/} · ${pct}% context"

For the payload above it prints:

[Opus 4.8] app · 22% context

You can try it without opening Claude Code: save that JSON to a file and run bash statusline.sh < sample.json. This repo's tests run that exact script against real payloads on every commit.

Common questions

Why isn't git in the JSON?

Claude Code does not send git state. Scripts that show a branch run git themselves against workspace.current_dir, including in a directory with no repo so you can see how they degrade.

Why is used_percentage null?

context_window.used_percentage is null at the start of a fresh session. Guard it (// 0 in jq) or the bar prints "null" until the first response. The gallery's new-session preview is that case.

How does this site know what a script prints?

It runs the submitted script in a sandbox against the same JSON scenarios on this page. The cards show that output, not a mock.

Going further

Want more than a few fields? The tools & resources list has themes, widgets, and usage trackers. Or copy a status line from the gallery and tweak it. If you build one you like, submit it to the gallery.

Using Claude Desktop? Its Code tab doesn't show custom status lines. Here's how to show yours there.