Claude Code Status Bar: Model, Git, Context and Cost at a Glance

March 20, 2026

Why a Custom Status Bar?

By default, Claude Code shows only basic information in its status line. With a simple Bash script, this can be significantly enhanced: model name, Git branch with staged/unstaged counters, context window usage as a progress bar, session cost and duration – all at a glance.

The result looks like this:

[Claude Sonnet 4.6]  my-project | main +2 ~1
████████████░░░░░░░░ 60% | $0.42 | 3m 12s

Prerequisites

  • Claude Code installed
  • jq (JSON parser): brew install jq
  • A terminal with ANSI color support (iTerm2, WezTerm, Ghostty, etc.)

Display Elements

ElementDescription
[Claude Sonnet 4.6]Currently active model
my-projectDirectory name (clickable link to repo)
mainGit branch (clickable link to branch)
+2Number of staged changes (green)
~1Number of unstaged changes (yellow)
Progress barContext window usage
60%Context window utilization
$0.42Total session cost
3m 12sSession duration so far

Context Bar Colors

ColorRangeMeaning
Green0 – 69%All good
Yellow70 – 89%Consider starting a new session soon
Red90%+Context nearly full

Installation

1. Create the Script

Create the file ~/.claude/statusline.sh with the following content:

#!/bin/bash
# Claude Code status line - two lines: git info + context/cost
input=$(cat)
MODEL=$(echo "$input" | jq -r '.model.display_name')
DIR=$(echo "$input" | jq -r '.workspace.current_dir')
COST=$(echo "$input" | jq -r '.cost.total_cost_usd // 0')
PCT=$(echo "$input" | jq -r '.context_window.used_percentage // 0' | cut -d. -f1)
DURATION_MS=$(echo "$input" | jq -r '.cost.total_duration_ms // 0')

CYAN='\033[36m'; GREEN='\033[32m'; YELLOW='\033[33m'; RED='\033[31m'; RESET='\033[0m'

# Git info with caching (refresh every 5s)
CACHE_FILE="/tmp/claude-statusline-git-cache"
CACHE_MAX_AGE=5

cache_is_stale() {
  [ ! -f "$CACHE_FILE" ] || \
  [ $(($(date +%s) - $(stat -f %m "$CACHE_FILE" 2>/dev/null || echo 0))) -gt $CACHE_MAX_AGE ]
}

BRANCH=""
GIT_STATUS=""
REMOTE_URL=""

if cache_is_stale; then
  if git rev-parse --git-dir > /dev/null 2>&1; then
    BRANCH=$(git branch --show-current 2>/dev/null)
    STAGED=$(git diff --cached --numstat 2>/dev/null | wc -l | tr -d ' ')
    MODIFIED=$(git diff --numstat 2>/dev/null | wc -l | tr -d ' ')
    REMOTE=$(git remote get-url origin 2>/dev/null \
      | sed 's/git@github\.com:/https:\/\/github.com\//' \
      | sed 's/\.git$//')
    echo "$BRANCH|$STAGED|$MODIFIED|$REMOTE" > "$CACHE_FILE"
  else
    echo "|||" > "$CACHE_FILE"
  fi
fi

IFS='|' read -r BRANCH STAGED MODIFIED REMOTE_URL < "$CACHE_FILE"

if [ -n "$BRANCH" ]; then
  [ "$STAGED" -gt 0 ] && GIT_STATUS="${GREEN}+${STAGED}${RESET}"
  [ "$MODIFIED" -gt 0 ] && GIT_STATUS="${GIT_STATUS} ${YELLOW}~${MODIFIED}${RESET}"
  if [ -n "$REMOTE_URL" ]; then
    BRANCH_LINK="\e]8;;${REMOTE_URL}/tree/${BRANCH}\a${BRANCH}\e]8;;\a"
  else
    BRANCH_LINK="${BRANCH}"
  fi
  GIT_INFO=" | ${BRANCH_LINK} ${GIT_STATUS}"
else
  GIT_INFO=""
fi

# Line 1: model, directory (clickable repo link), git branch
DIR_NAME="${DIR##*/}"
if [ -n "$REMOTE_URL" ]; then
  DIR_LINK="\e]8;;${REMOTE_URL}\a${DIR_NAME}\e]8;;\a"
else
  DIR_LINK="${DIR_NAME}"
fi

printf '%b\n' "${CYAN}[${MODEL}]${RESET} ${DIR_LINK}${GIT_INFO}"

# Line 2: context bar + cost + duration
if [ "$PCT" -ge 90 ]; then BAR_COLOR="$RED"
elif [ "$PCT" -ge 70 ]; then BAR_COLOR="$YELLOW"
else BAR_COLOR="$GREEN"; fi

FILLED=$((PCT / 5)); EMPTY=$((20 - FILLED))
BAR=""
[ "$FILLED" -gt 0 ] && BAR=$(printf "%${FILLED}s" | tr ' ' '█')
[ "$EMPTY" -gt 0 ] && BAR="${BAR}$(printf "%${EMPTY}s" | tr ' ' '░')"

COST_FMT=$(printf '$%.2f' "$COST")
MINS=$((DURATION_MS / 60000)); SECS=$(((DURATION_MS % 60000) / 1000))
echo -e "${BAR_COLOR}${BAR}${RESET} ${PCT}% | ${YELLOW}${COST_FMT}${RESET} | ${MINS}m ${SECS}s"

2. Make the Script Executable

chmod +x ~/.claude/statusline.sh

3. Update settings.json

Open ~/.claude/settings.json and add the statusLine configuration:

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

4. Restart Claude Code

After restarting, the new status bar will appear at the bottom of the terminal.

How the Script Works

Claude Code passes a JSON object via stdin to the configured script on every status line update. This object includes:

  • model.display_name – the active model
  • workspace.current_dir – the current working directory
  • cost.total_cost_usd – total session cost so far
  • context_window.used_percentage – context utilization
  • cost.total_duration_ms – session duration in milliseconds

The script parses these values with jq and assembles two output lines.

Git Caching

Since the status line updates frequently, the script caches Git information in /tmp/claude-statusline-git-cache. The cache refreshes every 5 seconds, keeping the display responsive without running git commands on every update.

In terminals with OSC 8 support (iTerm2, WezTerm, Ghostty), both the directory name and branch name are rendered as clickable links pointing directly to the repository or branch on GitHub.

Windows Variant

On Windows, the same can be achieved with a PowerShell script. Instead of jq, the built-in ConvertFrom-Json cmdlet is used. The settings.json configuration looks like this:

{
  "statusLine": {
    "type": "command",
    "command": "powershell -NoProfile -NonInteractive -File ~/.claude/statusline.ps1"
  }
}

Notes

  • No Git repo: Outside of a Git repository, only the model and directory name are displayed.
  • Terminal compatibility: Older terminals (e.g., macOS Terminal.app) will show OSC 8 links as plain text.
  • Enterprise GitHub: The script can automatically convert SSH URLs to HTTPS links – adjust the sed command in the script to match your domain.