Build This Now
Build This Now
Keyboard ShortcutsStatus Line Guide
Claude Code VSCode ExtensionClaude Code vs Cursor in 2026OpenClaw vs Claude CodeAI SEO and GEO OptimizationClaude Code KeybindingsClaude Code Status Line Setup
Get Build This Now
speedy_devvkoen_salo
Blog/Toolkit/Extensions/Claude Code Status Line Setup

Claude Code Status Line Setup

How to wire up a custom Claude Code status line. Configuration, JSON input, ready-to-copy scripts in bash, Python, and Node.js.

Problem: The Claude Code terminal leaves a lot of useful information off the screen. A custom status line drops the model name, the git branch, the running session cost, and your context usage right under the chat interface.

Think of it as PS1 for Claude Code. If you've ever tweaked a shell prompt with Oh-my-zsh or Starship, the idea is identical. One line of live info that keeps you oriented while you work.

What the Status Line Shows

The status line lives at the bottom of the Claude Code interface and refreshes every time the conversation changes. Whatever your script prints gets displayed: the current model, the active git branch, how much the session has cost, or how full your context window is.

Here's a configured one in the wild:

[Opus] my-project | main | $0.42 | Context: 37%

One line. Model, project folder, git branch, session cost so far, and the percentage of the context window in use. Every field updates on its own.

Quick Setup with /statusline

Built right into the CLI is the /statusline command. Type it inside Claude Code and it generates a script for you.

/statusline

The default behavior creates a status line script that mirrors your terminal prompt. You can also hand it a specific request:

/statusline show the model name in orange

/statusline display git branch and session cost

/statusline show context window percentage with color coding

That's it. Claude Code writes the script, wires up the settings, and the status line appears. For full control, the manual route is next.

Manual Setup via settings.json

To configure it by hand, add a statusLine entry to your project's .claude/settings.json (or to your global ~/.claude/settings.json if you want it on every project):

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

Three fields worth knowing:

  • type: Always "command" for script-based status lines
  • command: Path to the script that generates your status line output
  • padding: Number of empty lines above the status line (0 is typical)

Once that entry is in place, create the script file and mark it executable:

touch ~/.claude/statusline.sh
chmod +x ~/.claude/statusline.sh

The chmod +x step matters. If your status line never shows up, a missing execute permission is almost always the cause.

How the Status Line Engine Works

Knowing the mechanics pays off the moment you debug or customize a script:

  • Update trigger: The status line refreshes whenever conversation messages change
  • Throttle: Updates run at most every 300ms to avoid performance issues
  • Output handling: Only the first line of stdout from your script becomes the status line text
  • Colors: Full ANSI color code support for styling
  • Input: Claude Code pipes a JSON object with session data into your script via stdin

That last bullet is the key. Your script gets a structured JSON payload on stdin containing the current model, workspace paths, session cost, context window stats, and more. Parse it, format it, print one line to stdout.

The JSON Input Your Script Receives

Every status line update, your script receives this JSON structure on stdin:

{
  "hook_event_name": "Status",
  "session_id": "abc123...",
  "cwd": "/current/working/directory",
  "model": {
    "id": "claude-opus-4-1",
    "display_name": "Opus"
  },
  "workspace": {
    "current_dir": "/current/working/directory",
    "project_dir": "/original/project/directory"
  },
  "version": "1.0.80",
  "cost": {
    "total_cost_usd": 0.01234,
    "total_duration_ms": 45000,
    "total_api_duration_ms": 2300,
    "total_lines_added": 156,
    "total_lines_removed": 23
  },
  "context_window": {
    "total_input_tokens": 15234,
    "total_output_tokens": 4521,
    "context_window_size": 200000,
    "used_percentage": 42.5,
    "remaining_percentage": 57.5,
    "current_usage": {
      "input_tokens": 8500,
      "output_tokens": 1200,
      "cache_creation_input_tokens": 5000,
      "cache_read_input_tokens": 2000
    }
  }
}

The fields that do the real work in a practical status line:

  • model.display_name: Short model name like "Opus" or "Sonnet"
  • workspace.current_dir: Where you're working right now
  • cost.total_cost_usd: Running cost of the session in dollars
  • cost.total_lines_added / total_lines_removed: Track code changes
  • context_window.used_percentage: Pre-calculated context usage (0-100)
  • context_window.context_window_size: Total context window capacity

Status Line Scripts You Can Copy

Below are complete, runnable scripts in several languages. Grab the one that fits your setup.

Simple Bash Status Line

The smallest status line worth running. Model name plus current directory:

#!/bin/bash
input=$(cat)
 
MODEL=$(echo "$input" | jq -r '.model.display_name')
CURRENT_DIR=$(echo "$input" | jq -r '.workspace.current_dir')
 
echo "[$MODEL] ${CURRENT_DIR##*/}"

Output: [Opus] my-project

Behind the scenes this script leans on jq for JSON parsing. If jq isn't installed, run brew install jq on macOS or sudo apt install jq on Ubuntu.

Git-Aware Bash Status Line

Branch information joins the line, which pays off when you're juggling feature branches:

#!/bin/bash
input=$(cat)
 
MODEL=$(echo "$input" | jq -r '.model.display_name')
CURRENT_DIR=$(echo "$input" | jq -r '.workspace.current_dir')
 
GIT_BRANCH=""
if git rev-parse --git-dir > /dev/null 2>&1; then
    BRANCH=$(git branch --show-current 2>/dev/null)
    if [ -n "$BRANCH" ]; then
        GIT_BRANCH=" | $BRANCH"
    fi
fi
 
echo "[$MODEL] ${CURRENT_DIR##*/}$GIT_BRANCH"

Output: [Opus] my-project | feature/auth

Full-Featured Bash Status Line

Model, git branch, session cost, and context percentage, all on one line:

#!/bin/bash
input=$(cat)
 
MODEL=$(echo "$input" | jq -r '.model.display_name')
CURRENT_DIR=$(echo "$input" | jq -r '.workspace.current_dir')
COST=$(echo "$input" | jq -r '.cost.total_cost_usd // 0')
PERCENT_USED=$(echo "$input" | jq -r '.context_window.used_percentage // 0')
 
# Git branch
GIT_BRANCH=""
if git rev-parse --git-dir > /dev/null 2>&1; then
    BRANCH=$(git branch --show-current 2>/dev/null)
    if [ -n "$BRANCH" ]; then
        GIT_BRANCH=" | $BRANCH"
    fi
fi
 
# Format cost to 2 decimal places
COST_FMT=$(printf '%.2f' "$COST")
 
# Round context percentage
PERCENT_INT=$(printf '%.0f' "$PERCENT_USED")
 
echo "[$MODEL] ${CURRENT_DIR##*/}$GIT_BRANCH | \$${COST_FMT} | Ctx: ${PERCENT_INT}%"

Output: [Opus] my-project | main | $0.42 | Ctx: 37%

Bash with ANSI Colors

Color coding makes the line scannable at a glance:

#!/bin/bash
input=$(cat)
 
MODEL=$(echo "$input" | jq -r '.model.display_name')
CURRENT_DIR=$(echo "$input" | jq -r '.workspace.current_dir')
COST=$(echo "$input" | jq -r '.cost.total_cost_usd // 0')
PERCENT_USED=$(echo "$input" | jq -r '.context_window.used_percentage // 0')
 
# ANSI colors
ORANGE='\033[38;5;208m'
GREEN='\033[32m'
YELLOW='\033[33m'
RED='\033[31m'
CYAN='\033[36m'
RESET='\033[0m'
 
# Color context percentage based on usage
PERCENT_INT=$(printf '%.0f' "$PERCENT_USED")
if [ "$PERCENT_INT" -lt 50 ]; then
    CTX_COLOR=$GREEN
elif [ "$PERCENT_INT" -lt 80 ]; then
    CTX_COLOR=$YELLOW
else
    CTX_COLOR=$RED
fi
 
COST_FMT=$(printf '%.2f' "$COST")
 
echo -e "${ORANGE}[$MODEL]${RESET} ${CURRENT_DIR##*/} ${CYAN}\$${COST_FMT}${RESET} ${CTX_COLOR}Ctx:${PERCENT_INT}%${RESET}"

Below 50%, the context percentage is green. Between 50-80%, yellow. Above 80%, red. A quick visual signal that it's time to manage the context window.

Helper Function Approach for Complex Scripts

As a status line script grows, helper functions keep it readable:

#!/bin/bash
input=$(cat)
 
# Helper functions for clean extraction
get_model()     { echo "$input" | jq -r '.model.display_name'; }
get_dir()       { echo "$input" | jq -r '.workspace.current_dir'; }
get_cost()      { echo "$input" | jq -r '.cost.total_cost_usd // 0'; }
get_context()   { echo "$input" | jq -r '.context_window.used_percentage // 0'; }
get_added()     { echo "$input" | jq -r '.cost.total_lines_added // 0'; }
get_removed()   { echo "$input" | jq -r '.cost.total_lines_removed // 0'; }
get_version()   { echo "$input" | jq -r '.version'; }
 
MODEL=$(get_model)
DIR=$(get_dir)
COST=$(printf '%.2f' "$(get_cost)")
CTX=$(printf '%.0f' "$(get_context)")
ADDED=$(get_added)
REMOVED=$(get_removed)
 
echo "[$MODEL] ${DIR##*/} | \$$COST | Ctx:${CTX}% | +$ADDED/-$REMOVED"

Output: [Opus] my-project | $0.42 | Ctx:37% | +156/-23

+156/-23 at the end tracks lines added and removed in the session. A quick read on how much code has actually changed.

Python Status Line

For Python users over bash:

#!/usr/bin/env python3
import json
import sys
import os
import subprocess
 
data = json.load(sys.stdin)
 
model = data["model"]["display_name"]
current_dir = os.path.basename(data["workspace"]["current_dir"])
cost = data.get("cost", {}).get("total_cost_usd", 0)
ctx_pct = data.get("context_window", {}).get("used_percentage", 0)
 
# Get git branch
git_branch = ""
try:
    result = subprocess.run(
        ["git", "branch", "--show-current"],
        capture_output=True, text=True, timeout=2
    )
    if result.returncode == 0 and result.stdout.strip():
        git_branch = f" | {result.stdout.strip()}"
except Exception:
    pass
 
print(f"[{model}] {current_dir}{git_branch} | ${cost:.2f} | Ctx:{ctx_pct:.0f}%")

Node.js Status Line

For JavaScript developers:

#!/usr/bin/env node
const fs = require("fs");
const path = require("path");
const { execSync } = require("child_process");
 
let input = "";
process.stdin.on("data", (chunk) => (input += chunk));
process.stdin.on("end", () => {
  const data = JSON.parse(input);
 
  const model = data.model.display_name;
  const currentDir = path.basename(data.workspace.current_dir);
  const cost = (data.cost?.total_cost_usd || 0).toFixed(2);
  const ctxPct = Math.round(data.context_window?.used_percentage || 0);
 
  // Get git branch
  let gitBranch = "";
  try {
    const branch = execSync("git branch --show-current", {
      encoding: "utf8",
      timeout: 2000,
    }).trim();
    if (branch) gitBranch = ` | ${branch}`;
  } catch (e) {}
 
  console.log(
    `[${model}] ${currentDir}${gitBranch} | $${cost} | Ctx:${ctxPct}%`,
  );
});

Tracking Context Window Usage

Keeping eyes on the context window is one of the most practical reasons to run a status line. When it fills up, Claude Code compacts the conversation and detail gets lost. Seeing where you stand helps you decide when to start fresh or compact on your own terms.

Simple approach using the pre-calculated percentage:

#!/bin/bash
input=$(cat)
 
MODEL=$(echo "$input" | jq -r '.model.display_name')
PERCENT_USED=$(echo "$input" | jq -r '.context_window.used_percentage // 0')
 
echo "[$MODEL] Context: ${PERCENT_USED}%"

Advanced approach with manual calculation from raw token counts:

#!/bin/bash
input=$(cat)
 
MODEL=$(echo "$input" | jq -r '.model.display_name')
CONTEXT_SIZE=$(echo "$input" | jq -r '.context_window.context_window_size')
USAGE=$(echo "$input" | jq '.context_window.current_usage')
 
if [ "$USAGE" != "null" ]; then
    CURRENT_TOKENS=$(echo "$USAGE" | jq '.input_tokens + .cache_creation_input_tokens + .cache_read_input_tokens')
    PERCENT_USED=$((CURRENT_TOKENS * 100 / CONTEXT_SIZE))
    echo "[$MODEL] Context: ${PERCENT_USED}% (${CURRENT_TOKENS}/${CONTEXT_SIZE} tokens)"
else
    echo "[$MODEL] Context: 0%"
fi

The advanced version exposes the raw token numbers alongside the percentage. Useful when you want to know the exact remaining token budget, especially while picking between models with different context sizes.

Tracking Session Cost

cost.total_cost_usd updates in real time. Showing it in the status line keeps spending visible without a trip to the dashboard:

#!/bin/bash
input=$(cat)
 
MODEL=$(echo "$input" | jq -r '.model.display_name')
COST=$(echo "$input" | jq -r '.cost.total_cost_usd // 0')
COST_FMT=$(printf '%.2f' "$COST")
 
echo "[$MODEL] Session: \$${COST_FMT}"

For anyone on a budget or tracking cost per feature, that visibility pays off right away. Pair it with model selection strategies and you'll swap models as soon as a task drops below Opus-level demands.

Troubleshooting

Status line doesn't appear at all

A missing execute permission on the script file is the usual culprit. Fix it with:

chmod +x ~/.claude/statusline.sh

Script runs but output is empty

Your script may be writing to stderr instead of stdout. Only the first line of stdout reaches the status line. Add a quick echo "test" to confirm output, then build from there.

Testing your script manually

You can test without launching Claude Code by piping mock JSON straight into the script:

echo '{"model":{"display_name":"Test"},"workspace":{"current_dir":"/test"},"cost":{"total_cost_usd":0.5},"context_window":{"used_percentage":25}}' | ~/.claude/statusline.sh

If that prints the expected line, the script is fine. If nothing comes out, the problem is in your parsing.

jq not found

Grab it from your package manager:

# macOS
brew install jq
 
# Ubuntu/Debian
sudo apt install jq
 
# Windows (via scoop)
scoop install jq

Creative Status Line Ideas

Once the basics run, a few ideas to push the status line further:

  • Lines changed tracker: Print +added/-removed to keep an eye on session productivity
  • Session duration: Derive elapsed time from total_duration_ms
  • Model ID display: Surface the full model identifier while testing different model configurations
  • Project vs current directory: Show both when Claude Code moves into subdirectories
  • Cost-per-minute: Divide total_cost_usd by total_duration_ms and see the real burn rate
  • Context window bar: Swap the percentage for a visual bar like [========--]
  • Conditional warnings: Flip colors when context crosses 80% or cost passes a threshold

The status line runs any script you give it. Bash, Python, Node.js, anything you can write will render on screen.

What to Try Next

Your status line is live. Natural next moves:

  • Manage context proactively: Put the context percentage to work alongside context buffer management strategies
  • Set up the terminal environment: Learn terminal control techniques for a complete Claude Code workspace
  • Configure project settings: Lock in your configuration basics so every session starts with the right context

More in this guide

  • Keyboard Shortcuts
    Configure custom keyboard shortcuts in Claude Code.
  • Status Line Guide
    Set up a custom Claude Code status line showing model name, git branch, cost, and context usage.
  • AI SEO and GEO Optimization
    A rundown of Generative Engine Optimization: how to get content cited inside ChatGPT, Claude, and Perplexity responses instead of just ranked on Google.
  • Claude Code vs Cursor in 2026
    A side-by-side look at Claude Code and Cursor in 2026: agent models, context windows, pricing tiers, and how each tool fits different developer workflows.
  • Claude Code VSCode Extension
    Anthropic's VS Code extension puts Claude Code inside the editor sidebar as a Spark-icon panel, with inline diffs, plan mode, subagents, and MCP support.

Stop configuring. Start building.

SaaS builder templates with AI orchestration.

Get Build This Now

Claude Code Keybindings

Rebind any shortcut in Claude Code. Covers the 17 contexts, keystroke syntax, unbinding defaults, and keybindings.json example configs.

On this page

What the Status Line Shows
Quick Setup with /statusline
Manual Setup via settings.json
How the Status Line Engine Works
The JSON Input Your Script Receives
Status Line Scripts You Can Copy
Simple Bash Status Line
Git-Aware Bash Status Line
Full-Featured Bash Status Line
Bash with ANSI Colors
Helper Function Approach for Complex Scripts
Python Status Line
Node.js Status Line
Tracking Context Window Usage
Tracking Session Cost
Troubleshooting
Creative Status Line Ideas
What to Try Next

Stop configuring. Start building.

SaaS builder templates with AI orchestration.

Get Build This Now