Created
March 16, 2026 16:13
-
-
Save anderssonjohan/d3a379a1f5f008e8a70ed7f0cc71d116 to your computer and use it in GitHub Desktop.
~/.claude/statusline_command.sh
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
| #!/usr/bin/env bash | |
| # Claude Code status line — enhanced with cost, git, color thresholds, rate limits | |
| input=$(cat) | |
| # --- Extract fields --- | |
| model=$(echo "$input" | jq -r '.model.display_name // "?"') | |
| cwd=$(echo "$input" | jq -r '.cwd // .workspace.current_dir // "?"') | |
| session_id=$(echo "$input" | jq -r '.session_id // ""') | |
| session_name=$(echo "$input" | jq -r '.session_name // empty') | |
| used_pct=$(echo "$input" | jq -r '.context_window.used_percentage // empty') | |
| vim_mode=$(echo "$input" | jq -r '.vim.mode // empty') | |
| cost_usd=$(echo "$input" | jq -r '.cost.total_cost_usd // empty') | |
| duration_ms=$(echo "$input" | jq -r '.cost.total_duration_ms // empty') | |
| lines_added=$(echo "$input" | jq -r '.cost.total_lines_added // 0') | |
| lines_removed=$(echo "$input" | jq -r '.cost.total_lines_removed // 0') | |
| # --- Colors (use $'\e' so escapes are resolved at assignment time) --- | |
| ESC=$'\e' | |
| reset="${ESC}[0m" | |
| dim="${ESC}[2m" | |
| bold="${ESC}[1m" | |
| green="${ESC}[32m" | |
| yellow="${ESC}[33m" | |
| red="${ESC}[31m" | |
| cyan="${ESC}[36m" | |
| magenta="${ESC}[35m" | |
| blue="${ESC}[34m" | |
| color_for_pct() { | |
| local pct=${1%.*} | |
| if [ "$pct" -lt 50 ] 2>/dev/null; then | |
| printf '%s' "$green" | |
| elif [ "$pct" -lt 70 ] 2>/dev/null; then | |
| printf '%s' "$green" | |
| elif [ "$pct" -lt 80 ] 2>/dev/null; then | |
| printf '%s' "$yellow" | |
| else | |
| printf '%s' "$red" | |
| fi | |
| } | |
| # --- Git info (cached for 5s) --- | |
| git_cache="/tmp/claude-statusline-git-$$" | |
| git_info="" | |
| if [ -d "$cwd/.git" ] || git -C "$cwd" rev-parse --git-dir >/dev/null 2>&1; then | |
| cache_file="/tmp/claude-statusline-git-$(echo "$cwd" | md5 -q 2>/dev/null || echo "$cwd" | md5sum 2>/dev/null | cut -d' ' -f1)" | |
| cache_age=999 | |
| if [ -f "$cache_file" ]; then | |
| cache_age=$(( $(date +%s) - $(stat -f%m "$cache_file" 2>/dev/null || stat -c%Y "$cache_file" 2>/dev/null || echo 0) )) | |
| fi | |
| if [ "$cache_age" -gt 5 ]; then | |
| branch=$(git -C "$cwd" --no-optional-locks symbolic-ref --short HEAD 2>/dev/null || git -C "$cwd" --no-optional-locks rev-parse --short HEAD 2>/dev/null || echo "") | |
| dirty="" | |
| if [ -n "$(git -C "$cwd" --no-optional-locks status --porcelain 2>/dev/null | head -1)" ]; then | |
| dirty="*" | |
| fi | |
| echo "${branch}${dirty}" > "$cache_file" 2>/dev/null | |
| fi | |
| git_info=$(cat "$cache_file" 2>/dev/null) | |
| fi | |
| # --- Rate limits (cached for 60s) --- | |
| rate_info="" | |
| rate_cache="/tmp/claude-statusline-rate" | |
| rate_cache_age=999 | |
| if [ -f "$rate_cache" ]; then | |
| rate_cache_age=$(( $(date +%s) - $(stat -f%m "$rate_cache" 2>/dev/null || stat -c%Y "$rate_cache" 2>/dev/null || echo 0) )) | |
| fi | |
| if [ "$rate_cache_age" -gt 60 ]; then | |
| # Try to get OAuth token from credentials file | |
| creds_file="$HOME/.claude/.credentials.json" | |
| if [ -f "$creds_file" ]; then | |
| token=$(jq -r '.oauth_tokens // {} | to_entries[0].value.accessToken // empty' "$creds_file" 2>/dev/null) | |
| if [ -n "$token" ]; then | |
| usage_json=$(curl -sf -m 3 -H "Authorization: Bearer $token" "https://api.anthropic.com/api/oauth/usage" 2>/dev/null) | |
| if [ -n "$usage_json" ]; then | |
| echo "$usage_json" > "$rate_cache" 2>/dev/null | |
| fi | |
| fi | |
| fi | |
| fi | |
| if [ -f "$rate_cache" ]; then | |
| five_hr=$(jq -r '.five_hour.utilization_percentage // empty' "$rate_cache" 2>/dev/null) | |
| daily=$(jq -r '.daily.utilization_percentage // empty' "$rate_cache" 2>/dev/null) | |
| if [ -n "$five_hr" ]; then | |
| five_hr_int=${five_hr%.*} | |
| rate_color=$(color_for_pct "$five_hr_int") | |
| rate_info="${rate_color}5h:${five_hr_int}%${reset}" | |
| if [ -n "$daily" ]; then | |
| daily_int=${daily%.*} | |
| daily_color=$(color_for_pct "$daily_int") | |
| rate_info="${rate_info} ${daily_color}day:${daily_int}%${reset}" | |
| fi | |
| fi | |
| fi | |
| # --- Format duration --- | |
| duration_str="" | |
| if [ -n "$duration_ms" ] && [ "$duration_ms" != "null" ] && [ "$duration_ms" -gt 0 ] 2>/dev/null; then | |
| total_secs=$(( duration_ms / 1000 )) | |
| if [ "$total_secs" -ge 3600 ]; then | |
| hrs=$(( total_secs / 3600 )) | |
| mins=$(( (total_secs % 3600) / 60 )) | |
| duration_str="${hrs}h${mins}m" | |
| elif [ "$total_secs" -ge 60 ]; then | |
| mins=$(( total_secs / 60 )) | |
| secs=$(( total_secs % 60 )) | |
| duration_str="${mins}m${secs}s" | |
| else | |
| duration_str="${total_secs}s" | |
| fi | |
| fi | |
| # --- Line 1: git branch + directory (clickable) + model --- | |
| osc_open="${ESC}]8;;" | |
| osc_close="${ESC}\\" | |
| dir_link="${osc_open}file://${cwd}${osc_close}${dim}${cwd}${reset}${osc_open}${osc_close}" | |
| git_part="" | |
| if [ -n "$git_info" ]; then | |
| git_part="${magenta} ${git_info}${reset} " | |
| fi | |
| line1="${git_part}${dir_link} ${bold}${model}${reset}" | |
| # --- Line 2: context bar (color-coded) + cost + duration + churn --- | |
| if [ -n "$used_pct" ]; then | |
| used_int=${used_pct%.*} | |
| bar_color=$(color_for_pct "$used_int") | |
| filled=$(( used_int / 5 )) | |
| empty=$(( 20 - filled )) | |
| bar="" | |
| for i in $(seq 1 $filled); do bar="${bar}█"; done | |
| for i in $(seq 1 $empty); do bar="${bar}░"; done | |
| line2="${bar_color}ctx ${bar} ${used_pct}%${reset}" | |
| else | |
| line2="${dim}ctx —${reset}" | |
| fi | |
| # Append cost | |
| if [ -n "$cost_usd" ] && [ "$cost_usd" != "null" ]; then | |
| # Format to 2 decimal places | |
| cost_fmt=$(printf '%.2f' "$cost_usd" 2>/dev/null || echo "$cost_usd") | |
| line2="${line2} ${cyan}\$${cost_fmt}${reset}" | |
| fi | |
| # Append duration | |
| if [ -n "$duration_str" ]; then | |
| line2="${line2} ${dim}${duration_str}${reset}" | |
| fi | |
| # Append code churn | |
| if [ "$lines_added" -gt 0 ] || [ "$lines_removed" -gt 0 ] 2>/dev/null; then | |
| line2="${line2} ${green}+${lines_added}${reset}${red}-${lines_removed}${reset}" | |
| fi | |
| # --- Line 3: session link + rate limits + vim mode --- | |
| if [ -n "$session_id" ]; then | |
| session_url="https://claude.ai/code/sessions/${session_id}" | |
| label="${session_name:-session}" | |
| session_link="${osc_open}${session_url}${osc_close}${blue}${label}${reset}${osc_open}${osc_close}" | |
| else | |
| session_link="${dim}no session${reset}" | |
| fi | |
| line3="${session_link}" | |
| if [ -n "$rate_info" ]; then | |
| line3="${line3} ${rate_info}" | |
| fi | |
| if [ -n "$vim_mode" ]; then | |
| line3="${line3} ${dim}vim:${vim_mode}${reset}" | |
| fi | |
| printf '%s\n%s\n%s\n' "$line1" "$line2" "$line3" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment