Skip to content

Instantly share code, notes, and snippets.

@junetech
Created May 27, 2026 13:48
Show Gist options
  • Select an option

  • Save junetech/1290db596796d8646766eae365ee95af to your computer and use it in GitHub Desktop.

Select an option

Save junetech/1290db596796d8646766eae365ee95af to your computer and use it in GitHub Desktop.
Claude Code statusLine with context % and rate limits
#!/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
#!/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