Skip to content AI News: Mistral Large 4 is open weight: what you can run, and what it costs on the API →

Claude Code Statusline: Setup, JSON Fields and 6 Tested Scripts

Context at 72%, $1.87 spent, branch feature/login: a Claude Code status line keeps numbers like these on a row under the prompt while you work. Claude Code pipes session data into your script as JSON on stdin and shows whatever it prints. The script runs locally and doesn't consume API tokens.

Turn it on: /statusline or settings.json

The quick route is the /statusline command. Describe what you want, and Claude Code writes a script into ~/.claude/ and updates your settings; approve the file edits when it asks. Name each field, and say what to show when it's missing:

/statusline Two lines. Line 1: the model display name in brackets, the current folder name, and the git branch with * when there are uncommitted changes. Line 2: a 10-cell bar of context_window.used_percentage, green under 60%, yellow from 60%, red from 80%, then the session cost as $0.00 and the elapsed minutes. Treat any missing or null field as 0. Write it in bash with jq.

To take it off again, run /statusline delete or remove the statusLine field from your settings.

The manual route is the same block written by hand, in your user settings or in project settings if the whole repo should get it:

{
  "statusLine": {
    "type": "command",
    "command": "~/.claude/statusline.sh",
    "padding": 0,
    "refreshInterval": 5
  }
}
FieldWhat it does
typeAlways "command"
commandA script path or an inline shell command; it runs in a shell
paddingExtra horizontal spacing in characters, default 0
refreshIntervalAlso re-runs the command every N seconds, minimum 1. Leave it out to run on events only
hideVimModeIndicatortrue hides the built-in -- INSERT -- text when your script shows vim.mode itself

Every field after command is optional, and Claude Code picks up the change as soon as you save the file. A separate subagentStatusLine setting rewrites the rows of the agent panel, one per subagent.

Start with /statusline, then edit the file it wrote. It's a plain script.

When Claude Code re-runs the script

The script runs once when a session starts or resumes, then again on events: a new assistant message, /compact finishing, a permission-mode change, a vim-mode toggle, or an edit to command. A refreshInterval timer adds runs on top. So does a rate-limit window, or a warm prompt cache, reaching the reset or expiry time in the data your script last saw.

Updates are debounced at 300 ms, and a new update cancels a script that's still running. Output shows only after the script exits with code 0, so a non-zero exit or empty stdout leaves the row blank. The row also hides during the help menu and permission prompts.

That shapes the script. Anything that changes while Claude sits idle, a clock for instance, needs refreshInterval, because no event will fire. Anything slow delays the row: a git status in a big repo belongs behind a cache, and Anthropic's caching example keys a temp file on session_id. For width, read $COLUMNS. Claude Code captures your output, so tput cols can't see the terminal.

The JSON your script receives

Each run gets one JSON object. These are the fields worth putting on a status line; the full field list adds prompt-cache statistics, the transcript path, the output style and a few more.

FieldHoldsAbsent when
model.display_name, model.idModel name and identifierNever
workspace.current_dirWorking directory. Same value as cwd; this one is preferredNever
workspace.project_dirWhere Claude Code was launchedNever
workspace.git_worktreeName of the linked git worktree you're inIn the main working tree
workspace.repo.owner, .name, .hostRepo identity from the origin remoteOutside a repo, or with no origin
context_window.used_percentageShare of the context window in useNever, but it can be null early in a session
context_window.context_window_sizeMax tokens: 200000 by default, 1000000 with extended contextNever
cost.total_cost_usdEstimated session cost in USDNever; resets to $0 on /clear
cost.total_duration_ms, cost.total_api_duration_msSession wall-clock time, and time spent waiting on the APINever
cost.total_lines_added, cost.total_lines_removedLines of code changedNever
rate_limits.five_hour.*, rate_limits.seven_day.*used_percentage (0 to 100) and resets_at (epoch seconds)Off Pro and Max plans, and before the first API response
effort.levellow, medium, high, xhigh or maxThe model doesn't support effort
session_nameThe --name or /rename name, else the AI-generated titleNeither exists yet
pr.number, pr.url, pr.review_stateOpen PR (or GitLab merge request) for the branchNo open PR found; gone once it merges or closes
worktree.name, worktree.branchThe Claude Code worktree session you're inOutside a worktree session
vim.modeNORMAL, INSERT, VISUAL or VISUAL LINEVim mode is off
agent.nameAgent set with --agent or agent settingsNo agent configured
versionClaude Code versionNever

The cost figure is computed client-side at list price unless a modelPricing table is in effect, so it can differ from your bill. Rate limits also appear behind a Claude apps gateway that sets a spend limit, under rate_limits.spend_limit.

used_percentage is calculated from input tokens only: fresh input plus cache writes plus cache reads, no output tokens. And /context can read higher than the status line, because it estimates the messages added since the last response. Read used_percentage and don't recompute it.

Save this as sample.json. It holds only documented fields, with values chosen so every script below has something to show:

{
  "session_id": "test-session-abc",
  "model": { "id": "claude-opus-5-5", "display_name": "Opus" },
  "workspace": {
    "current_dir": "/home/you/my-app",
    "project_dir": "/home/you/my-app",
    "git_worktree": "feature-xyz"
  },
  "cost": {
    "total_cost_usd": 1.8734,
    "total_duration_ms": 1384000,
    "total_api_duration_ms": 412000,
    "total_lines_added": 156,
    "total_lines_removed": 23
  },
  "context_window": {
    "context_window_size": 200000,
    "used_percentage": 72,
    "remaining_percentage": 28
  },
  "rate_limits": {
    "five_hour": { "used_percentage": 23.5, "resets_at": 1738425600 },
    "seven_day": { "used_percentage": 41.2, "resets_at": 1738857600 }
  },
  "pr": { "number": 1234, "url": "https://github.com/anthropics/claude-code/pull/1234", "review_state": "pending" }
}

Test a script with ./statusline.sh < sample.json, then delete fields and run it again. A fresh session sends a thinner object than this one, and the script has to survive that.

Six status line scripts to copy

Each script reads stdin, prints one or two lines and exits 0. Save it under ~/.claude/, run chmod +x on it, and put its path in command. The output under each one is what it printed for sample.json on macOS's stock bash 3.2 with jq 1.7.1 (Node 26 for the last), with current_dir pointed at a git repo on branch feature/login that had uncommitted changes. The first five need jq installed.

1. Model, folder and git branch

git -C points git at the folder from the JSON, and a trailing * flags uncommitted changes.

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

MODEL=$(echo "$input" | jq -r '.model.display_name')
DIR=$(echo "$input" | jq -r '.workspace.current_dir')

# Branch of the folder Claude is working in; * when there are uncommitted changes
BRANCH=$(git -C "$DIR" branch --show-current 2>/dev/null)
if [ -n "$BRANCH" ]; then
  [ -n "$(git -C "$DIR" status --porcelain 2>/dev/null)" ] && BRANCH="$BRANCH*"
  echo "[$MODEL] ${DIR##*/} | $BRANCH"
else
  echo "[$MODEL] ${DIR##*/}"
fi

Output:

[Opus] my-app | feature/login*

Outside a repo it prints [Opus] my-app. On a large repo, put the two git calls behind the cache.

2. Context bar that changes color

A 10-cell bar of used_percentage: green below 60%, yellow from 60%, red from 80%. One jq call returns both values as tab-separated text, which saves starting a second jq process on every update.

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

# One jq call, two tab-separated values
IFS=
Weekly

New prompts in your inbox

One email a week: the best new prompts and one short guide. Confirm by email and get the free Prompt Cheat Sheet (PDF). Unsubscribe any time. Privacy policy