Created
February 9, 2026 06:29
-
-
Save armujahid/3b5d4fa0de358e9bc3d472015e0fa3ba to your computer and use it in GitHub Desktop.
CC statusline (Generated from https://www.reddit.com/r/ClaudeCode/comments/1qycvdu/comment/o42s7bj)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # Claude Code StatusLine Script (Bash port of PowerShell version) | |
| # Line 1: Model | tokens used/total | % used <fullused> | % remain <fullremain> | thinking: on/off | |
| # Line 2: current: <progressbar> % | weekly: <progressbar> % | extra: <progressbar> $used/$limit | |
| # Line 3: resets <time> | resets <datetime> | resets <date> | |
| set -f # disable globbing | |
| input=$(cat) | |
| if [ -z "$input" ]; then | |
| printf "Claude" | |
| exit 0 | |
| fi | |
| # ANSI colors matching oh-my-posh theme | |
| blue='\033[38;2;0;153;255m' | |
| orange='\033[38;2;255;176;85m' | |
| green='\033[38;2;0;160;0m' | |
| cyan='\033[38;2;46;149;153m' | |
| red='\033[38;2;255;85;85m' | |
| yellow='\033[38;2;230;200;0m' | |
| white='\033[38;2;220;220;220m' | |
| dim='\033[2m' | |
| reset='\033[0m' | |
| # Format token counts (e.g., 50k / 200k) | |
| format_tokens() { | |
| local num=$1 | |
| if [ "$num" -ge 1000000 ]; then | |
| awk "BEGIN {printf \"%.1fm\", $num / 1000000}" | |
| elif [ "$num" -ge 1000 ]; then | |
| awk "BEGIN {printf \"%.0fk\", $num / 1000}" | |
| else | |
| printf "%d" "$num" | |
| fi | |
| } | |
| # Format number with commas (e.g., 134,938) | |
| format_commas() { | |
| printf "%'d" "$1" | |
| } | |
| # Build a colored progress bar | |
| # Usage: build_bar <pct> <width> | |
| build_bar() { | |
| local pct=$1 | |
| local width=$2 | |
| [ "$pct" -lt 0 ] 2>/dev/null && pct=0 | |
| [ "$pct" -gt 100 ] 2>/dev/null && pct=100 | |
| local filled=$(( pct * width / 100 )) | |
| local empty=$(( width - filled )) | |
| # Color based on usage level | |
| local bar_color | |
| if [ "$pct" -ge 90 ]; then bar_color="$red" | |
| elif [ "$pct" -ge 70 ]; then bar_color="$yellow" | |
| elif [ "$pct" -ge 50 ]; then bar_color="$orange" | |
| else bar_color="$green" | |
| fi | |
| local filled_str="" empty_str="" | |
| for ((i=0; i<filled; i++)); do filled_str+="●"; done | |
| for ((i=0; i<empty; i++)); do empty_str+="○"; done | |
| printf "${bar_color}${filled_str}${dim}${empty_str}${reset}" | |
| } | |
| # ===== Extract data from JSON ===== | |
| model_name=$(echo "$input" | jq -r '.model.display_name // "Claude"') | |
| # Context window | |
| size=$(echo "$input" | jq -r '.context_window.context_window_size // 200000') | |
| [ "$size" -eq 0 ] 2>/dev/null && size=200000 | |
| # Token usage | |
| input_tokens=$(echo "$input" | jq -r '.context_window.current_usage.input_tokens // 0') | |
| cache_create=$(echo "$input" | jq -r '.context_window.current_usage.cache_creation_input_tokens // 0') | |
| cache_read=$(echo "$input" | jq -r '.context_window.current_usage.cache_read_input_tokens // 0') | |
| current=$(( input_tokens + cache_create + cache_read )) | |
| used_tokens=$(format_tokens $current) | |
| total_tokens=$(format_tokens $size) | |
| if [ "$size" -gt 0 ]; then | |
| pct_used=$(( current * 100 / size )) | |
| else | |
| pct_used=0 | |
| fi | |
| pct_remain=$(( 100 - pct_used )) | |
| used_comma=$(format_commas $current) | |
| remain_comma=$(format_commas $(( size - current ))) | |
| # Check thinking status | |
| thinking_on=false | |
| settings_path="$HOME/.claude/settings.json" | |
| if [ -f "$settings_path" ]; then | |
| thinking_val=$(jq -r '.alwaysThinkingEnabled // false' "$settings_path" 2>/dev/null) | |
| [ "$thinking_val" = "true" ] && thinking_on=true | |
| fi | |
| # ===== LINE 1: Model | tokens | % used | % remain | thinking ===== | |
| line1="" | |
| line1+="${blue}${model_name}${reset}" | |
| line1+=" ${dim}|${reset} " | |
| line1+="${orange}${used_tokens} / ${total_tokens}${reset}" | |
| line1+=" ${dim}|${reset} " | |
| line1+="${green}${pct_used}% used ${orange}${used_comma}${reset}" | |
| line1+=" ${dim}|${reset} " | |
| line1+="${cyan}${pct_remain}% remain ${blue}${remain_comma}${reset}" | |
| line1+=" ${dim}|${reset} " | |
| line1+="thinking: " | |
| if $thinking_on; then | |
| line1+="${orange}On${reset}" | |
| else | |
| line1+="${dim}Off${reset}" | |
| fi | |
| # ===== LINE 2 & 3: Usage limits with progress bars (cached) ===== | |
| cache_file="/tmp/claude/statusline-usage-cache.json" | |
| cache_max_age=60 # seconds between API calls | |
| mkdir -p /tmp/claude | |
| needs_refresh=true | |
| usage_data="" | |
| # Check cache | |
| if [ -f "$cache_file" ]; then | |
| cache_mtime=$(stat -c %Y "$cache_file" 2>/dev/null || stat -f %m "$cache_file" 2>/dev/null) | |
| now=$(date +%s) | |
| cache_age=$(( now - cache_mtime )) | |
| if [ "$cache_age" -lt "$cache_max_age" ]; then | |
| needs_refresh=false | |
| usage_data=$(cat "$cache_file" 2>/dev/null) | |
| fi | |
| fi | |
| # Fetch fresh data if cache is stale | |
| if $needs_refresh; then | |
| creds_path="$HOME/.claude/.credentials.json" | |
| if [ -f "$creds_path" ]; then | |
| token=$(jq -r '.claudeAiOauth.accessToken // empty' "$creds_path" 2>/dev/null) | |
| if [ -n "$token" ]; then | |
| response=$(curl -s --max-time 5 \ | |
| -H "Accept: application/json" \ | |
| -H "Content-Type: application/json" \ | |
| -H "Authorization: Bearer $token" \ | |
| -H "anthropic-beta: oauth-2025-04-20" \ | |
| -H "User-Agent: claude-code/2.1.34" \ | |
| "https://api.anthropic.com/api/oauth/usage" 2>/dev/null) | |
| if [ -n "$response" ] && echo "$response" | jq . >/dev/null 2>&1; then | |
| usage_data="$response" | |
| echo "$response" > "$cache_file" | |
| fi | |
| fi | |
| fi | |
| # Fall back to stale cache | |
| if [ -z "$usage_data" ] && [ -f "$cache_file" ]; then | |
| usage_data=$(cat "$cache_file" 2>/dev/null) | |
| fi | |
| fi | |
| # Format ISO reset time to compact local time | |
| # Usage: format_reset_time <iso_string> <style: time|datetime|date> | |
| format_reset_time() { | |
| local iso_str="$1" | |
| local style="$2" | |
| [ -z "$iso_str" ] || [ "$iso_str" = "null" ] && return | |
| # Parse ISO datetime and convert to local time | |
| local epoch | |
| epoch=$(date -d "$iso_str" +%s 2>/dev/null) | |
| [ -z "$epoch" ] && return | |
| case "$style" in | |
| time) date -d "@$epoch" +"%l:%M%P" | sed 's/^ //' ;; | |
| datetime) date -d "@$epoch" +"%b %-d, %l:%M%P" | sed 's/ / /g; s/^ //' ;; | |
| *) date -d "@$epoch" +"%b %-d" ;; | |
| esac | |
| } | |
| line2="" | |
| line3="" | |
| sep=" ${dim}|${reset} " | |
| if [ -n "$usage_data" ] && echo "$usage_data" | jq -e . >/dev/null 2>&1; then | |
| bar_width=10 | |
| # ---- 5-hour (current) ---- | |
| five_hour_pct=$(echo "$usage_data" | jq -r '.five_hour.utilization // 0' | awk '{printf "%.0f", $1}') | |
| five_hour_reset_iso=$(echo "$usage_data" | jq -r '.five_hour.resets_at // empty') | |
| five_hour_reset=$(format_reset_time "$five_hour_reset_iso" "time") | |
| five_hour_bar=$(build_bar "$five_hour_pct" "$bar_width") | |
| col1_bar="${white}current:${reset} ${five_hour_bar} ${cyan}${five_hour_pct}%${reset}" | |
| col1_reset="${white}resets ${five_hour_reset}${reset}" | |
| # ---- 7-day (weekly) ---- | |
| seven_day_pct=$(echo "$usage_data" | jq -r '.seven_day.utilization // 0' | awk '{printf "%.0f", $1}') | |
| seven_day_reset_iso=$(echo "$usage_data" | jq -r '.seven_day.resets_at // empty') | |
| seven_day_reset=$(format_reset_time "$seven_day_reset_iso" "datetime") | |
| seven_day_bar=$(build_bar "$seven_day_pct" "$bar_width") | |
| col2_bar="${white}weekly:${reset} ${seven_day_bar} ${cyan}${seven_day_pct}%${reset}" | |
| col2_reset="${white}resets ${seven_day_reset}${reset}" | |
| # ---- Extra usage ---- | |
| col3_bar="" | |
| col3_reset="" | |
| extra_enabled=$(echo "$usage_data" | jq -r '.extra_usage.is_enabled // false') | |
| if [ "$extra_enabled" = "true" ]; then | |
| extra_pct=$(echo "$usage_data" | jq -r '.extra_usage.utilization // 0' | awk '{printf "%.0f", $1}') | |
| extra_used=$(echo "$usage_data" | jq -r '.extra_usage.used_credits // 0' | awk '{printf "%.2f", $1/100}') | |
| extra_limit=$(echo "$usage_data" | jq -r '.extra_usage.monthly_limit // 0' | awk '{printf "%.0f", $1/100}') | |
| extra_bar=$(build_bar "$extra_pct" "$bar_width") | |
| # Next month 1st for reset date | |
| extra_reset=$(date -d "$(date +%Y-%m-01) +1 month" +"%b %-d" | tr '[:upper:]' '[:lower:]') | |
| col3_bar="${white}extra:${reset} ${extra_bar} ${cyan}\$${extra_used}/\$${extra_limit}${reset}" | |
| col3_reset="${white}resets ${extra_reset}${reset}" | |
| fi | |
| # Assemble line 2: bars row | |
| line2="${col1_bar}${sep}${col2_bar}" | |
| [ -n "$col3_bar" ] && line2+="${sep}${col3_bar}" | |
| # Assemble line 3: resets row | |
| line3="${col1_reset}${sep}${col2_reset}" | |
| [ -n "$col3_reset" ] && line3+="${sep}${col3_reset}" | |
| fi | |
| # Output all lines | |
| printf "%b" "$line1" | |
| [ -n "$line2" ] && printf "\n%b" "$line2" | |
| [ -n "$line3" ] && printf "\n%b" "$line3" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment