Claude Code Guide

Context-Aware Statusline

Claude Code reports 1M context for every session — even when running GLM or Kimi through shell aliases. This script detects the actual model, clamps the context window to its real limit, and gives you an accurate progress bar.

1M Context — But Not Really

When you run alternative models through Claude Code using shell aliases, the statusline JSON always reports context_window_size: 1000000. Claude Code doesn't know the downstream model has a smaller window. Your progress bar shows 8% when you're actually at 60%.

The danger
Autocompact fires at ~83% of the reported window. But if your model's real limit is 200K and CC thinks you have 1M, you'll hit the model's context limit and get errors long before autocompact kicks in to save you.

What CC reports vs. reality

ModelCC ReportsActual LimitAt 120K tokens
Claude Opus 4.61M1M12% — correct
GLM-4.71M200K12% shown, actually 60%
GLM-4.7-Flash1M200K12% shown, actually 60%
Kimi K2.51M256K12% shown, actually 47%
Model-Aware Context Clamping

The statusline JSON includes model.id — the actual model name your alias configured. The script reads it, detects non-Anthropic models, clamps the context window to the model's real limit, and recalculates the percentage.

What the script shows

Model Badge

Model name + real context window. GLM gets 🤖, Kimi gets 🌙, Claude gets ◆. A ⚡ icon appears when clamping is active.

Progress Bar

16-char bar with color coding. Green <50%, yellow 50-64%, orange 65-79% with ⚠️, red 80%+ with 🔥.

Git Branch

Red highlight for main/master, purple for dev, blue for feature branches and worktrees.

Working Directory

Shortened CWD so you always know where you are on disk.

Example output

🤖 GLM-4.7-Flash [200K] ⚡ │ █████████░░░░░░░ 60% feature/auth │ ~/G/StakTrakr ◆ Opus [1M] │ ██░░░░░░░░░░░░░░ 12% main │ ~/G/Devops 🌙 kimi-k2.5 [256K] ⚡ │ █████████████░░░ 85% 🔥 wt-fix-auth │ ~/G/.worktrees/fix-auth

Without clamping, those GLM and Kimi bars would both show ~12% — dangerously misleading.

statusline.sh

Save this as ~/.claude/statusline.sh and make it executable. The script reads JSON from stdin (piped by Claude Code), detects the model, and prints a formatted status bar to stdout.

~/.claude/statusline.sh
#!/bin/bash
# Claude Code Statusline — GLM-aware context display
# Reads JSON from stdin, outputs ANSI-formatted status bar

input=$(cat)

# ── Model info ──
MODEL_ID=$(echo "$input" | jq -r '.model.id // "unknown"')
MODEL_NAME=$(echo "$input" | jq -r '.model.display_name // "?"')

# ── Context window ──
CTX_SIZE=$(echo "$input" | jq -r '.context_window.context_window_size // 200000')
USED_PCT=$(echo "$input" | jq -r '.context_window.used_percentage // 0')
INPUT_TOKENS=$(echo "$input" | jq -r '.context_window.total_input_tokens // 0')

# ── GLM context clamping ──
# CC reports 1M for all models but GLM caps at 200K (4.7/Flash)
ACTUAL_CTX=$CTX_SIZE
GLM_CLAMPED=""
if echo "$MODEL_ID" | grep -qi "GLM"; then
  ACTUAL_CTX=200000
  if [ "$CTX_SIZE" -gt 200000 ] 2>/dev/null; then
    if [ "$INPUT_TOKENS" -gt 0 ] 2>/dev/null; then
      USED_PCT=$(echo "scale=0; $INPUT_TOKENS * 100 / $ACTUAL_CTX" | bc 2>/dev/null || echo "$USED_PCT")
    fi
    GLM_CLAMPED=" ⚡"
  fi
elif echo "$MODEL_ID" | grep -qi "kimi"; then
  ACTUAL_CTX=256000
  if [ "$CTX_SIZE" -gt 256000 ] 2>/dev/null; then
    if [ "$INPUT_TOKENS" -gt 0 ] 2>/dev/null; then
      USED_PCT=$(echo "scale=0; $INPUT_TOKENS * 100 / $ACTUAL_CTX" | bc 2>/dev/null || echo "$USED_PCT")
    fi
    GLM_CLAMPED=" ⚡"
  fi
fi

# ── Format context size for display ──
if [ "$ACTUAL_CTX" -ge 1000000 ]; then
  CTX_LABEL="1M"
elif [ "$ACTUAL_CTX" -ge 256000 ]; then
  CTX_LABEL="256K"
elif [ "$ACTUAL_CTX" -ge 200000 ]; then
  CTX_LABEL="200K"
else
  CTX_LABEL="$((ACTUAL_CTX / 1000))K"
fi

# ── Git info ──
WORKTREE=$(echo "$input" | jq -r '.workspace.git_worktree // empty')
WT_BRANCH=$(echo "$input" | jq -r '.worktree.branch // empty')
BRANCH=""
if [ -n "$WT_BRANCH" ]; then
  BRANCH="$WT_BRANCH"
elif [ -n "$WORKTREE" ]; then
  BRANCH="$WORKTREE"
else
  BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "")
fi

# ── CWD (shorten your workspace prefix to taste) ──
CWD=$(echo "$input" | jq -r '.cwd // ""')
CWD_SHORT=$(echo "$CWD" | sed "s|$HOME|~|")

# ── Colors ──
RESET="\033[0m"; BOLD="\033[1m"; DIM="\033[2m"
BCYAN="\033[1;36m"; BGREEN="\033[1;32m"
BYELLOW="\033[1;33m"; BRED="\033[1;31m"
BORANGE="\033[1;38;5;208m"
BMAGENTA="\033[1;35m"; BBLUE="\033[1;34m"
BGRED="\033[41m"; WHITE="\033[37m"

# ── Progress bar ──
BAR_WIDTH=16
FILLED=$((USED_PCT * BAR_WIDTH / 100))
[ "$FILLED" -gt "$BAR_WIDTH" ] && FILLED=$BAR_WIDTH
EMPTY=$((BAR_WIDTH - FILLED))

if [ "$USED_PCT" -ge 80 ]; then
  BAR_COLOR="$BRED"; PCT_COLOR="$BRED"; WARN=" 🔥"
elif [ "$USED_PCT" -ge 65 ]; then
  BAR_COLOR="$BORANGE"; PCT_COLOR="$BORANGE"; WARN=" ⚠️"
elif [ "$USED_PCT" -ge 50 ]; then
  BAR_COLOR="$BYELLOW"; PCT_COLOR="$BYELLOW"; WARN=""
else
  BAR_COLOR="$BGREEN"; PCT_COLOR="$BGREEN"; WARN=""
fi

BAR="${BAR_COLOR}"
for ((i=0; i<FILLED; i++)); do BAR+="█"; done
BAR+="${DIM}"
for ((i=0; i<EMPTY; i++)); do BAR+="░"; done
BAR+="${RESET}"

# ── Branch display ──
BRANCH_STR=""
if [ -n "$BRANCH" ]; then
  if [ "$BRANCH" = "main" ] || [ "$BRANCH" = "master" ]; then
    BRANCH_STR=" ${BGRED}${WHITE}${BOLD} ${BRANCH} ${RESET}"
  elif echo "$BRANCH" | grep -q "^dev$"; then
    BRANCH_STR=" ${BMAGENTA} ${BRANCH}${RESET}"
  else
    BRANCH_STR=" ${BBLUE} ${BRANCH}${RESET}"
  fi
fi

# ── Model badge ──
if echo "$MODEL_ID" | grep -qi "GLM"; then
  MODEL_BADGE="${BCYAN}🤖 ${MODEL_ID}${RESET}${DIM} [${CTX_LABEL}]${GLM_CLAMPED}${RESET}"
elif echo "$MODEL_ID" | grep -qi "kimi"; then
  MODEL_BADGE="${BCYAN}🌙 ${MODEL_ID}${RESET}${DIM} [${CTX_LABEL}]${GLM_CLAMPED}${RESET}"
else
  MODEL_BADGE="${BCYAN}◆ ${MODEL_NAME}${RESET}${DIM} [${CTX_LABEL}]${RESET}"
fi

# ── Output ──
echo -e "${MODEL_BADGE} ${DIM}│${RESET} ${BAR} ${PCT_COLOR}${BOLD}${USED_PCT}%${RESET}${WARN}${BRANCH_STR} ${DIM}│ ${CWD_SHORT}${RESET}"
Extending for other models
Add more elif blocks for any model with a different context limit. Match on MODEL_ID (the value your alias sets via ANTHROPIC_DEFAULT_*_MODEL), set ACTUAL_CTX to the real limit, and the rest handles itself.
Two Steps

Save the script, point your settings at it. Restart Claude Code to pick up the change.

1. Save and make executable

chmod +x ~/.claude/statusline.sh

2. Add to settings.json

~/.claude/settings.json
{
  "statusLine": {
    "type": "command",
    "command": "bash ~/.claude/statusline.sh"
  }
}

That's it. The statusline updates after each assistant message and on permission mode changes.

JSON fields available

Claude Code pipes a JSON object to your script's stdin on every update. Key fields this script uses:

FieldTypeDescription
model.idstringModel identifier — matches what your alias sets
model.display_namestringFriendly name (Opus, Sonnet, Haiku)
context_window.context_window_sizenumberReported context limit (always 1M for extended models)
context_window.used_percentagenumberPre-calculated percentage (based on reported size)
context_window.total_input_tokensnumberActual tokens consumed — needed for recalculation
workspace.git_worktreestringWorktree name if in a linked worktree
worktree.branchstringBranch name in --worktree sessions
cwdstringCurrent working directory
Dependency
The script requires jq for JSON parsing and bc for percentage calculation. Both are pre-installed on macOS. On Linux: apt install jq bc.
The Clamping Logic

Three steps: detect the model, override the context window, recalculate the percentage.

Step 1: Detect

Read model.id from the JSON. If it contains "GLM" (case-insensitive), the model is running through a GLM alias. Same check for "kimi".

Step 2: Clamp

Override context_window_size with the model's real limit. GLM-4.7 and Flash both cap at 200K. Kimi K2.5 caps at 256K. Native Claude models pass through unchanged.

Step 3: Recalculate

Divide total_input_tokens by the clamped context size. This gives the true percentage. The ⚡ icon appears when clamping is active, so you always know the displayed percentage is adjusted.

Why not just set CLAUDE_CODE_AUTO_COMPACT_WINDOW?
That env var controls when autocompact fires, but it doesn't fix the statusline display. You still see a misleading percentage. The statusline script fixes what you see. Use both together: CLAUDE_CODE_AUTO_COMPACT_WINDOW="150000" in your alias to trigger compaction at the right time, and this script to display the right number.