Last active
March 21, 2026 16:37
-
-
Save n-WN/07abd31ac1a3bc960a542abdebc04303 to your computer and use it in GitHub Desktop.
Claude Code custom statusline — shows rate limits, corrected cost, git branch, session duration
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 custom statusline | |
| # Shows: user@host:path branch [model] ctx% $cost duration 5h/7d quota Sonnet flag | |
| # | |
| # Setup: | |
| # 1. Save this file to ~/.claude/statusline-command.sh | |
| # 2. Add to ~/.claude/settings.json: | |
| # { | |
| # "statusLine": { | |
| # "type": "command", | |
| # "command": "bash ~/.claude/statusline-command.sh" | |
| # } | |
| # } | |
| # 3. Restart Claude Code | |
| # | |
| # Features: | |
| # - Rate limits (5h/7d) with reset countdown, cached across sessions | |
| # - Session cost corrected for 1h cache pricing (Pro/Max users) | |
| # - Git branch + dirty state | |
| # - Context window usage % | |
| # - Session duration | |
| # - Sonnet model indicator with quota | |
| # | |
| # Requires: jq, git (optional) | |
| # https://gist.github.com/n-WN/07abd31ac1a3bc960a542abdebc04303 | |
| input=$(cat) | |
| NOW=$(date +%s) | |
| # ---------- Parse all fields in one jq call ---------- | |
| eval "$(echo "$input" | jq -r ' | |
| @sh "cwd=\(.workspace.current_dir // .cwd // "")", | |
| @sh "project_dir=\(.workspace.project_dir // .workspace.current_dir // "")", | |
| @sh "model_id=\(.model.id // "")", | |
| @sh "model_raw=\(.model.display_name // "")", | |
| @sh "used=\(.context_window.used_percentage // "")", | |
| @sh "session_id=\(.session_id // "")", | |
| @sh "claude_cost=\(.cost.total_cost_usd // 0)", | |
| @sh "duration_ms=\(.cost.total_duration_ms // 0)", | |
| @sh "rl_5h=\(.rate_limits.five_hour.used_percentage // "")", | |
| @sh "rl_5h_reset=\(.rate_limits.five_hour.resets_at // "")", | |
| @sh "rl_7d=\(.rate_limits.seven_day.used_percentage // "")", | |
| @sh "rl_7d_reset=\(.rate_limits.seven_day.resets_at // "")", | |
| @sh "cache_create=\(.context_window.current_usage.cache_creation_input_tokens // 0)" | |
| ')" || exit 0 | |
| # ---------- Derived values ---------- | |
| cwd="${cwd/#$HOME/\~}" | |
| model="${model_raw/ \(1M context\)/ 1M}" | |
| model="${model/ \(200K context\)/ 200K}" | |
| # ---------- Git branch (single git call) ---------- | |
| git_seg="" | |
| if [ -n "$project_dir" ] && [ -d "$project_dir/.git" ]; then | |
| branch=$(git -C "$project_dir" rev-parse --abbrev-ref HEAD 2>/dev/null) | |
| if [ -n "$branch" ]; then | |
| if [ -z "$(git -C "$project_dir" status --porcelain 2>/dev/null | head -1)" ]; then | |
| git_seg=" \033[0;32m${branch}\033[0m" | |
| else | |
| git_seg=" \033[0;33m${branch}*\033[0m" | |
| fi | |
| fi | |
| fi | |
| # ---------- Cost (with 1h cache correction, single jq call) ---------- | |
| # Claude Code uses $6.25/M for cache writes, but firstParty (Pro/Max) get 1h at $10/M. | |
| # Track cumulative correction by detecting when cache_create changes. | |
| CCOST_FILE="/tmp/claude-ccost-${session_id}" | |
| prev_corr=0 | |
| if [ -n "$session_id" ]; then | |
| if [ -f "$CCOST_FILE" ]; then | |
| read -r prev_cc prev_corr < "$CCOST_FILE" | |
| prev_corr="${prev_corr:-0}" | |
| if [ "$cache_create" != "${prev_cc:-}" ] && [ "$cache_create" != "0" ]; then | |
| prev_corr=$(jq -n "$prev_corr + $cache_create * 3.75 / 1000000") | |
| fi | |
| elif [ "$cache_create" != "0" ]; then | |
| prev_corr=$(jq -n "$cache_create * 3.75 / 1000000") | |
| fi | |
| echo "$cache_create $prev_corr" > "$CCOST_FILE" | |
| fi | |
| real_cost=$(jq -n "($claude_cost + $prev_corr) * 100 | round / 100") | |
| cost_seg="" | |
| [ "$real_cost" != "0" ] && cost_seg=" \033[0;90m\$\033[0;33m${real_cost}\033[0m" | |
| # ---------- Duration ---------- | |
| duration_s=$(( duration_ms / 1000 )) | |
| dur_h=$(( duration_s / 3600 )) | |
| dur_m=$(( (duration_s % 3600) / 60 )) | |
| dur_seg="" | |
| if [ "$dur_h" -gt 0 ]; then | |
| dur_seg=" \033[0;90m${dur_h}h${dur_m}m\033[0m" | |
| elif [ "$dur_m" -gt 0 ]; then | |
| dur_seg=" \033[0;90m${dur_m}m\033[0m" | |
| fi | |
| # ---------- Rate limits (live → cache fallback) ---------- | |
| CACHE_FILE="$HOME/.claude/rate-limits-cache.json" | |
| rl_stale="" | |
| if [ -n "$rl_5h" ] || [ -n "$rl_7d" ]; then | |
| echo "{\"fh\":\"$rl_5h\",\"fr\":\"$rl_5h_reset\",\"sd\":\"$rl_7d\",\"sr\":\"$rl_7d_reset\"}" > "$CACHE_FILE" | |
| elif [ -f "$CACHE_FILE" ]; then | |
| eval "$(jq -r '@sh "rl_5h=\(.fh)",@sh "rl_5h_reset=\(.fr)",@sh "rl_7d=\(.sd)",@sh "rl_7d_reset=\(.sr)"' "$CACHE_FILE" 2>/dev/null)" | |
| [ -n "$rl_5h" ] || [ -n "$rl_7d" ] && rl_stale="*" | |
| fi | |
| fmt_reset() { | |
| [ -z "$1" ] && return | |
| local d=$(( $1 - NOW )) | |
| [ "$d" -le 0 ] && return | |
| local h=$(( d / 3600 )) m=$(( d % 3600 / 60 )) | |
| [ "$h" -gt 0 ] && echo "${h}h${m}m" || echo "${m}m" | |
| } | |
| # ---------- Build segments ---------- | |
| quota="" | |
| if [ -n "$rl_5h" ]; then | |
| r=$(fmt_reset "$rl_5h_reset") | |
| quota="$quota \033[0;90m5h:\033[0;35m$(printf '%.0f' "$rl_5h")%${rl_stale}\033[0m" | |
| [ -n "$r" ] && quota="$quota\033[0;90m(↺${r})\033[0m" | |
| else | |
| quota="$quota \033[0;90m5h:\033[0;37m--\033[0m" | |
| fi | |
| if [ -n "$rl_7d" ]; then | |
| r=$(fmt_reset "$rl_7d_reset") | |
| quota="$quota \033[0;90m7d:\033[0;35m$(printf '%.0f' "$rl_7d")%${rl_stale}\033[0m" | |
| [ -n "$r" ] && quota="$quota\033[0;90m(↺${r})\033[0m" | |
| else | |
| quota="$quota \033[0;90m7d:\033[0;37m--\033[0m" | |
| fi | |
| sonnet="" | |
| if [[ "$model_id" == *sonnet* ]] && [ -n "$rl_5h" ]; then | |
| sonnet=" \033[0;33mSonnet\033[0m\033[0;90m[$(printf '%.0f' "$rl_5h")%]\033[0m" | |
| elif [[ "$model_id" == *sonnet* ]]; then | |
| sonnet=" \033[0;33mSonnet\033[0m" | |
| fi | |
| flag="" | |
| FLAG_LOG="/tmp/claude-ctf-flags.log" | |
| [ -f "$FLAG_LOG" ] && [ -s "$FLAG_LOG" ] && flag=" \033[0;90mflag:\033[0;32m$(wc -l < "$FLAG_LOG" | tr -d ' ')\033[0m" | |
| ctx="" | |
| [ -n "$used" ] && ctx=" \033[0;90mctx:${used%.*}%\033[0m" | |
| # ---------- Render ---------- | |
| echo -ne "\033[0;32m${USER:-$(whoami)}\033[0m@\033[0;36m${HOSTNAME%%.*}\033[0m:\033[0;34m${cwd}\033[0m${git_seg} \033[0;33m[${model}]\033[0m${ctx}${cost_seg}${dur_seg}${quota}${sonnet}${flag}" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment