Created
May 27, 2026 13:48
-
-
Save junetech/1290db596796d8646766eae365ee95af to your computer and use it in GitHub Desktop.
Claude Code statusLine with context % and rate limits
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 statusLine command (POSIX) | |
| # Format: <shell> user@host:/path (Model, effort) {ctx: NNN%; NNNk} [5h NNN% | 7d NNN%] | |
| # Input: JSON via stdin (Claude Code statusLine protocol) | |
| # Requires: jq on PATH (install: apt install jq / dnf install jq / brew install jq / pacman -S jq) | |
| # Setup: register in ~/.claude/settings.json: | |
| # "statusLine": { | |
| # "type": "command", | |
| # "command": "bash ~/.claude/statusline-posix.sh" | |
| # } | |
| input=$(cat) | |
| # ── cwd: prefer JSON field, fall back to $PWD ─────────────────────────────── | |
| cwd=$(printf '%s' "$input" | jq -r '.workspace.current_dir // empty') | |
| [ -z "$cwd" ] && cwd="$PWD" | |
| # Shorten $HOME prefix to ~ (standard shell convention) | |
| home_dir="$HOME" | |
| if [ -n "$home_dir" ] && [ "$home_dir" != "/" ]; then | |
| case "$cwd" in | |
| "$home_dir"|"$home_dir"/*) short_cwd="~${cwd#$home_dir}" ;; | |
| *) short_cwd="$cwd" ;; | |
| esac | |
| else | |
| short_cwd="$cwd" | |
| fi | |
| # ── Shell detection ────────────────────────────────────────────────────────── | |
| if [ -n "$BASH_VERSION" ]; then | |
| shell_label="bash" | |
| elif [ -n "$ZSH_VERSION" ]; then | |
| shell_label="zsh" | |
| elif [ -n "$FISH_VERSION" ]; then | |
| shell_label="fish" | |
| else | |
| shell_label="$(basename "${SHELL:-sh}")" | |
| fi | |
| # ── user@host ──────────────────────────────────────────────────────────────── | |
| user="${USER:-$(whoami)}" | |
| host="${HOSTNAME:-$(hostname -s 2>/dev/null)}" | |
| host="${host%%.*}" | |
| # ── Model: shorten display_name to drop leading "Claude " ──────────────────── | |
| model_raw=$(printf '%s' "$input" | jq -r '.model.display_name // empty') | |
| model_short="${model_raw#Claude }" | |
| # ── Effort level ───────────────────────────────────────────────────────────── | |
| effort=$(printf '%s' "$input" | jq -r '.effort.level // empty') | |
| # ── Context: used% and token count ─────────────────────────────────────────── | |
| ctx_pct_raw=$(printf '%s' "$input" | jq -r '.context_window.used_percentage // empty') | |
| ctx_part="" | |
| if [ -n "$ctx_pct_raw" ]; then | |
| ctx_pct_int=$(printf '%3.0f' "$ctx_pct_raw") | |
| ctx_k=$(printf '%s' "$input" | jq -r ' | |
| (.context_window.total_input_tokens // 0) as $t | | |
| if $t >= 1000 then "\(($t / 1000 | floor))k" else "\($t)" end') | |
| ctx_k=$(printf '%4s' "$ctx_k") | |
| ctx_part="{ctx: ${ctx_pct_int}%; ${ctx_k}}" | |
| fi | |
| # ── Rate limits ────────────────────────────────────────────────────────────── | |
| five_pct_raw=$(printf '%s' "$input" | jq -r '.rate_limits.five_hour.used_percentage // empty') | |
| week_pct_raw=$(printf '%s' "$input" | jq -r '.rate_limits.seven_day.used_percentage // empty') | |
| rate_part="" | |
| if [ -n "$five_pct_raw" ] || [ -n "$week_pct_raw" ]; then | |
| inner="" | |
| if [ -n "$five_pct_raw" ]; then | |
| five_pct_int=$(printf '%3.0f' "$five_pct_raw") | |
| inner="5h ${five_pct_int}%" | |
| fi | |
| if [ -n "$week_pct_raw" ]; then | |
| week_pct_int=$(printf '%3.0f' "$week_pct_raw") | |
| if [ -n "$inner" ]; then | |
| inner="${inner} | 7d ${week_pct_int}%" | |
| else | |
| inner="7d ${week_pct_int}%" | |
| fi | |
| fi | |
| rate_part="[${inner}]" | |
| fi | |
| # ── Compose output ─────────────────────────────────────────────────────────── | |
| # <shell> — magenta | |
| printf '\033[35m<%s>\033[0m ' "$shell_label" | |
| # user@host — bold green | |
| printf '\033[1;32m%s@%s\033[0m' "$user" "$host" | |
| # :/path — bold blue (colon is part of this segment) | |
| printf '\033[1;34m:%s\033[0m' "$short_cwd" | |
| # (Model, effort) — default color | |
| if [ -n "$model_short" ]; then | |
| if [ -n "$effort" ]; then | |
| printf ' (%s, %s)' "$model_short" "$effort" | |
| else | |
| printf ' (%s)' "$model_short" | |
| fi | |
| fi | |
| # [ctx: %% / k] — default color | |
| if [ -n "$ctx_part" ]; then | |
| printf ' %s' "$ctx_part" | |
| fi | |
| # [5h: %% | 7d: %%] — default color | |
| if [ -n "$rate_part" ]; then | |
| printf ' %s' "$rate_part" | |
| fi |
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 statusLine command (Win11) | |
| # Format: <shell> user@host:/path (Model, effort) {ctx: NNN%; NNNk} [5h NNN% | 7d NNN%] | |
| # Input: JSON via stdin (Claude Code statusLine protocol) | |
| # Requires: jq on PATH (install: winget install jqlang.jq / scoop install jq / choco install jq) | |
| # Setup: register in ~/.claude/settings.json: | |
| # "statusLine": { | |
| # "type": "command", | |
| # "command": "bash ~/.claude/statusline-win11.sh" | |
| # } | |
| input=$(cat) | |
| # ── cwd: prefer JSON field, fall back to $PWD ─────────────────────────────── | |
| cwd=$(printf '%s' "$input" | jq -r '.workspace.current_dir // empty') | |
| [ -z "$cwd" ] && cwd="$PWD" | |
| # Convert Windows path (C:\foo) to Unix-style (/c/foo) when running under Git Bash | |
| # jq returns the raw string from JSON; on Windows this may be a Windows path. | |
| if printf '%s' "$cwd" | grep -qE '^[A-Za-z]:\\'; then | |
| drive=$(printf '%s' "$cwd" | cut -c1 | tr '[:upper:]' '[:lower:]') | |
| rest=$(printf '%s' "$cwd" | cut -c3- | tr '\\' '/') | |
| cwd="/${drive}${rest}" | |
| fi | |
| # Shorten $HOME prefix to ~ (standard shell convention; avoids depending on $USER) | |
| # Use case+prefix-strip rather than ${var/#$home/~}: the latter triggers tilde | |
| # expansion in the replacement, putting $HOME back and making the substitution a no-op. | |
| home_dir="$HOME" | |
| if [ -n "$home_dir" ] && [ "$home_dir" != "/" ]; then | |
| case "$cwd" in | |
| "$home_dir"|"$home_dir"/*) short_cwd="~${cwd#$home_dir}" ;; | |
| *) short_cwd="$cwd" ;; | |
| esac | |
| else | |
| short_cwd="$cwd" | |
| fi | |
| # ── Shell detection ─────────────────────────────────────────────────────────── | |
| # On Windows, PSModulePath is a system-wide env var inherited into CMD sessions | |
| # too, so it produces false positives. Instead, walk the parent-process chain | |
| # via Cygwin/MSYS procfs (/proc/<pid>/exename, /proc/<pid>/ppid) and look for | |
| # the actual host exe. wmic was removed in Win11 24H2, so it is not used. | |
| # | |
| # Priority: | |
| # 1. MSYSTEM set → Git Bash / MSYS2 (this env var is Git-Bash-exclusive) | |
| # 2. procfs walk → pwsh.exe (PS 7+) | powershell.exe (PS 5) | cmd.exe | |
| # 3. Fallback to "CMD" if procfs walk exhausts without a match | |
| # 4. Linux/macOS: $BASH_VERSION / $ZSH_VERSION / $FISH_VERSION / $SHELL | |
| # Walk parent PIDs via Cygwin/MSYS procfs; echoes PS7, PS5, CMD, or nothing. | |
| _detect_parent_shell_proc() { | |
| local pid="$$" depth=0 exe ppid | |
| while [ "$depth" -lt 8 ] && [ -n "$pid" ] && [ "$pid" != "0" ]; do | |
| exe="" | |
| [ -r "/proc/$pid/exename" ] && read -r exe < "/proc/$pid/exename" | |
| case "$exe" in | |
| */pwsh.exe) printf 'PS7'; return ;; | |
| */powershell.exe) printf 'PS5'; return ;; | |
| */cmd.exe) printf 'CMD'; return ;; | |
| esac | |
| ppid="" | |
| [ -r "/proc/$pid/ppid" ] && read -r ppid < "/proc/$pid/ppid" | |
| [ -z "$ppid" ] || [ "$ppid" = "0" ] || [ "$ppid" = "$pid" ] && break | |
| pid="$ppid" | |
| depth=$((depth + 1)) | |
| done | |
| } | |
| if [ -n "$MSYSTEM" ]; then | |
| # Git Bash / MSYS2 — MSYSTEM is exclusively set by the MSYS2 runtime | |
| shell_label="$MSYSTEM" | |
| elif [ -n "$COMSPEC" ]; then | |
| # Windows host (CMD or PowerShell launched this bash); walk procfs for host | |
| _parent=$(_detect_parent_shell_proc) | |
| case "$_parent" in | |
| PS7) | |
| ps_ver=$(pwsh --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+' | head -1) | |
| shell_label="PS ${ps_ver:-7}" | |
| ;; | |
| PS5) | |
| ps_ver=$(powershell -NoProfile -Command '$PSVersionTable.PSVersion.ToString()' 2>/dev/null | tr -d '\r\n') | |
| shell_label="PS ${ps_ver:-5}" | |
| ;; | |
| *) | |
| # CMD, or procfs walk exhausted without finding a known host | |
| shell_label="CMD" | |
| ;; | |
| esac | |
| else | |
| # Non-Windows (Linux / macOS) | |
| if [ -n "$BASH_VERSION" ]; then | |
| shell_label="bash" | |
| elif [ -n "$ZSH_VERSION" ]; then | |
| shell_label="zsh" | |
| elif [ -n "$FISH_VERSION" ]; then | |
| shell_label="fish" | |
| else | |
| shell_label="$(basename "${SHELL:-sh}")" | |
| fi | |
| fi | |
| # ── user@host ──────────────────────────────────────────────────────────────── | |
| user="${USER:-$(whoami)}" | |
| # $HOSTNAME may not be exported in all Git Bash sessions; fall back to hostname cmd | |
| host="${HOSTNAME:-$(hostname -s 2>/dev/null)}" | |
| # Strip any domain suffix (keep only the short hostname) | |
| host="${host%%.*}" | |
| # ── Model: shorten display_name to drop leading "Claude " ──────────────────── | |
| # "Claude Opus 4.5" → "Opus 4.5" | |
| model_raw=$(printf '%s' "$input" | jq -r '.model.display_name // empty') | |
| model_short="${model_raw#Claude }" | |
| # ── Effort level ───────────────────────────────────────────────────────────── | |
| effort=$(printf '%s' "$input" | jq -r '.effort.level // empty') | |
| # ── Context: used% and token count ─────────────────────────────────────────── | |
| ctx_pct_raw=$(printf '%s' "$input" | jq -r '.context_window.used_percentage // empty') | |
| ctx_part="" | |
| if [ -n "$ctx_pct_raw" ]; then | |
| ctx_pct_int=$(printf '%3.0f' "$ctx_pct_raw") | |
| ctx_k=$(printf '%s' "$input" | jq -r ' | |
| (.context_window.total_input_tokens // 0) as $t | | |
| if $t >= 1000 then "\(($t / 1000 | floor))k" else "\($t)" end') | |
| ctx_k=$(printf '%4s' "$ctx_k") | |
| ctx_part="{ctx: ${ctx_pct_int}%; ${ctx_k}}" | |
| fi | |
| # ── Rate limits ─────────────────────────────────────────────────────────────── | |
| five_pct_raw=$(printf '%s' "$input" | jq -r '.rate_limits.five_hour.used_percentage // empty') | |
| week_pct_raw=$(printf '%s' "$input" | jq -r '.rate_limits.seven_day.used_percentage // empty') | |
| rate_part="" | |
| if [ -n "$five_pct_raw" ] || [ -n "$week_pct_raw" ]; then | |
| inner="" | |
| if [ -n "$five_pct_raw" ]; then | |
| five_pct_int=$(printf '%3.0f' "$five_pct_raw") | |
| inner="5h ${five_pct_int}%" | |
| fi | |
| if [ -n "$week_pct_raw" ]; then | |
| week_pct_int=$(printf '%3.0f' "$week_pct_raw") | |
| if [ -n "$inner" ]; then | |
| inner="${inner} | 7d ${week_pct_int}%" | |
| else | |
| inner="7d ${week_pct_int}%" | |
| fi | |
| fi | |
| rate_part="[${inner}]" | |
| fi | |
| # ── Compose output ──────────────────────────────────────────────────────────── | |
| # [<shell>] — magenta | |
| printf '\033[35m<%s>\033[0m ' "$shell_label" | |
| # user@host — bold green | |
| printf '\033[1;32m%s@%s\033[0m' "$user" "$host" | |
| # :/path — bold blue (colon is part of this segment) | |
| printf '\033[1;34m:%s\033[0m' "$short_cwd" | |
| # (Model, effort) — default color | |
| if [ -n "$model_short" ]; then | |
| if [ -n "$effort" ]; then | |
| printf ' (%s, %s)' "$model_short" "$effort" | |
| else | |
| printf ' (%s)' "$model_short" | |
| fi | |
| fi | |
| # [ctx: %% / k] — default color | |
| if [ -n "$ctx_part" ]; then | |
| printf ' %s' "$ctx_part" | |
| fi | |
| # [5h: %% | 7d: %%] — default color | |
| if [ -n "$rate_part" ]; then | |
| printf ' %s' "$rate_part" | |
| fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment