Published on

Custom Status Line for Claude Code: Track Context and Costs in Real-Time

Authors

Claude Code supports a customizable status line at the bottom of your terminal. This status line runs a command of your choice and displays the output, giving you real-time visibility into your session.

┌────────────────────────────────────────────────────────────────────────────┐
Claude Opus 4.5 | 45000/200000 (22%) | $0.1234 | git:main                  │
└────────────────────────────────────────────────────────────────────────────┘

What the Status Line Shows

My setup displays:

  • Model name - Which Claude model is active
  • Context usage - Tokens used vs total, with percentage (color-coded)
  • Session cost - Running total in USD
  • Git branch - Current branch when in a repo
  • Python environment - Active venv or conda environment

Example output:

Claude Opus 4.5 | 45000/200000 (22%) | $0.1234 | git:main

The context percentage changes color as it fills: green under 20%, light green under 40%, yellow under 60%, orange under 80%, red above 80%.


Configuration

Add a statusLine entry to your .claude/settings.json:

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

The command receives JSON data via stdin containing context window info, cost, and model details.


The Script

Create .claude/statusline-command.sh:

#!/bin/bash

# Color codes (ANSI)
GREEN='\033[0;32m'
LIGHT_GREEN='\033[0;92m'
YELLOW='\033[0;33m'
ORANGE='\033[0;38;5;208m'
RED='\033[0;31m'
RESET='\033[0m'

# Read JSON input from stdin
input=$(cat)

# Extract context window info from JSON
CONTEXT_SIZE=$(echo "$input" | jq -r '.context_window.context_window_size')
USAGE=$(echo "$input" | jq '.context_window.current_usage')

# Calculate current tokens and percentage
if [ "$USAGE" != "null" ]; then
    # Sum up all token usage: input + cache creation + cache read
    USED_TOKENS=$(echo "$USAGE" | jq '.input_tokens + .cache_creation_input_tokens + .cache_read_input_tokens')
    TOTAL_TOKENS="$CONTEXT_SIZE"

    if [ "$TOTAL_TOKENS" -gt 0 ]; then
        PERCENTAGE=$((USED_TOKENS * 100 / TOTAL_TOKENS))
    else
        PERCENTAGE=0
    fi
else
    USED_TOKENS=0
    TOTAL_TOKENS="$CONTEXT_SIZE"
    PERCENTAGE=0
fi

# Determine color based on percentage (20% increments)
if [ "$PERCENTAGE" -lt 20 ]; then
    COLOR="$GREEN"
elif [ "$PERCENTAGE" -lt 40 ]; then
    COLOR="$LIGHT_GREEN"
elif [ "$PERCENTAGE" -lt 60 ]; then
    COLOR="$YELLOW"
elif [ "$PERCENTAGE" -lt 80 ]; then
    COLOR="$ORANGE"
else
    COLOR="$RED"
fi

# Format context display with color
CONTEXT_DISPLAY="${COLOR}${USED_TOKENS}/${TOTAL_TOKENS} (${PERCENTAGE}%)${RESET}"

# Get cost from JSON
COST_USD=$(echo "$input" | jq -r '.cost.total_cost_usd // 0')
# Format cost to 4 decimal places
COST_DISPLAY=$(printf '$%.4f' "$COST_USD")

# Get model name from JSON
MODEL_NAME=$(echo "$input" | jq -r '.model.display_name // "Claude"')

# Get git branch (if in git repo)
GIT_BRANCH=""
if git rev-parse --git-dir > /dev/null 2>&1; then
    GIT_BRANCH=$(git branch --show-current 2>/dev/null || git rev-parse --short HEAD 2>/dev/null)
    if [ -n "$GIT_BRANCH" ]; then
        GIT_BRANCH=" | git:${GIT_BRANCH}"
    fi
fi

# Get Python virtual environment
PYTHON_ENV=""
if [ -n "$VIRTUAL_ENV" ]; then
    PYTHON_ENV=" | venv:$(basename "$VIRTUAL_ENV")"
elif [ -n "$CONDA_DEFAULT_ENV" ]; then
    PYTHON_ENV=" | conda:${CONDA_DEFAULT_ENV}"
fi

# Output the status line
echo -e "${MODEL_NAME} | ${CONTEXT_DISPLAY} | ${COST_DISPLAY}${GIT_BRANCH}${PYTHON_ENV}"

Make it executable:

chmod +x .claude/statusline-command.sh

Available JSON Data

The script receives a JSON object with these fields:

PathDescription
.model.display_nameHuman-readable model name
.context_window.context_window_sizeTotal context tokens available
.context_window.current_usage.input_tokensDirect input tokens used
.context_window.current_usage.cache_creation_input_tokensTokens used for cache creation
.context_window.current_usage.cache_read_input_tokensTokens read from cache
.cost.total_cost_usdSession cost in USD

Requirements

The script requires jq for JSON parsing. Install it with:

# macOS
brew install jq

# Ubuntu/Debian
apt install jq

# Arch
pacman -S jq

Alternative: Static Status Line

For a simpler setup without a script, use a static string:

{
  "statusLine": {
    "type": "static",
    "content": "Claude Code Session"
  }
}

This displays fixed text but loses the dynamic context and cost tracking.


Full Settings Example

Here's a complete .claude/settings.json with the status line and common permissions:

{
  "permissions": {
    "allow": [
      "WebSearch",
      "Bash(npm run build:*)",
      "Bash(npm install:*)",
      "Bash(npm test)"
    ],
    "deny": [],
    "ask": []
  },
  "statusLine": {
    "type": "command",
    "command": "bash .claude/statusline-command.sh"
  }
}

The status line updates automatically as you interact with Claude, giving you constant visibility into context consumption and costs without leaving the terminal.