Created
January 29, 2026 09:13
-
-
Save markomitranic/2584561209afb74899c5f1644d55024e to your computer and use it in GitHub Desktop.
Minimal Claude Code statusline with context window warning
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 | |
| # Status line script for Claude Code | |
| # Displays: Branch, Model, Cost, Duration, Lines changed | |
| # Location: ~/.claude/scripts/statusline.sh | |
| # | |
| # Installation: ~/.claude/settings.json | |
| # "statusLine": { | |
| # "type": "command", | |
| # "command": "~/.claude/scripts/statusline.sh" | |
| # } | |
| # | |
| # Flags: | |
| # --preview Use hardcoded JSON for quick testing | |
| # Parse flags | |
| PREVIEW=0 | |
| for arg in "$@"; do | |
| case "$arg" in | |
| --preview) | |
| PREVIEW=1 | |
| ;; | |
| esac | |
| done | |
| # Check if jq is installed | |
| if ! command -v jq >/dev/null 2>&1; then | |
| echo "Error: jq is required but not installed. Please install jq first." >&2 | |
| exit 1 | |
| fi | |
| # Read JSON input | |
| if [ "$PREVIEW" -eq 1 ]; then | |
| input=$(cat <<EOF | |
| { | |
| "hook_event_name": "Status", | |
| "session_id": "abc123...", | |
| "transcript_path": "/path/to/transcript.json", | |
| "cwd": "/current/working/directory", | |
| "model": { | |
| "id": "claude-opus-4-1", | |
| "display_name": "Opus" | |
| }, | |
| "workspace": { | |
| "current_dir": "/current/working/directory", | |
| "project_dir": "/original/project/directory" | |
| }, | |
| "version": "1.0.80", | |
| "output_style": { | |
| "name": "default" | |
| }, | |
| "cost": { | |
| "total_cost_usd": 0.01234, | |
| "total_duration_ms": 45000, | |
| "total_api_duration_ms": 2300, | |
| "total_lines_added": 156, | |
| "total_lines_removed": 23 | |
| }, | |
| "context_window": { | |
| "total_input_tokens": 15234, | |
| "total_output_tokens": 4521, | |
| "context_window_size": 200000, | |
| "used_percentage": 42.5, | |
| "remaining_percentage": 57.5, | |
| "current_usage": { | |
| "input_tokens": 8500, | |
| "output_tokens": 1200, | |
| "cache_creation_input_tokens": 5000, | |
| "cache_read_input_tokens": 2000 | |
| } | |
| } | |
| } | |
| EOF | |
| ) | |
| else | |
| input=$(cat) | |
| fi | |
| # Validate JSON input | |
| if [ -z "$input" ]; then | |
| echo "Error: No JSON input received from Claude Code." >&2 | |
| exit 1 | |
| fi | |
| # Dump JSON to file for debugging | |
| echo "$input" > /tmp/claude-statusline-input.json | |
| # Extract data from JSON | |
| cost=$(echo "$input" | jq -r '.cost.total_cost_usd // 0' 2>/dev/null) | |
| total_input=$(echo "$input" | jq -r '.context_window.total_input_tokens // 0' 2>/dev/null) | |
| total_output=$(echo "$input" | jq -r '.context_window.total_output_tokens // 0' 2>/dev/null) | |
| context_percentage=$(echo "$input" | jq -r '.context_window.used_percentage // 0' 2>/dev/null) | |
| model_name=$(echo "$input" | jq -r '.model.display_name // ""' 2>/dev/null) | |
| model_id=$(echo "$input" | jq -r '.model.id // ""' 2>/dev/null) | |
| workspace_dir=$(echo "$input" | jq -r '.workspace.current_dir // .workspace.project_dir // ""' 2>/dev/null) | |
| # Validate critical values were parsed successfully | |
| if [ -z "$cost" ] || [ "$cost" = "null" ]; then | |
| echo "Error: Failed to parse session data. Invalid or malformed JSON input." >&2 | |
| exit 1 | |
| fi | |
| # Get current git branch (use workspace directory if available) | |
| if [ -n "$workspace_dir" ] && [ -d "$workspace_dir" ]; then | |
| branch=$(git -C "$workspace_dir" rev-parse --abbrev-ref HEAD 2>/dev/null || echo "no-branch") | |
| else | |
| branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "no-branch") | |
| fi | |
| # Format tokens with k/M suffix | |
| format_tokens_short() { | |
| local num="$1" | |
| num=${num//[^0-9]/} | |
| if [ -z "$num" ]; then | |
| echo "0" | |
| return | |
| fi | |
| if [ "$num" -ge 1000000 ]; then | |
| awk "BEGIN {printf \"%.0fM\", $num / 1000000}" | |
| elif [ "$num" -ge 1000 ]; then | |
| awk "BEGIN {printf \"%.0fk\", $num / 1000}" | |
| else | |
| echo "$num" | |
| fi | |
| } | |
| # Calculate context tokens from percentage (actual context window usage) | |
| context_window_size=$(echo "$input" | jq -r '.context_window.context_window_size // 200000' 2>/dev/null) | |
| context_tokens=$(awk "BEGIN {printf \"%.0f\", $context_percentage * $context_window_size / 100}") | |
| context_display=$(format_tokens_short "$context_tokens") | |
| # Calculate session total (all input/output tokens consumed) | |
| session_total=$((total_input + total_output)) | |
| session_display=$(format_tokens_short "$session_total") | |
| # Prepare model display string (show name if available, fallback to ID) | |
| if [ -z "$model_name" ] || [ "$model_name" = "null" ]; then | |
| model_display="$model_id" | |
| else | |
| model_display="$model_name" | |
| fi | |
| # Convert percentage to integer | |
| context_percent_int=$(awk "BEGIN {printf \"%.0f\", $context_percentage}") | |
| # Choose context emoji based on token count | |
| if [ "$context_tokens" -lt 30000 ]; then | |
| context_emoji="π" | |
| elif [ "$context_tokens" -lt 70000 ]; then | |
| context_emoji="π€" | |
| elif [ "$context_tokens" -lt 100000 ]; then | |
| context_emoji="π" | |
| else | |
| context_emoji="π " | |
| fi | |
| # Build and print status line | |
| LC_ALL=C printf "πΏ \033[1;92m%s\033[0m | π€ \033[1;96m%b\033[0m | %s Context: \033[1;97m%s\033[0m (\033[1;94m%d%%\033[0m) | π° Session: \033[1;97m%s\033[0m (\033[1;93m\$%.4f\033[0m)" \ | |
| "$branch" \ | |
| "$model_display" \ | |
| "$context_emoji" \ | |
| "$context_display" \ | |
| "$context_percent_int" \ | |
| "$session_display" \ | |
| "$cost" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment