Skip to content

Instantly share code, notes, and snippets.

@catkins
Last active January 18, 2026 23:26
Show Gist options
  • Select an option

  • Save catkins/72455a9fed6099952c8a8c938149a726 to your computer and use it in GitHub Desktop.

Select an option

Save catkins/72455a9fed6099952c8a8c938149a726 to your computer and use it in GitHub Desktop.
Claude Code Statusline

Fancy Claude statusline

CleanShot 2026-01-09 at 10 22 57@2x

Requirements

Usage

Copy the statusline.sh script in this gist to ~/.claude and make it executable

chmod +x ~/.claude/statusline.sh

Update the statusline in your claude config

{
  "$schema": "https://json.schemastore.org/claude-code-settings.json",

  // ...
  
  // add the following snippet, with the full path to your statusline.sh
  "statusLine": {
    "type": "command",
    "command": "/Users/catkins/.claude/statusline.sh"
  }
}
#!/bin/bash
# Powerline/Nerd Font symbols (UTF-8 hex bytes)
SEP=$'\xee\x82\xb4' # U+E0B4 rounded powerline
SEP_THIN=$'\xee\x82\xb5' # U+E0B5 thin separator
# Nerd Font icons (UTF-8 hex bytes)
ICON_BOLT=$'\xef\x83\xa7' # U+F0E7 bolt
ICON_FOLDER=$'\xef\x81\xbc' # U+F07C folder
ICON_CHART=$'\xef\x87\xbe' # U+F1FE chart
ICON_DOLLAR=$'\xef\x85\x95' # U+F155 dollar
ICON_CLOCK=$'\xef\x80\x97' # U+F017 clock
ICON_PENCIL=$'\xef\x81\x84' # U+F044 pencil
ICON_BRANCH=$'\xef\x90\x98' # U+E0A0 git branch
# ANSI color codes (foreground/background)
RESET='\033[0m'
BOLD='\033[1m'
# Color palette for powerline segments
BG_PURPLE='\033[48;5;141m'
FG_PURPLE='\033[38;5;141m'
FG_ON_PURPLE='\033[38;5;235m'
BG_BLUE='\033[48;5;75m'
FG_BLUE='\033[38;5;75m'
FG_ON_BLUE='\033[38;5;235m'
BG_GREEN='\033[48;5;150m'
FG_GREEN='\033[38;5;150m'
FG_ON_GREEN='\033[38;5;235m'
BG_YELLOW='\033[48;5;222m'
FG_YELLOW='\033[38;5;222m'
FG_ON_YELLOW='\033[38;5;235m'
BG_ORANGE='\033[48;5;216m'
FG_ORANGE='\033[38;5;216m'
FG_ON_ORANGE='\033[38;5;235m'
BG_RED='\033[48;5;210m'
FG_RED='\033[38;5;210m'
FG_ON_RED='\033[38;5;235m'
BG_CYAN='\033[48;5;117m'
FG_CYAN='\033[38;5;117m'
FG_ON_CYAN='\033[38;5;235m'
BG_PINK='\033[48;5;218m'
FG_PINK='\033[38;5;218m'
FG_ON_PINK='\033[38;5;235m'
# Read JSON input once
input=$(cat)
# Helper functions for common extractions
get_model_name() { echo "$input" | jq -r '.model.display_name'; }
get_current_dir() { echo "$input" | jq -r '.workspace.current_dir'; }
get_project_dir() { echo "$input" | jq -r '.workspace.project_dir'; }
get_cost() { echo "$input" | jq -r '.cost.total_cost_usd'; }
get_duration() { echo "$input" | jq -r '.cost.total_duration_ms'; }
get_lines_added() { echo "$input" | jq -r '.cost.total_lines_added'; }
get_lines_removed() { echo "$input" | jq -r '.cost.total_lines_removed'; }
get_context_size() { echo "$input" | jq -r '.context_window.context_window_size'; }
get_current_usage() { echo "$input" | jq '.context_window.current_usage'; }
get_git_branch() {
local dir=$(get_current_dir)
if [[ -d "$dir" ]]; then
git -C "$dir" rev-parse --abbrev-ref HEAD 2>/dev/null
fi
}
# Powerline segment builder
# Usage: segment "bg_color" "fg_color" "fg_for_sep" "next_bg" "content"
segment() {
local bg="$1"
local fg="$2"
local fg_sep="$3"
local next_bg="$4"
local content="$5"
if [[ -z "$content" ]]; then
return
fi
# Print segment with content
printf "%b%b%b %s %b" "$bg" "$fg" "$BOLD" "$content" "$RESET"
# Print separator to next segment
if [[ -z "$next_bg" ]]; then
# Last segment - separator to transparent background
printf "%b%s%b" "$fg_sep" "$SEP" "$RESET"
else
# Separator to next colored segment
printf "%b%b%s%b" "$next_bg" "$fg_sep" "$SEP" "$RESET"
fi
}
format_model() {
local model=$(get_model_name)
echo "${ICON_BOLT} ${model}"
}
format_directory() {
local dir=$(get_current_dir)
echo "${ICON_FOLDER} ${dir##*/}"
}
format_git_branch() {
local branch=$(get_git_branch)
if [[ -n "$branch" ]]; then
echo "${ICON_BRANCH} ${branch}"
else
echo ""
fi
}
format_cost() {
local cost=$(get_cost)
if [[ "$cost" == "null" || -z "$cost" ]]; then
echo ""
else
printf "%s \$%.3f" "$ICON_DOLLAR" "$cost"
fi
}
format_duration() {
local duration=$(get_duration)
if [[ "$duration" == "null" || -z "$duration" ]]; then
echo ""
else
local seconds=$((duration / 1000))
if [[ $seconds -lt 60 ]]; then
echo "${ICON_CLOCK} ${seconds}s"
else
local minutes=$((seconds / 60))
local remaining_seconds=$((seconds % 60))
if [[ $remaining_seconds -eq 0 ]]; then
echo "${ICON_CLOCK} ${minutes}m"
else
echo "${ICON_CLOCK} ${minutes}m${remaining_seconds}s"
fi
fi
fi
}
format_lines() {
local added=$(get_lines_added)
local removed=$(get_lines_removed)
local result=""
if [[ "$added" != "null" && "$added" -gt 0 ]]; then
result+="+${added}"
fi
if [[ "$removed" != "null" && "$removed" -gt 0 ]]; then
[[ -n "$result" ]] && result+=" "
result+="-${removed}"
fi
if [[ -n "$result" ]]; then
echo "${ICON_PENCIL} ${result}"
else
echo ""
fi
}
get_context_percentage() {
local context_size=$(get_context_size)
local usage=$(get_current_usage)
if [[ "$context_size" == "null" || -z "$context_size" || "$context_size" -eq 0 ]]; then
echo ""
return
fi
if [[ "$usage" == "null" ]]; then
echo "0"
return
fi
local input_tokens=$(echo "$usage" | jq -r '.input_tokens // 0')
local cache_create=$(echo "$usage" | jq -r '.cache_creation_input_tokens // 0')
local cache_read=$(echo "$usage" | jq -r '.cache_read_input_tokens // 0')
local used=$((input_tokens + cache_create + cache_read))
echo $((used * 100 / context_size))
}
format_context() {
local context_size=$(get_context_size)
local usage=$(get_current_usage)
if [[ "$context_size" == "null" || -z "$context_size" || "$context_size" -eq 0 ]]; then
echo ""
return
fi
if [[ "$usage" == "null" ]]; then
echo "${ICON_CHART} 0% 0K"
return
fi
local input_tokens=$(echo "$usage" | jq -r '.input_tokens // 0')
local cache_create=$(echo "$usage" | jq -r '.cache_creation_input_tokens // 0')
local cache_read=$(echo "$usage" | jq -r '.cache_read_input_tokens // 0')
local used=$((input_tokens + cache_create + cache_read))
local used_k=$((used / 1000))
local percentage=$((used * 100 / context_size))
echo "${ICON_CHART} ${percentage}% ${used_k}K"
}
# Build the status line
output=""
# Model segment (purple)
model=$(format_model)
if [[ -n "$model" ]]; then
output+="$(segment "$BG_PURPLE" "$FG_ON_PURPLE" "$FG_PURPLE" "$BG_BLUE" "$model")"
fi
# Directory segment (blue)
directory=$(format_directory)
git_branch=$(format_git_branch)
context=$(format_context)
context_pct=$(get_context_percentage)
# Determine context segment colors based on percentage
if [[ -n "$context_pct" && "$context_pct" -gt 80 ]]; then
CTX_BG="$BG_RED"
CTX_FG="$FG_ON_RED"
CTX_FG_SEP="$FG_RED"
else
CTX_BG="$BG_GREEN"
CTX_FG="$FG_ON_GREEN"
CTX_FG_SEP="$FG_GREEN"
fi
if [[ -n "$directory" ]]; then
if [[ -n "$git_branch" ]]; then
output+="$(segment "$BG_BLUE" "$FG_ON_BLUE" "$FG_BLUE" "$BG_PINK" "$directory")"
else
output+="$(segment "$BG_BLUE" "$FG_ON_BLUE" "$FG_BLUE" "$CTX_BG" "$directory")"
fi
fi
# Git branch segment (pink)
if [[ -n "$git_branch" ]]; then
output+="$(segment "$BG_PINK" "$FG_ON_PINK" "$FG_PINK" "$CTX_BG" "$git_branch")"
fi
# Context segment (green or red if >80%)
if [[ -n "$context" ]]; then
output+="$(segment "$CTX_BG" "$CTX_FG" "$CTX_FG_SEP" "$BG_YELLOW" "$context")"
fi
# Cost segment (yellow)
cost=$(format_cost)
if [[ -n "$cost" ]]; then
if [[ -n "$(format_duration)" ]]; then
output+="$(segment "$BG_YELLOW" "$FG_ON_YELLOW" "$FG_YELLOW" "$BG_ORANGE" "$cost")"
else
if [[ -n "$(format_lines)" ]]; then
output+="$(segment "$BG_YELLOW" "$FG_ON_YELLOW" "$FG_YELLOW" "$BG_CYAN" "$cost")"
else
output+="$(segment "$BG_YELLOW" "$FG_ON_YELLOW" "$FG_YELLOW" "" "$cost")"
fi
fi
fi
# Duration segment (orange)
duration=$(format_duration)
if [[ -n "$duration" ]]; then
if [[ -n "$(format_lines)" ]]; then
output+="$(segment "$BG_ORANGE" "$FG_ON_ORANGE" "$FG_ORANGE" "$BG_CYAN" "$duration")"
else
output+="$(segment "$BG_ORANGE" "$FG_ON_ORANGE" "$FG_ORANGE" "" "$duration")"
fi
fi
# Lines changed segment (cyan)
lines=$(format_lines)
if [[ -n "$lines" ]]; then
output+="$(segment "$BG_CYAN" "$FG_ON_CYAN" "$FG_CYAN" "" "$lines")"
fi
printf "%s \n" "$output"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment