Created
September 3, 2026 13:25
-
-
Save agrublev/282d6054044953ddcac1c9f09dec9997 to your computer and use it in GitHub Desktop.
STATUSLINE!
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 | |
| # Installs the Claude Code statusline script and wires it up in ~/.claude/settings.json. | |
| # Run this on the target (server) machine: bash install-statusline.sh | |
| set -euo pipefail | |
| CLAUDE_DIR="$HOME/.claude" | |
| STATUSLINE_PATH="$CLAUDE_DIR/statusline-command.sh" | |
| SETTINGS_PATH="$CLAUDE_DIR/settings.json" | |
| mkdir -p "$CLAUDE_DIR" | |
| cat > "$STATUSLINE_PATH" << 'STATUSLINE_EOF' | |
| #!/bin/bash | |
| # Claude Code status line. | |
| # Layout: context | cost | model | effort | cwd | repo | branch | |
| # Repo and branch are omitted entirely outside a git repository. | |
| # jq emits numbers with a dot; this shell runs under a comma-decimal locale, | |
| # where printf %f then rejects "8.4" and silently yields 0. Force C numerics | |
| # for the conversions below. Not LC_ALL, which would also affect path text. | |
| export LC_NUMERIC=C | |
| input=$(cat) | |
| # One jq call, one field per line. Newline-delimited (not @tsv) on purpose: | |
| # with IFS=$'\t', bash `read` collapses runs of tab because tab is IFS | |
| # whitespace, so a single empty field silently shifts every later field left. | |
| fields=() | |
| while IFS= read -r line; do fields+=("$line"); done < <( | |
| printf '%s' "$input" | jq -r ' | |
| [ | |
| (.context_window.used_percentage // "" | tostring), | |
| (.cost.total_cost_usd // "" | tostring), | |
| (.model.display_name // ""), | |
| (if .effort.level then .effort.level | |
| elif .thinking.enabled == true then "on" | |
| elif .thinking.enabled == false then "off" | |
| else "" end), | |
| (.workspace.current_dir // .cwd // ""), | |
| (.workspace.repo | if . then ((.owner // "") + "/" + (.name // "")) else "" end) | |
| ] | .[] | |
| ' 2>/dev/null | |
| ) | |
| used_pct="${fields[0]}" | |
| cost="${fields[1]}" | |
| model="${fields[2]:-Claude}" | |
| effort="${fields[3]}" | |
| raw_cwd="${fields[4]}" | |
| repo="${fields[5]}" | |
| # Abbreviate home for display. | |
| disp_cwd="$raw_cwd" | |
| case "$disp_cwd" in | |
| "$HOME") disp_cwd="~" ;; | |
| "$HOME"/*) disp_cwd="~${disp_cwd#"$HOME"}" ;; | |
| esac | |
| # Single lock-free git call, guarded on the directory still existing. | |
| # Silent outside a repo, on detached HEAD, or if cwd was deleted. | |
| branch="" | |
| if [ -n "$raw_cwd" ] && [ -d "$raw_cwd" ]; then | |
| branch=$(git -C "$raw_cwd" --no-optional-locks symbolic-ref --short -q HEAD 2>/dev/null) | |
| fi | |
| C_CTX=$'\033[2;32m' | |
| C_COST=$'\033[2;31m' | |
| C_MODEL=$'\033[2;36m' | |
| C_EFFORT=$'\033[2;35m' | |
| C_DIR=$'\033[2;34m' | |
| C_REPO=$'\033[2;90m' | |
| C_BRANCH=$'\033[2;33m' | |
| RESET=$'\033[0m' | |
| SEP=" " | |
| # Collect only non-empty segments, so an absent field leaves no separator | |
| # or placeholder behind. | |
| parts=() | |
| case "$used_pct" in | |
| ''|*[!0-9.]*) ;; | |
| *) parts+=("${C_CTX}Ctx $(printf '%.0f' "$used_pct" 2>/dev/null)%${RESET}") ;; | |
| esac | |
| case "$cost" in | |
| ''|*[!0-9.]*) ;; | |
| *) parts+=("${C_COST}\$$(printf '%.2f' "$cost" 2>/dev/null)${RESET}") ;; | |
| esac | |
| parts+=("${C_MODEL}${model}${RESET}") | |
| [ -n "$effort" ] && parts+=("${C_EFFORT}Effort: ${effort}${RESET}") | |
| [ -n "$disp_cwd" ] && parts+=("${C_DIR}${disp_cwd}${RESET}") | |
| [ -n "$repo" ] && parts+=("${C_REPO}${repo}${RESET}") | |
| [ -n "$branch" ] && parts+=("${C_BRANCH}${branch}${RESET}") | |
| line="" | |
| for p in "${parts[@]}"; do | |
| if [ -z "$line" ]; then line="$p"; else line="${line}${SEP}${p}"; fi | |
| done | |
| # %s not %b: the colour vars hold literal ESC bytes already, and %b would | |
| # expand backslash sequences inside a path or branch name. | |
| printf '%s' "$line" | |
| STATUSLINE_EOF | |
| chmod +x "$STATUSLINE_PATH" | |
| echo "Wrote $STATUSLINE_PATH" | |
| if ! command -v jq >/dev/null 2>&1; then | |
| echo "Warning: 'jq' is not installed on this machine — the statusline script requires it." >&2 | |
| fi | |
| STATUSLINE_CMD="bash $STATUSLINE_PATH" | |
| if [ -f "$SETTINGS_PATH" ]; then | |
| if ! command -v jq >/dev/null 2>&1; then | |
| echo "Error: jq is required to safely update $SETTINGS_PATH. Install jq and re-run." >&2 | |
| exit 1 | |
| fi | |
| tmp=$(mktemp) | |
| jq --arg cmd "$STATUSLINE_CMD" '.statusLine = {"type": "command", "command": $cmd}' "$SETTINGS_PATH" > "$tmp" | |
| mv "$tmp" "$SETTINGS_PATH" | |
| echo "Updated statusLine in $SETTINGS_PATH" | |
| else | |
| cat > "$SETTINGS_PATH" << SETTINGS_EOF | |
| { | |
| "statusLine": { | |
| "type": "command", | |
| "command": "$STATUSLINE_CMD" | |
| } | |
| } | |
| SETTINGS_EOF | |
| echo "Created $SETTINGS_PATH with statusLine config" | |
| fi | |
| echo "Done. Restart Claude Code (or start a new session) to see the statusline." |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
curl -fsSL https://gist.githubusercontent.com/agrublev/282d6054044953ddcac1c9f09dec9997/raw/71c6419ef78eda77c284f01f556e542e2f7e8714/statusline.sh | bash