A Powerline-style status line with nerd-font separators and a Dracula palette: colored directory, git branch, a per-model icon, and a faded context progress bar with an arrow tail.
MIT licensed · original source
Updated 2026-06-29
8 copies
Preview
Clean repo
app main Opus 4.8 ━━━━━━━━━━ 22% 128 34
New session
app main Opus 4.8 0 0
Dirty branch
app feat/auth Sonnet 4.6 ━━━━━━━━━━ 48% 2 128 34
Near-full
app main Opus 4.8 ━━━━━━━━━━ 91% 128 34
1M context
app main Fable 5 ━━━━━━━━━━ 64% 128 34
Post-compact
app main Haiku 4.5 128 34
Worktree
…/feature worktree-feature Opus 4.8 ━━━━━━━━━━ 37% 128 34
Non-git
scratch Opus 4.8 ━━━━━━━━━━ 22% 128 34
Source
#!/bin/bash
# Statusline polls run frequently (multiple times per Claude refresh).
# Without this, `git status` below would try to refresh the index stat
# cache and race the user's own git operations for .git/index.lock.
export GIT_OPTIONAL_LOCKS=0
input=$(cat)
current_dir=$(echo "$input" | jq -r '.workspace.current_dir // .cwd')
ARROW_RIGHT=$(printf '\xee\x82\xb0')
ARROW_LEFT=$(printf '\xee\x82\xb2')
ARROW_ROUND=$(printf '\xee\x82\xb6')
ICON_PLUS=$(printf '\xef\x81\x95')
ICON_MINUS=$(printf '\xef\x81\x96')
ICON_SONNET=$(printf '\xee\xb8\xb4')
ICON_OPUS=$(printf '\xee\xb5\xa2')
ICON_HAIKU=$(printf '\xee\x9f\x95')
ICON_GIT=$(printf '\xee\x82\xa0')
ICON_DIFF=$(printf '\xf3\xb0\xa6\x93')
FG="40;42;54"
BG="40;42;54"
COLOR_DIR="189;147;249"
COLOR_GIT="255;121;198"
COLOR_MODEL="139;233;253"
COLOR_CTX="80;250;123"
COLOR_LINES="255;184;108"
if [ "$current_dir" = "$HOME" ]; then
dir_display="~"
else
if [[ "$current_dir" == "$HOME"/* ]]; then
rel_path="${current_dir#$HOME/}"
depth=$(echo "$rel_path" | tr -cd '/' | wc -c | tr -d ' ')
if [ "$depth" -gt 0 ]; then
dir_display="…/$(basename "$current_dir")"
else
dir_display="$(basename "$current_dir")"
fi
else
dir_display="$(basename "$current_dir")"
fi
fi
git_branch=""
git_changes="0"
git_root=""
if git -C "$current_dir" rev-parse --git-dir > /dev/null 2>&1; then
git_root=$(git -C "$current_dir" rev-parse --show-toplevel 2>/dev/null)
git_branch=$(git -C "$git_root" symbolic-ref --short HEAD 2>/dev/null || git -C "$git_root" rev-parse --short HEAD 2>/dev/null)
modified_count=$(git -C "$git_root" status --short --untracked-files=all 2>/dev/null | wc -l | tr -d ' ')
git_changes="$modified_count"
fi
model_display=$(echo "$input" | jq -r '.model.display_name // "Unknown"')
model_id=$(echo "$input" | jq -r '.model.id // ""')
if echo "$model_display" | grep -qi "sonnet" || echo "$model_id" | grep -qi "sonnet"; then
model_icon="$ICON_SONNET"
elif echo "$model_display" | grep -qi "haiku" || echo "$model_id" | grep -qi "haiku"; then
model_icon="$ICON_HAIKU"
elif echo "$model_display" | grep -qi "opus" || echo "$model_id" | grep -qi "opus"; then
model_icon="$ICON_OPUS"
else
model_icon="$ICON_SONNET"
fi
context_data=$(echo "$input" | jq '.context_window.current_usage')
context_percentage=""
if [ "$context_data" != "null" ]; then
input_tokens=$(echo "$context_data" | jq '.input_tokens // 0')
cache_creation=$(echo "$context_data" | jq '.cache_creation_input_tokens // 0')
cache_read=$(echo "$context_data" | jq '.cache_read_input_tokens // 0')
context_size=$(echo "$input" | jq '.context_window.context_window_size // 200000')
current_usage=$((input_tokens + cache_creation + cache_read))
percentage=$((current_usage * 100 / context_size))
context_percentage="$percentage"
filled_segments=$((percentage / 10))
if [ $filled_segments -gt 10 ]; then
filled_segments=10
fi
empty_segments=$((10 - filled_segments))
progress_bar=""
for i in $(seq 1 $filled_segments); do
progress_bar="${progress_bar}━"
done
fade_idx=0
for i in $(seq 1 $empty_segments); do
case $fade_idx in
0) progress_bar="${progress_bar}\033[38;2;68;71;100m━" ;;
1) progress_bar="${progress_bar}\033[38;2;68;71;90m━" ;;
2) progress_bar="${progress_bar}\033[38;2;60;63;80m━" ;;
3) progress_bar="${progress_bar}\033[38;2;52;55;70m━" ;;
*) progress_bar="${progress_bar}\033[38;2;44;47;60m━" ;;
esac
fade_idx=$((fade_idx + 1))
done
progress_bar="${progress_bar}\033[38;2;${FG}m"
fi
lines_added=$(echo "$input" | jq -r '.cost.total_lines_added // 0')
lines_removed=$(echo "$input" | jq -r '.cost.total_lines_removed // 0')
printf "\033[38;2;${COLOR_DIR}m${ARROW_ROUND}\033[0m"
printf "\033[38;2;${FG}m\033[48;2;${COLOR_DIR}m $dir_display \033[0m"
if [ -n "$git_branch" ]; then
printf "\033[38;2;${COLOR_DIR}m\033[48;2;${COLOR_GIT}m${ARROW_RIGHT}\033[0m"
printf "\033[38;2;${FG}m\033[48;2;${COLOR_GIT}m $ICON_GIT $git_branch \033[0m"
printf "\033[38;2;${COLOR_GIT}m\033[48;2;${COLOR_MODEL}m${ARROW_RIGHT}\033[0m"
else
printf "\033[38;2;${COLOR_DIR}m\033[48;2;${COLOR_MODEL}m${ARROW_RIGHT}\033[0m"
fi
printf "\033[38;2;${FG}m\033[48;2;${COLOR_MODEL}m $model_icon $model_display \033[0m"
if [ -n "$context_percentage" ]; then
printf "\033[38;2;${COLOR_MODEL}m\033[48;2;${COLOR_CTX}m${ARROW_RIGHT}\033[0m"
printf "\033[38;2;${FG}m\033[48;2;${COLOR_CTX}m "
printf "%b" "$progress_bar"
printf " ${context_percentage}%% \033[0m"
if [ "$lines_added" != "0" ] || [ "$lines_removed" != "0" ] || [ -n "$git_changes" ]; then
printf "\033[38;2;${COLOR_CTX}m\033[48;2;${COLOR_LINES}m${ARROW_RIGHT}\033[0m"
files_part=""
[ "$git_changes" != "0" ] && files_part="$ICON_DIFF $git_changes "
printf "\033[38;2;${FG}m\033[48;2;${COLOR_LINES}m ${files_part}$ICON_PLUS $lines_added $ICON_MINUS $lines_removed \033[0m"
printf "\033[38;2;${COLOR_LINES}m\033[48;2;180;130;80m${ARROW_RIGHT}\033[0m"
printf "\033[38;2;180;130;80m\033[48;2;120;85;55m${ARROW_RIGHT}\033[0m"
printf "\033[38;2;120;85;55m\033[48;2;70;50;35m${ARROW_RIGHT}\033[0m"
printf "\033[38;2;70;50;35m${ARROW_RIGHT}\033[0m\n"
else
printf "\033[38;2;${COLOR_CTX}m\033[48;2;55;180;90m${ARROW_RIGHT}\033[0m"
printf "\033[38;2;55;180;90m\033[48;2;40;130;65m${ARROW_RIGHT}\033[0m"
printf "\033[38;2;40;130;65m\033[48;2;30;90;48m${ARROW_RIGHT}\033[0m"
printf "\033[38;2;30;90;48m${ARROW_RIGHT}\033[0m\n"
fi
else
if [ "$lines_added" != "0" ] || [ "$lines_removed" != "0" ] || [ -n "$git_changes" ]; then
printf "\033[38;2;${COLOR_MODEL}m\033[48;2;${COLOR_LINES}m${ARROW_RIGHT}\033[0m"
files_part=""
[ "$git_changes" != "0" ] && files_part="$ICON_DIFF $git_changes "
printf "\033[38;2;${FG}m\033[48;2;${COLOR_LINES}m ${files_part}$ICON_PLUS $lines_added $ICON_MINUS $lines_removed \033[0m"
printf "\033[38;2;${COLOR_LINES}m\033[48;2;180;130;80m${ARROW_RIGHT}\033[0m"
printf "\033[38;2;180;130;80m\033[48;2;120;85;55m${ARROW_RIGHT}\033[0m"
printf "\033[38;2;120;85;55m\033[48;2;70;50;35m${ARROW_RIGHT}\033[0m"
printf "\033[38;2;70;50;35m${ARROW_RIGHT}\033[0m\n"
else
printf "\033[38;2;${COLOR_MODEL}m\033[48;2;100;180;210m${ARROW_RIGHT}\033[0m"
printf "\033[38;2;100;180;210m\033[48;2;70;130;160m${ARROW_RIGHT}\033[0m"
printf "\033[38;2;70;130;160m\033[48;2;50;90;110m${ARROW_RIGHT}\033[0m"
printf "\033[38;2;50;90;110m${ARROW_RIGHT}\033[0m\n"
fi
fi
What it shows
- Current directory name, shortened to ~ for the home directory and to …/dirname for paths nested more than one level under home
- Current git branch name, falling back to the short commit hash when HEAD is detached
- Count of changed and untracked files in the repo, shown with a diff icon when nonzero
- Model display name with a Nerd Font icon chosen per model family (Sonnet, Haiku, or Opus)
- Context window usage as a percentage, computed from input, cache-creation, and cache-read tokens against the context window size
- A ten-segment context progress bar whose unfilled tail fades to darker shades
- Total lines added and removed in the session, each with its own icon
Requirements
- bash
- jq, used to parse the JSON that Claude Code sends on stdin
- git, used for branch detection and change counts
- A Nerd Font, for the Powerline separators and the git, model, diff, plus, and minus icons
- A terminal that supports 24-bit truecolor ANSI escape codes
- No network access; the script declares no hosts and runs with network access off
Behavior notes
- The pink git segment disappears entirely when the current directory is not a git repository, as in the scratch-directory scenario
- The green context bar and percentage segment are omitted when context_window.current_usage is null, as in the brand-new-session and post-compact scenarios
- The file-change count and diff icon appear only when the repo has uncommitted changes; the dirty-branch scenario shows a count of 2 while clean-repo scenarios show only the lines added and removed
- The lines segment renders even when both counts are zero, as in the fresh-session scenario, because the file-change count variable is initialized to 0 before the git-repo check runs, regardless of whether the directory is a git repo
- The progress bar fills one segment per 10 percent used: two segments at 22 percent, nine at 91 percent
- The model icon switches by matching sonnet, haiku, or opus in the model name or ID; unrecognized models like Fable 5 fall back to the Sonnet icon
- The directory shortens to …/feature in the worktree scenario because the path sits more than one level below home
- The branch name comes from the actual git checkout, so the worktree scenario shows worktree-feature and the dirty-branch scenario shows feat/auth regardless of the JSON payload
- The status line ends with a four-arrow tail that fades through darker shades of the last segment's color
- The script sets GIT_OPTIONAL_LOCKS=0 so its frequent git status polls do not compete with the user's own git commands for the index lock
- Fields in the JSON with no matching code, such as vim mode, effort level, rate limits, PR info, and session name, do not appear in the output
More status lines
Dreambase Panel
150 copies
╭─ CONTEXT ────────────────────────────────────────────╮
│ ████▊░░░░░░░░░░░░░░░░░ 22% of 200K · GOOD │
├─ STATS ──────────────────────────────────────────────┤
│ ↓ 44.0K ↑ 1.4K │ $0.41 │ ⏱ 10m 12s │ +128/-34 │
├─ REPO ───────────────────────────────────────────────┤
│ ◆ Opus 4.8 · main · 16:21 │
╰──────────────────────────────────────────────────────╯
Single-line usage
87 copies
app · main · Opus-4.8 · effort high · ctx 22% · 5h 26% ↻2h6m · 7d 7% ↻2d0hPace Dot Meters
63 copies
Opus 4.8 [high] ~/app main
16:20:55 | ⛁ ██░░░░░░░░ 22% | 5h ●◔○○○ 26% ↻2h7m | 7d ◔○○○○○○ 7% ↻2d1h │ $0.41 ⏱ 10m
Catppuccin Frappé
38 copies
Opus 4.8 │ main │ app │ ▓▓░░░░░░░░ 44k/200k │ $0.41
Activity Feed
36 copies
Opus 4.8 high ✦ │ ctx 22% │ app (main) │ PR #1287 ● │ $0.41 · 10m +128 -34
Session ● ● ● ● ● ● ● ● ○ ○ ○ 74% left Resets in 2h 6m
Weekly ● ● ● ● ● ● ● ● ● ● ○ 93% left Resets in 2d 0h
Fable ● ● ● ● ● ● ● ● ● ○ ○ 85% left Resets in 2d 0h
◐ Read:index.ts ✓ Read×1 ✓ Bash×1 ✓ Edit×1 ✓ Grep×1
◐ code-reviewer Review the change for regressions
Dreambase Flat
29 copies
████▊░░░░░░░░░░░░░░░░░ 22% of 200K · GOOD │ ↓ 44.0K ↑ 1.4K │ $0.41 │ ⏱ 10m 12s │ +128/-34 │ ◆ Opus 4.8 · main · 16:22