Custom Claude Code Status Line
Claude Code has a fully customizable status line. You point it at a shell script, it pipes in session data as JSON, and your script renders whatever you want. I built a powerline-style status bar that gives me everything I need at a glance.

Left to right:
- Model (Opus 4.6) — active Claude model
- Folder (git-manager/dev) — current repo as parent/folder
- Git branch (dev) — only shows when not on
main - Kubernetes context (k8s-blue-cc) — active cluster
- Context window (86%) — conversation fullness, scaled so 100% = compaction threshold
- 5h usage (2%, resets in 4h6m) — rolling 5-hour API quota
- 7d usage (53%, resets Thu 11:00) — rolling 7-day API quota
Each meter is color-coded: green under 50%, yellow 50-79%, red 80%+.
How It Works
Claude Code calls your script after each assistant message, piping a JSON blob to stdin with session metadata (model, workspace, context_window with token breakdown, cost, session_id, vim.mode, etc.). Your script reads it and prints ANSI-colored output to stdout.
The script has four parts: parse JSON for model/folder/branch, fetch API usage from Anthropic’s OAuth endpoint (cached 60s to avoid hammering the API), render color-coded progress bars, and assemble powerline segments with ANSI escape codes.
security find-generic-password. On Linux, you’d need a different approach to read the token.Installation
Requirements: Nerd Font (for powerline separators and icons), jq, kubectl (optional — remove the k8s segment if you don’t need it).
- Save the full script below to
~/.claude/statusline.shand make it executable:
chmod +x ~/.claude/statusline.sh- Add to
~/.claude/settings.json:
{
"statusLine": {
"type": "command",
"command": "bash ~/.claude/statusline.sh"
}
}- Restart Claude Code. The status line appears above the input prompt.
Adapting It
Each segment is independent — just ask Claude Code to adapt the script to your needs.
Full Script
statusline.sh
#!/bin/bash
# Modern Powerline-style statusline for Claude Code
# Requires: Nerd Font (for icons and separators)
# Read JSON input from stdin
input=$(cat)
# ═══════════════════════════════════════════════════════════════════════════════
# POWERLINE CHARACTERS & COLORS
# ═══════════════════════════════════════════════════════════════════════════════
# Powerline separators (Nerd Font)
SEP="" # U+E0B0 - right arrow (filled)
SEPR="" # U+E0B2 - left arrow (filled)
# Color definitions (256-color mode)
# Format: \033[38;5;XXXm = foreground, \033[48;5;XXXm = background
RST='\033[0m'
# Segment colors (bg, fg pairs)
# Using a cohesive dark palette
BG_MODEL="\033[48;5;24m" # Deep blue
FG_MODEL="\033[38;5;255m" # White text
FG_MODEL_SEP="\033[38;5;24m" # For separator after
BG_FOLDER="\033[48;5;30m" # Teal
FG_FOLDER="\033[38;5;255m" # White
FG_FOLDER_SEP="\033[38;5;30m"
BG_BRANCH="\033[48;5;132m" # Mauve (git branch segment)
FG_BRANCH="\033[38;5;255m" # White
FG_BRANCH_SEP="\033[38;5;132m"
BG_K8S="\033[48;5;91m" # Purple
FG_K8S="\033[38;5;255m" # White
FG_K8S_SEP="\033[38;5;91m"
BG_CTX="\033[48;5;237m" # Dark grey
FG_CTX="\033[38;5;250m" # Light grey
FG_CTX_SEP="\033[38;5;237m"
BG_5H="\033[48;5;236m" # Darker grey
FG_5H="\033[38;5;250m"
FG_5H_SEP="\033[38;5;236m"
BG_7D="\033[48;5;235m" # Darkest grey
FG_7D="\033[38;5;250m"
FG_7D_SEP="\033[38;5;235m"
# Status colors for usage levels
FG_OK="\033[38;5;77m" # Green
FG_WARN="\033[38;5;220m" # Yellow
FG_CRIT="\033[38;5;203m" # Red
# Nerd Font icons
ICON_MODEL="" # nf-md-robot
ICON_FOLDER="" # nf-md-folder
ICON_GIT="" # nf-md-git
ICON_BRANCH="" # nf-oct-git_branch
ICON_K8S="" # nf-md-kubernetes
ICON_CTX="" # nf-fa-tachometer_alt / gauge
ICON_5H="" # nf-fa-clock
ICON_7D="" # nf-fa-calendar_week
# ═══════════════════════════════════════════════════════════════════════════════
# DATA EXTRACTION
# ═══════════════════════════════════════════════════════════════════════════════
# Extract basic info
model=$(echo "$input" | jq -r '.model.display_name')
cwd=$(echo "$input" | jq -r '.workspace.current_dir')
# Get folder and branch (separate segments)
folder="$(basename "$(dirname "$cwd")")/$(basename "$cwd")"
folder_icon="${ICON_FOLDER}"
show_branch=""
branch_name=""
if git -C "$cwd" rev-parse --is-inside-work-tree &>/dev/null; then
branch_name=$(git -C "$cwd" branch --show-current 2>/dev/null)
if [[ "$branch_name" != "main" && -n "$branch_name" ]]; then
show_branch="yes"
fi
fi
# Context window usage
context_size=$(echo "$input" | jq -r '.context_window.context_window_size // 0')
context_usage=$(echo "$input" | jq -r '.context_window.current_usage // null')
if [[ "$context_usage" != "null" && "$context_size" -gt 0 ]]; then
context_tokens=$(echo "$input" | jq -r '.context_window.current_usage | (.input_tokens // 0) + (.cache_creation_input_tokens // 0) + (.cache_read_input_tokens // 0)')
context_pct_raw=$((context_tokens * 100 / context_size))
# Scale so 82% (conservative threshold) displays as 100%
# This gives more headroom before compaction at 78%
context_pct=$((context_pct_raw * 100 / 82))
[[ $context_pct -gt 100 ]] && context_pct=100
else
context_pct=0
fi
# Kubernetes context
k8s_context=$(kubectl config current-context 2>/dev/null || echo "none")
# ═══════════════════════════════════════════════════════════════════════════════
# API USAGE (5h/7d from Anthropic API)
# ═══════════════════════════════════════════════════════════════════════════════
USAGE_CACHE="$HOME/.cache/cc-usage.txt"
USAGE_LOCK="$HOME/.cache/cc-usage.lock"
USAGE_TTL="${CC_CACHE_TTL:-60}"
mkdir -p "$HOME/.cache"
get_api_usage() {
if [[ -f "$USAGE_CACHE" ]]; then
age=$(($(date +%s) - $(stat -f '%m' "$USAGE_CACHE" 2>/dev/null || echo 0)))
if [[ $age -lt $USAGE_TTL ]]; then
cat "$USAGE_CACHE"
return
fi
fi
if [[ -f "$USAGE_LOCK" ]]; then
age=$(($(date +%s) - $(stat -f '%m' "$USAGE_LOCK" 2>/dev/null || echo 0)))
if [[ $age -lt 30 ]]; then
[[ -f "$USAGE_CACHE" ]] && cat "$USAGE_CACHE"
return
fi
fi
touch "$USAGE_LOCK"
creds=$(security find-generic-password -s "Claude Code-credentials" -w 2>/dev/null)
if [[ -z "$creds" ]]; then
echo "?|?|?|?"
return
fi
token=$(echo "$creds" | jq -r '.claudeAiOauth.accessToken // empty' 2>/dev/null)
if [[ -z "$token" ]]; then
echo "?|?|?|?"
return
fi
resp=$(curl -s --max-time 5 \
"https://api.anthropic.com/api/oauth/usage" \
-H "Authorization: Bearer $token" \
-H "anthropic-beta: oauth-2025-04-20" 2>/dev/null) || true
if [[ -z "$resp" ]]; then
[[ -f "$USAGE_CACHE" ]] && cat "$USAGE_CACHE" || echo "?|?|?|?"
return
fi
session=$(echo "$resp" | jq -r '.five_hour.utilization // empty' 2>/dev/null)
weekly=$(echo "$resp" | jq -r '.seven_day.utilization // empty' 2>/dev/null)
if [[ -z "$session" || -z "$weekly" ]]; then
[[ -f "$USAGE_CACHE" ]] && cat "$USAGE_CACHE" || echo "?|?|?|?"
return
fi
session_int=$(printf "%.0f" "$session")
weekly_int=$(printf "%.0f" "$weekly")
session_reset=$(echo "$resp" | jq -r '.five_hour.resets_at // empty' 2>/dev/null)
if [[ -n "$session_reset" ]]; then
utc_epoch_5h=$(date -j -u -f "%Y-%m-%dT%H:%M:%S" "${session_reset%%.*}" "+%s" 2>/dev/null)
if [[ -n "$utc_epoch_5h" ]]; then
now_epoch=$(date +%s)
diff_sec=$((utc_epoch_5h - now_epoch))
if [[ $diff_sec -gt 0 ]]; then
diff_hr=$((diff_sec / 3600))
diff_min=$(((diff_sec % 3600) / 60))
session_reset_fmt="${diff_hr}h${diff_min}m"
else
session_reset_fmt="now"
fi
else
session_reset_fmt="?"
fi
else
session_reset_fmt="?"
fi
weekly_reset=$(echo "$resp" | jq -r '.seven_day.resets_at // empty' 2>/dev/null)
if [[ -n "$weekly_reset" ]]; then
utc_epoch=$(date -j -u -f "%Y-%m-%dT%H:%M:%S" "${weekly_reset%%.*}" "+%s" 2>/dev/null)
if [[ -n "$utc_epoch" ]]; then
weekly_reset_fmt=$(date -j -f "%s" "$utc_epoch" "+%a %H:%M" 2>/dev/null || echo "?")
else
weekly_reset_fmt="?"
fi
else
weekly_reset_fmt="?"
fi
echo "${session_int}|${weekly_int}|${session_reset_fmt}|${weekly_reset_fmt}" | tee "$USAGE_CACHE"
}
api_usage_raw=$(get_api_usage)
usage_5h=$(echo "$api_usage_raw" | cut -d'|' -f1)
usage_7d=$(echo "$api_usage_raw" | cut -d'|' -f2)
reset_5h=$(echo "$api_usage_raw" | cut -d'|' -f3)
reset_7d=$(echo "$api_usage_raw" | cut -d'|' -f4)
# ═══════════════════════════════════════════════════════════════════════════════
# PROGRESS BAR (compact dot style)
# ═══════════════════════════════════════════════════════════════════════════════
progress_bar() {
local percent=$1
local width=5
if ! [[ "$percent" =~ ^[0-9]+$ ]]; then
printf "○○○○○"
return
fi
local filled=$((percent * width / 100))
[[ $filled -gt $width ]] && filled=$width
[[ $filled -lt 0 ]] && filled=0
local empty=$((width - filled))
local bar=""
for ((i=0; i<filled; i++)); do bar+="●"; done
for ((i=0; i<empty; i++)); do bar+="○"; done
printf "%s" "$bar"
}
# Get color based on percentage
get_usage_color() {
local pct=$1
if ! [[ "$pct" =~ ^[0-9]+$ ]]; then
echo "$FG_CTX"
return
fi
if [[ $pct -ge 80 ]]; then
echo "$FG_CRIT"
elif [[ $pct -ge 50 ]]; then
echo "$FG_WARN"
else
echo "$FG_OK"
fi
}
# Generate bars with colors
bar_ctx=$(progress_bar "$context_pct")
bar_5h=$(progress_bar "$usage_5h")
bar_7d=$(progress_bar "$usage_7d")
color_ctx=$(get_usage_color "$context_pct")
color_5h=$(get_usage_color "$usage_5h")
color_7d=$(get_usage_color "$usage_7d")
# ═══════════════════════════════════════════════════════════════════════════════
# BUILD POWERLINE OUTPUT
# ═══════════════════════════════════════════════════════════════════════════════
# Segment 1: Model
printf "${BG_MODEL}${FG_MODEL} ${ICON_MODEL} %s " "$model"
printf "${BG_FOLDER}${FG_MODEL_SEP}${SEP}"
# Segment 2: Folder
printf "${BG_FOLDER}${FG_FOLDER} ${folder_icon} %s " "$folder"
# Segment 3: Branch (only if not on main)
if [[ -n "$show_branch" ]]; then
printf "${BG_BRANCH}${FG_FOLDER_SEP}${SEP}"
printf "${BG_BRANCH}${FG_BRANCH} ${ICON_GIT}${ICON_BRANCH} %s " "$branch_name"
printf "${BG_K8S}${FG_BRANCH_SEP}${SEP}"
else
printf "${BG_K8S}${FG_FOLDER_SEP}${SEP}"
fi
# Segment 4: Kubernetes
printf "${BG_K8S}${FG_K8S} ${ICON_K8S} %s " "$k8s_context"
printf "${BG_CTX}${FG_K8S_SEP}${SEP}"
# Segment 4: Context usage
printf "${BG_CTX}${FG_CTX} ${ICON_CTX} ${color_ctx}%s${FG_CTX} %s%% " "$bar_ctx" "$context_pct"
printf "${BG_5H}${FG_CTX_SEP}${SEP}"
# Segment 5: 5h usage
printf "${BG_5H}${FG_5H} ${ICON_5H} ${color_5h}%s${FG_5H} %s%% %s " "$bar_5h" "$usage_5h" "$reset_5h"
printf "${BG_7D}${FG_5H_SEP}${SEP}"
# Segment 6: 7d usage
printf "${BG_7D}${FG_7D} ${ICON_7D} ${color_7d}%s${FG_7D} %s%% %s " "$bar_7d" "$usage_7d" "$reset_7d"
printf "${RST}${FG_7D_SEP}${SEP}${RST}"