Last active
June 13, 2026 05:39
-
-
Save QinMing/2a7861418cc0e80b1f0c72eef136d309 to your computer and use it in GitHub Desktop.
Claude Code Status Line Customization
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 command script | |
| # Gist link: https://gist.github.com/QinMing/2a7861418cc0e80b1f0c72eef136d309 | |
| # When committing changes to this file, also update the gist. | |
| # Read JSON input from stdin | |
| input=$(cat) | |
| # --------------------------------------------------------------------------- | |
| # Extract all fields from JSON in a single jq call | |
| # --------------------------------------------------------------------------- | |
| eval "$(echo "$input" | jq -r ' | |
| @sh "cwd=\(.workspace.current_dir // "")", | |
| @sh "used_pct=\(.context_window.used_percentage // "")", | |
| @sh "ctx_size=\(.context_window.context_window_size // "")", | |
| @sh "ctx_used=\((.context_window.current_usage | (.input_tokens // 0) + (.output_tokens // 0) + (.cache_creation_input_tokens // 0) + (.cache_read_input_tokens // 0)) // "")", | |
| @sh "model_name=\(.model.display_name // "")", | |
| @sh "git_worktree=\(.workspace.git_worktree // "")" | |
| ')" | |
| user=$(whoami) | |
| host=$(hostname -s) | |
| # --------------------------------------------------------------------------- | |
| # ANSI color palette (all colors defined here) | |
| # --------------------------------------------------------------------------- | |
| C_RESET="\033[0m" | |
| C_DIM_GREY="\033[38;5;240m" | |
| C_BRIGHT_CYAN="\033[1;36m" | |
| C_BOLD_BLUE="\033[1;34m" | |
| C_PAREN="\033[38;5;240m" # grey for informationless delimiters () [] | |
| C_BRANCH="\033[38;2;210;153;34m" # GitHub #d29922 | |
| C_UNTRACKED="\033[38;5;139m" # mauve for untracked line count | |
| C_DIM_WHITE="\033[2;37m" | |
| C_GH_GREEN="\033[38;5;71m" # GitHub #3fb950 | |
| C_GH_RED="\033[38;5;203m" # GitHub #f85149 | |
| C_SUBDIR="\033[38;5;67m" # muted steel blue for subdirs below repo root | |
| # Gradient endpoints for progress bar (GitHub palette, passed to awk) | |
| GRAD_GREEN="63,185,80" # #3fb950 | |
| GRAD_YELLOW="210,153,34" # #d29922 | |
| GRAD_RED="248,81,73" # #f85149 | |
| # --------------------------------------------------------------------------- | |
| # Path coloring: dim prefix, bright repo, steel-blue subdirs, grey slashes | |
| # Derives dim prefix from git toplevel — works for any repo/worktree location. | |
| # --------------------------------------------------------------------------- | |
| # Detect git repo root (works the same for worktrees) | |
| git_toplevel="" | |
| if git -C "$cwd" rev-parse --show-toplevel &>/dev/null; then | |
| git_toplevel=$(git -C "$cwd" rev-parse --show-toplevel) | |
| fi | |
| # Colorize /path/segments: grey slashes + per-segment color | |
| _color_segs() { | |
| local p="${1#/}" c="$2" out="" | |
| while [ -n "$p" ]; do | |
| out+="${C_DIM_GREY}/${c}${p%%/*}" | |
| [[ "$p" == */* ]] && p="${p#*/}" || p="" | |
| done | |
| printf '%b' "$out" | |
| } | |
| if [ -n "$git_toplevel" ]; then | |
| dim_prefix=$(dirname "$git_toplevel") | |
| repo_name=$(basename "$git_toplevel") | |
| subdir_path="${cwd#"$git_toplevel"}" | |
| colored_sub=$(_color_segs "$subdir_path" "$C_SUBDIR") | |
| if [ "$dim_prefix" = "/" ]; then | |
| cwd_display=$(printf '%b' "${C_DIM_GREY}/${C_BRIGHT_CYAN}${repo_name}${colored_sub}${C_RESET}") | |
| else | |
| cwd_display=$(printf '%b' "${C_DIM_GREY}${dim_prefix}/${C_BRIGHT_CYAN}${repo_name}${colored_sub}${C_RESET}") | |
| fi | |
| else | |
| # Not in a git repo — show full path in bright cyan | |
| cwd_display=$(printf '%b' "${C_BRIGHT_CYAN}${cwd}${C_RESET}") | |
| fi | |
| # --------------------------------------------------------------------------- | |
| # Git branch and line-based dirty summary | |
| # Purple counts lines in untracked files. | |
| # Green/red come from `git diff --numstat HEAD`, so rename detection stays enabled | |
| # and pure renames collapse to 0 added / 0 deleted lines once staged. | |
| # --------------------------------------------------------------------------- | |
| git_info="" | |
| if [ -n "$git_toplevel" ]; then | |
| branch=$(git -C "$cwd" symbolic-ref --short HEAD 2>/dev/null \ | |
| || git -C "$cwd" rev-parse --short HEAD 2>/dev/null) | |
| untracked_info="" | |
| untracked_files=$(git -C "$cwd" --no-optional-locks ls-files --others --exclude-standard 2>/dev/null) | |
| if [ -n "$untracked_files" ]; then | |
| untracked_lines=$(echo "$untracked_files" | tr '\n' '\0' | xargs -0 wc -l 2>/dev/null | tail -1 | awk '{print $1+0}') | |
| if [ "$untracked_lines" -gt 0 ]; then | |
| untracked_info=$(printf " ${C_UNTRACKED}+%s${C_RESET}" "$untracked_lines") | |
| fi | |
| fi | |
| diff_info="" | |
| numstat=$(git -C "$cwd" --no-optional-locks diff --numstat HEAD 2>/dev/null) | |
| if [ -n "$numstat" ]; then | |
| read additions deletions <<< "$(echo "$numstat" | awk '{a+=$1; d+=$2} END {print a+0, d+0}')" | |
| if [ "$additions" -gt 0 ] || [ "$deletions" -gt 0 ]; then | |
| diff_info=$(printf " ${C_GH_GREEN}+%s${C_RESET} ${C_GH_RED}-%s${C_RESET}" "$additions" "$deletions") | |
| fi | |
| fi | |
| # Hide branch name when it matches the worktree directory name | |
| branch_label="$branch" | |
| [ "$branch" = "$repo_name" ] && branch_label="" | |
| [ -n "$branch_label" ] && branch_label="${C_BRANCH}${branch_label}${C_RESET}" | |
| inner="${branch_label}${untracked_info}${diff_info}" | |
| inner="${inner# }" | |
| [ -n "$inner" ] && git_info=$(printf " ${C_PAREN}(${C_RESET}%b${C_PAREN})${C_RESET}" "$inner") | |
| fi | |
| # --------------------------------------------------------------------------- | |
| # Context window progress bar | |
| # --------------------------------------------------------------------------- | |
| context_info="" | |
| if [ -n "$used_pct" ]; then | |
| used_pct_int=$(printf "%.0f" "$used_pct") | |
| # Braille bar: 13 chars × 8 levels = 104 steps → ~1% precision | |
| bar_width=13 | |
| total_eighths=$(echo "$used_pct $bar_width" | awk '{v=$1*$2*8/100; printf "%d",int(v+0.5)}') | |
| max_eighths=$(( bar_width * 8 )) | |
| [ "$total_eighths" -gt "$max_eighths" ] && total_eighths=$max_eighths | |
| [ "$total_eighths" -lt 0 ] && total_eighths=0 | |
| full_cells=$(( total_eighths / 8 )) | |
| remainder=$(( total_eighths % 8 )) | |
| has_partial=0 | |
| [ "$remainder" -gt 0 ] && has_partial=1 | |
| empty_count=$(( bar_width - full_cells - has_partial )) | |
| [ "$empty_count" -lt 0 ] && empty_count=0 | |
| # Percentage label (shown inside or outside bar) | |
| pct_label="${used_pct_int}%" | |
| label_len=${#pct_label} | |
| space_needed=$(( label_len + 1 )) | |
| # Build gradient bar + token suffix in a single awk call | |
| context_and_tokens=$(awk \ | |
| -v full="$full_cells" -v rem="$remainder" \ | |
| -v empty_n="$empty_count" -v has_p="$has_partial" \ | |
| -v n="$bar_width" -v label="$pct_label" \ | |
| -v sp_need="$space_needed" \ | |
| -v grad_g="$GRAD_GREEN" -v grad_y="$GRAD_YELLOW" -v grad_r="$GRAD_RED" \ | |
| -v ctx_used="$ctx_used" -v ctx_total="$ctx_size" ' | |
| BEGIN { | |
| esc = sprintf("%c", 27) | |
| dim = esc "[38;5;240m" | |
| rst = esc "[0m" | |
| # Parse gradient endpoints | |
| split(grad_g, gn, ","); split(grad_y, yl, ","); split(grad_r, rd, ",") | |
| # Precompute gradient colors: green → yellow → red | |
| for (i = 0; i < n; i++) { | |
| frac = (n > 1) ? i / (n - 1) : 0 | |
| if (frac <= 0.5) { | |
| f = frac * 2 | |
| r = int(gn[1] + (yl[1]-gn[1])*f + 0.5) | |
| g = int(gn[2] + (yl[2]-gn[2])*f + 0.5) | |
| b = int(gn[3] + (yl[3]-gn[3])*f + 0.5) | |
| } else { | |
| f = (frac - 0.5) * 2 | |
| r = int(yl[1] + (rd[1]-yl[1])*f + 0.5) | |
| g = int(yl[2] + (rd[2]-yl[2])*f + 0.5) | |
| b = int(yl[3] + (rd[3]-yl[3])*f + 0.5) | |
| } | |
| gc[i] = esc sprintf("[38;2;%d;%d;%dm", r, g, b) | |
| } | |
| # Braille partial chars by remainder (1-7) | |
| br[1]="⡀"; br[2]="⡄"; br[3]="⡆"; br[4]="⡇" | |
| br[5]="⣇"; br[6]="⣧"; br[7]="⣷" | |
| # Filled cells with per-cell gradient | |
| bar = "" | |
| for (i = 0; i < full; i++) bar = bar gc[i] "⣿" | |
| # Partial cell | |
| if (has_p && rem > 0) bar = bar gc[full] br[rem] | |
| # Label color = gradient at current fill edge | |
| fe = full + has_p - 1 | |
| if (fe < 0) fe = 0 | |
| if (fe >= n) fe = n - 1 | |
| lc = gc[fe] | |
| if (empty_n >= sp_need) { | |
| # Right-align: [⣿⡄⣀⣀⣀⣀⣀⣀⣀ 10%] | |
| remaining = empty_n - sp_need | |
| for (i = 0; i < remaining; i++) bar = bar dim "⣀" | |
| bar = bar " " lc label | |
| printf " %s[%s%s%s]%s", dim, rst, bar, dim, rst | |
| } else { | |
| for (i = 0; i < empty_n; i++) bar = bar dim "⣀" | |
| printf " %s[%s%s%s]%s %s%s%s", dim, rst, bar, dim, rst, lc, label, rst | |
| } | |
| # Token count suffix (same color as percentage label) | |
| if (ctx_used > 0 || ctx_total > 0) { | |
| if (ctx_used >= 1000000) u = sprintf("%.1fM", ctx_used/1000000) | |
| else if (ctx_used >= 1000) u = sprintf("%.0fk", ctx_used/1000) | |
| else u = sprintf("%d", ctx_used) | |
| if (ctx_total >= 1000000) t = sprintf("%.0fM", ctx_total/1000000) | |
| else if (ctx_total >= 1000) t = sprintf("%.0fk", ctx_total/1000) | |
| else t = sprintf("%d", ctx_total) | |
| # Dim the "/total" part: same hue but with ANSI dim attribute | |
| dim_lc = esc "[2m" lc | |
| printf " %s%s%s/%s%s", lc, u, dim_lc, t, rst | |
| } | |
| }') | |
| context_info="$context_and_tokens" | |
| fi | |
| # --------------------------------------------------------------------------- | |
| # Model name (muted/dim style) | |
| # --------------------------------------------------------------------------- | |
| model_info="" | |
| if [ -n "$model_name" ]; then | |
| model_info=$(printf " ${C_DIM_WHITE}%s${C_RESET}" "$model_name") | |
| fi | |
| # --------------------------------------------------------------------------- | |
| # Assemble the status line | |
| # --------------------------------------------------------------------------- | |
| printf "${C_BOLD_BLUE}%s@%s${C_RESET}%s%s\n" "$user" "$host" "$model_info" "$context_info" | |
| printf "%s%s\n" "$cwd_display" "$git_info" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment