Building a Custom Status Line for Claude Code

· prosetesting's blog

A bash script that displays a rich statusline in Claude Code: model, git info, context usage, cost and duration.

Building a Custom Status Line for Claude Code #

Reading time: ~3 min

Claude Code lets you customize the status bar displayed between each response using an external script. Here's how I built mine.

Overview #

The script outputs two lines after each Claude response:

[Claude Opus 4.6] 📁 my-project | 🌿 main +2~1 | ⏰ 14:32:07
██████░░░░ 60% | $0.142 | ⏱️  3m 24s

Line 1 — Model name, workspace directory, git branch with staged/modified indicators, timestamp

Line 2 — Context window progress bar (color-coded by threshold), session cost, total duration

The script #

The script receives a JSON payload on stdin containing all the Claude Code session info. It extracts what it needs with jq.

1#!/bin/bash
2input=$(cat)
3
4# Extract data with jq
5MODEL=$(echo "$input" | jq -r '.model.display_name')
6DIR=$(echo "$input" | jq -r '.workspace.current_dir')
7COST=$(echo "$input" | jq -r '.cost.total_cost_usd // 0')
8PCT=$(echo "$input" | jq -r '.context_window.used_percentage // 0' | cut -d. -f1)
9DURATION_MS=$(echo "$input" | jq -r '.cost.total_duration_ms // 0')

ANSI colors #

An important gotcha: you must use $'...' (ANSI-C quoting) so bash interprets escape sequences at assignment time. Otherwise colors won't work when passed as %s arguments to printf.

1# Correct
2CYAN=$'\033[36m'
3
4# Wrong (outputs literal escape codes)
5CYAN='\033[36m'

Git integration with caching #

The script fetches the current branch and the number of staged/modified files. To avoid calling git on every refresh, a 42-second cache is used:

 1CACHE_FILE="/tmp/claude-statusline-cache"
 2CACHE_MAX_AGE=42
 3
 4cache_is_stale() {
 5    [ ! -f "$CACHE_FILE" ] && return 0
 6    local file_age
 7    file_age=$(stat -c %Y "$CACHE_FILE" 2>/dev/null) \
 8        || file_age=$(stat -f %m "$CACHE_FILE" 2>/dev/null) \
 9        || file_age=0
10    [ $(($(date +%s) - file_age)) -gt $CACHE_MAX_AGE ]
11}

The cache_is_stale() function handles both Linux (stat -c %Y) and macOS (stat -f %m).

Important detail: all git commands use -C "$DIR" to run in the workspace directory rather than /tmp (the script's actual working directory).

Color-coded progress bar #

The bar changes color based on context window usage:

Usage Color
< 70% Green
70-89% Yellow
>= 90% Red
1if [ "$PCT" -ge 90 ]; then BAR_COLOR="$RED"
2elif [ "$PCT" -ge 70 ]; then BAR_COLOR="$YELLOW"
3else BAR_COLOR="$GREEN"; fi
4
5FILLED=$((PCT / 10))
6EMPTY=$((10 - FILLED))
7BAR=$(printf "%${FILLED}s" | tr ' ' '█')$(printf "%${EMPTY}s" | tr ' ' '░')

Installation #

  1. Place the script at ~/.claude/statusline.sh
  2. Make it executable: chmod +x ~/.claude/statusline.sh
  3. Configure Claude Code in ~/.claude/settings.json:
1{
2  "preferences": {
3    "statusline": "~/.claude/statusline.sh"
4  }
5}

Version history #


Architect: t0nt0n | Implementation: Claude Sonnet 4.5 (v1.0) & Claude Opus 4.6 (v1.1+)

last updated:
⬛⚪⬛
⬛⬛⚪  ☠ user
⚪⚪⚪  rm -rf /ignorance && echo 42 > /dev/brain