ES · Leer en español Explore for free

Recipe · Basic · 10 min

Claude Code statusline: live model, context and usage limits

A dependency-free Python status line for Claude Code: model, branch, colored context, 5-hour and 7-day limits, and what to do when it doesn't show.

Cover: Claude Code statusline: live model, context and usage limits

Tested with Claude Code 2.1.316 · reviewed

See the files on GitHub Free · MIT license

The problem

While you work with Claude Code you don't know how much context you have left, which branch you're on or how much of your 5-hour and 7-day limits you've used until it's too late. The statusline solves it: a row at the bottom that runs your script. But many example scripts use jq, which doesn't come installed on Ubuntu (we checked), and then the bar shows up empty without you knowing why.

The solution

The status line is a customizable row at the bottom of Claude Code, above the footer indicators. Claude Code runs the command you configure, passes it a JSON with session data on standard input (model, folder, context, estimated cost and, on Pro, Max and Ultra plans, usage of the 5-hour and 7-day limits) and shows whatever the script prints to standard output. It runs locally and uses no tokens.

1. The quick way: /statusline

If you don't want to write anything, use the /statusline command with what you want to see in plain language:

/statusline show the model, the git branch and the context percentage with a progress bar

Claude Code generates a script in ~/.claude/ and updates your settings; approve the edits if it asks. With no arguments, it tries to set it up from your shell prompt. To remove it, /statusline delete (or "clear", "remove it"), or delete the statusLine key from your settings.json by hand.

The quick way is fine to start, but it pays to know what's inside: if the generated script uses jq and you don't have it installed, the bar comes out empty or garbled. That's why this recipe uses Python, which ships with almost every Linux and macOS. If you prefer jq, install it first (sudo apt install jq on Ubuntu or Debian).

2. The script (Python, no dependencies)

Save it as ~/.claude/statusline.py:

#!/usr/bin/env python3
# Save it as ~/.claude/statusline.py and make it executable: chmod +x ~/.claude/statusline.py
"""Status line: model · folder (branch) · context · 5 h / 7 d limits · cost."""
import json, os, subprocess, sys

d = json.load(sys.stdin)
model = (d.get("model") or {}).get("display_name", "?")
cwd = (d.get("workspace") or {}).get("current_dir") or d.get("cwd", "")
pct = int((d.get("context_window") or {}).get("used_percentage") or 0)
cost = (d.get("cost") or {}).get("total_cost_usd") or 0
limits = d.get("rate_limits") or {}

try:
    branch = subprocess.run(["git", "-C", cwd, "branch", "--show-current"],
                            capture_output=True, text=True, timeout=1).stdout.strip()
except Exception:
    branch = ""

color = "\033[31m" if pct >= 80 else "\033[33m" if pct >= 50 else "\033[32m"
parts = [f"[{model}] {os.path.basename(cwd)}" + (f" ({branch})" if branch else ""),
         f"{color}ctx {pct}%\033[0m"]
for key, label in (("five_hour", "5h"), ("seven_day", "7d")):
    used = (limits.get(key) or {}).get("used_percentage")
    if used is not None:
        parts.append(f"{label} {used:.0f}%")
parts.append(f"${cost:.2f}")
print(" | ".join(parts))

It shows the model in brackets, the folder and git branch, the context percentage in color (green below 50 %, yellow up to 80 %, red from 80 %), usage of the 5-hour and 7-day limits if present, and the session's estimated cost. It uses the official fields:

FieldWhat it is
model.display_nameModel name
workspace.current_dirWorking folder
context_window.used_percentagePercentage of context used
rate_limits.five_hour.used_percentageUsage of the 5-hour limit
rate_limits.seven_day.used_percentageUsage of the 7-day limit
cost.total_cost_usdSession's estimated cost

Two important details from the docs: rate_limits only exists for Pro, Max and Ultra subscribers (or behind a gateway with a spend limit) and only after the session's first response; and used_percentage can be null at the start. That's why the script uses defaults and never fails when a field is missing. The cost is a list-price estimate computed on your machine: it may not match your bill and resets to 0 with /clear.

3. Turn it on in settings.json

Make the script executable and add the statusLine block to ~/.claude/settings.json:

chmod +x ~/.claude/statusline.py
{
  "statusLine": {
    "type": "command",
    "command": "~/.claude/statusline.py"
  }
}

It also works in the project settings, but then the whole team inherits it. Claude Code reloads the settings by itself and runs the script when you save. If you change the script, the change shows on the next event that runs it again (for example, the next message). For data that changes over time, like a clock, add "refreshInterval": 5 inside statusLine and it will also run every 5 seconds (minimum 1).

If you prefer jq, this is the one-line alternative from the official docs (requires jq installed):

{
  "statusLine": {
    "type": "command",
    "command": "jq -r '\"[\\(.model.display_name)] \\(.context_window.used_percentage // 0)% context\"'"
  }
}

4. Extras worth having

Check it

Before looking at the bar, test the script outside Claude Code with mock data. If it prints a line and exits with code 0, it will work in Claude Code. Also try a nearly empty JSON to check it copes with missing or null fields:

# 1. Test the script outside Claude Code with mock data
echo '{"model":{"display_name":"Opus"},"workspace":{"current_dir":"'$PWD'"},"context_window":{"used_percentage":62.4},"cost":{"total_cost_usd":0.43},"rate_limits":{"five_hour":{"used_percentage":23.5},"seven_day":{"used_percentage":41.2}},"session_id":"test"}' | ~/.claude/statusline.py
# [Opus] my-project (main) | ctx 62% | 5h 24% | 7d 41% | $0.43

# 2. No limits or data (session start or API key): it must not break
echo '{"model":{"display_name":"Sonnet"},"workspace":{"current_dir":"/tmp"},"context_window":{"used_percentage":null},"session_id":"x"}' | ~/.claude/statusline.py; echo "exit=$?"
# [Sonnet] tmp | ctx 0% | $0.00
# exit=0

We tested it on 1 Nov 2026 on Linux with Claude Code 2.1.316 and Python 3.12.3, without touching the user's settings (using claude --settings <file>): the script passes both tests and, in a trusted folder, the bar rendered like this:

[Opus 5.5] proyecto-50usd (main) | ctx 0% | $0.00

We didn't get to see rate_limits in the real bar, because it only arrives after the first response and we sent no message in that test.

Why it works

The script runs when a session starts or resumes, and again when a new assistant message arrives, when /compact finishes, when you change permission mode or vim mode, when you change the command and when a limit window reaches its reset time. Updates are batched with a 300 ms debounce and, if another one arrives while your script is still running, the previous run is cancelled. Note: with a custom bar, Claude Code stops showing most of the footer's keyboard hints, such as "esc to interrupt", and the bar hides for a moment during some dialogs, for example when it asks for permission.

Why does /context show more than your bar? It's not a bug. The bar shows the counts from the last API response, while /context adds an estimate of messages that arrived afterwards, so /context can show more until the next response. context_window.used_percentage is computed from input tokens only (regular input plus cache writes and reads), without output; if you compute the percentage yourself from current_usage, use the same formula, and keep in mind that current_usage is null before the first call and right after /compact. Another useful field: exceeds_200k_tokens says whether the last response went over 200,000 tokens, a fixed threshold even if your model has a 1-million window; context_window.context_window_size gives you the real window size. It's all in the statusline documentation.

Common mistakes

If your statusline doesn't show, check in this order:

To see what's going on, start with debug logging. It records your script's stderr and exit code:

# Still blank? Start with debug logging and look for the bar
claude --debug-file /tmp/claude-debug.log
# (in another terminal)
grep -i "statusline\|status line" /tmp/claude-debug.log

We saw these lines in our tests, the first with the Python script and the other two with a command that used jq without it being installed:

[DEBUG] StatusLine [~/.claude/statusline.py] completed with status 0
[DEBUG] StatusLine [jq -r ...] stderr: /bin/sh: 1: jq: not found
[WARN] StatusLine [jq -r ...] completed with status 1

If the problem is workspace trust, according to the official docs the log says Status line command skipped: workspace trust not accepted. We didn't verify that message ourselves: we didn't accept the trust dialog so as not to modify the user's configuration.

FAQ

Does the statusline use tokens or usage limits?

No. It runs on your machine with data Claude Code already has; it makes no API calls.

Why don't I see the 5-hour and 7-day usage?

The rate_limits object only reaches Pro, Max and Ultra subscribers (or behind a gateway with a spend limit) and only after the session's first response. With an API key it doesn't appear. Each window can be missing separately.

Is the cost it shows what I pay?

Not necessarily. cost.total_cost_usd is a list-price estimate computed on your machine; the docs warn it may differ from your actual bill, and on subscriptions it's not what you're charged. It resets to 0 with /clear.

It shows "--" or empty values, is it broken?

At the start of the session some fields arrive as null. Use defaults (in Python or 0, in jq // 0). If they're still empty after several messages, restart Claude Code.

Does it work on Windows?

Yes. Claude Code runs the command with Git Bash if it's installed, or with PowerShell if not. Write paths with / slashes, or call a script with powershell -NoProfile -File C:/Users/your-user/.claude/statusline.ps1.

Should I put it in the project or in my user settings?

In ~/.claude/settings.json if it's yours. In the project's .claude/settings.json the team inherits it, and it only runs once each person accepts workspace trust for the folder. To see which other pieces are configured there, check which piece to use.

The whole library