How to set up a Claude Code status line
A status line is a bar at the bottom of Claude Code. Claude Code runs your script, pipes it a JSON snapshot of the session, and shows what the script prints.
This guide is for writing your own from scratch. To use one someone already made, install one from the gallery.
Updated 2026-10-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.
Copy from the gallery
Each status line there shows its real output before you copy it. Browse Claude Code status lines.
Wire up a script by hand
- 1
Save a minimal working script
Save this script to ~/.claude/statusline.sh. 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"The script needs jq. Install it with brew install jq on macOS, or sudo apt install jq on Debian and Ubuntu. - 2
Make it runnable
Mark it executable, so Claude Code can run it:
chmod +x ~/.claude/statusline.sh
- 3
Point settings.json at it
Point the statusLine setting in ~/.claude/settings.json at the script:
{ "statusLine": { "type": "command", "command": "~/.claude/statusline.sh" } }Claude Code runs the script as soon as you save. Two optional fields: padding indents the line by N characters, and refreshInterval re-runs the script every N seconds, for a clock or other live data. The official docs list the rest.
- 4
Test it
To try it outside Claude Code, save the sample JSON below as sample.json and run:
bash ~/.claude/statusline.sh < sample.json
For that payload it prints:
[Opus 5.5] app · 22% contextThis site's tests run this script on every pull request.
The JSON your script receives
Your script gets one JSON object on stdin per update. This is one of the payloads the gallery renders previews against:
{
"session_id": "b8e1c0d2-4a6f-4e2a-9c1b-3f5d7a9e2c10",
"transcript_path": "/home/user/.claude/projects/app/transcript.jsonl",
"fast_mode": false,
"version": "2.1.307",
"cwd": "/home/user/app",
"prompt_id": "7f3c2a91-5d4e-4b8a-a2c6-0e9d1b4f6a83",
"model": {
"id": "claude-opus-5-5",
"display_name": "Opus 5.5"
},
"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": []
},
"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,
"prompt_cache": {
"warm": true,
"caching_observed": true,
"ttl": "1h",
"expires_at": 1782003120,
"requests": 14,
"misses": 1,
"expected_rebuilds": 0,
"hit_ratio": 0.86,
"cache_write_tokens": 61000,
"miss_recache_tokens": 18500,
"last_miss_at": 1781997720,
"last_miss_cause": {
"causes": [
"tools_changed"
],
"tools_added": 2,
"tools_removed": 0
},
"miss_causes": {
"tools_changed": 1
},
"recache_tokens_if_cold": 44000
},
"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. Browse status lines that show token usage, usage limits or git status.
What each field holds, including the ones only some sessions send:
- session_id
- Unique ID for this session.
- transcript_path
- Path to the session's transcript file.
- fast_mode
- Whether fast mode is on.
- version
- Claude Code version.
- cwd
- Same value as workspace.current_dir.
- prompt_id
- ID of the prompt being processed. Absent until your first prompt.
- model
- id and display_name.
- effort
- Reasoning effort level. Absent when the model doesn't support it.
- thinking
- Whether extended thinking is on.
- workspace
- current_dir, project_dir and added_dirs, plus repo and git_worktree when they apply.
- cost
- Session cost, duration, and lines added and removed. Most scripts show total_cost_usd.
- context_window
- Token counts and used_percentage, which can be null early in a session.
- exceeds_200k_tokens
- Whether the last response passed 200k tokens.
- prompt_cache
- The main conversation's prompt cache: whether it's warm, hit_ratio, misses, when it expires, and more. Absent until the first response.
- rate_limits
- five_hour and seven_day windows on Pro and Max plans, or spend_limit behind a Claude apps gateway, each with used_percentage and resets_at in unix seconds. spend_limit can add used_usd, limit_usd and period. Appears after the first response, and a window drops out once its resets_at passes.
- output_style
- The current output style's name.
- pr
- Open PR's number, url and review_state, when the branch has one. For a GitLab merge request, kind is "mr".
- session_name
- The name from --name or /rename, else the AI-generated title. Absent until there is one.
- vim
- The vim mode, such as NORMAL or INSERT, when vim mode is on.
- agent
- The agent's name, when running with --agent or agent settings.
- worktree
- name, path, branch, original_cwd and original_branch, during a worktree session.
Common questions
Why isn't the git branch in the JSON?
Claude Code sends the repository name in workspace.repo and any open PR in pr, but not the branch or changed files. Scripts that show them run git in workspace.current_dir.
Why is used_percentage null?
context_window.used_percentage can be null early in a session. Guard it with // 0 in jq, or the line prints "null" until the first response.
Going further
The tools and resources list has status line tools, themes and usage trackers. If you build a status line you like, submit it to the gallery.
Status line blank in the terminal? Work through the fixes.
Claude Desktop's Code tab doesn't run your status line. Here's how to show it there.
For a pane or a slash command, you need a mod. Compare status lines and mods.