
If you use Claude Code (Anthropic’s CLI tool), you might have noticed something: the default status line is… functional. But functional doesn’t mean beautiful. And if you’re someone who spends hours in the terminal, you deserve something that looks as good as your Starship prompt.
I decided to fix this. Here’s what I built:

A Powerline-style status line with:
- Forest gradient colors that flow from dark to light
- Git branch and changed files count
- Model indicator with unique icons for Sonnet, Opus, and Haiku
- Context usage with a fading progress bar
- Lines added/removed with visual icons
Let me show you how to build this yourself.
Prerequisites
Before we start, you’ll need:
- A Nerd Font installed - I use Hack Nerd Font, but any Nerd Font works
- A terminal that supports true colors - Ghostty, iTerm2, Kitty, Alacritty, or WezTerm
- Claude Code installed - Obviously!
- Basic understanding of bash - We’ll write a shell script
Check Your Font
Open your terminal and run:
echo -e "\ue0b0 \ue0b2 \ue0b6"
You should see three arrow shapes. If you see boxes or question marks, you need to install a Nerd Font and configure your terminal to use it.
The Architecture
Claude Code’s status line works through a simple mechanism:
- You define a command in
~/.claude/settings.json - Claude Code runs this command and displays the output
- The command receives JSON data about the current session via stdin
The JSON includes:
- Current working directory
- Model information (name, ID)
- Context window usage (tokens used, cache info)
- Cost data (lines added/removed)
We’ll write a bash script that:
- Reads this JSON
- Adds git information
- Formats everything with colors and icons
- Outputs a beautiful Powerline status line
Installation
Step 1: Create the Script
Create a file at ~/.claude/statusline-command.sh:
#!/bin/bash
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="251;241;199"
BG="60;56;54"
COLOR_DIR="47;62;70"
COLOR_GIT="53;79;82"
COLOR_MODEL="62;98;89"
COLOR_CTX="80;106;86"
COLOR_LINES="90;120;97"
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;180;190;170m━" ;;
1) progress_bar="${progress_bar}\033[38;2;140;155;135m━" ;;
2) progress_bar="${progress_bar}\033[38;2;110;125;105m━" ;;
3) progress_bar="${progress_bar}\033[38;2;85;100;82m━" ;;
*) progress_bar="${progress_bar}\033[38;2;65;80;65m━" ;;
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;75;95;78m${ARROW_RIGHT}\033[0m"
printf "\033[38;2;75;95;78m\033[48;2;55;70;58m${ARROW_RIGHT}\033[0m"
printf "\033[38;2;55;70;58m\033[48;2;40;50;42m${ARROW_RIGHT}\033[0m"
printf "\033[38;2;40;50;42m${ARROW_RIGHT}\033[0m\n"
else
printf "\033[38;2;${COLOR_CTX}m\033[48;2;65;85;70m${ARROW_RIGHT}\033[0m"
printf "\033[38;2;65;85;70m\033[48;2;50;65;52m${ARROW_RIGHT}\033[0m"
printf "\033[38;2;50;65;52m\033[48;2;35;45;37m${ARROW_RIGHT}\033[0m"
printf "\033[38;2;35;45;37m${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;75;95;78m${ARROW_RIGHT}\033[0m"
printf "\033[38;2;75;95;78m\033[48;2;55;70;58m${ARROW_RIGHT}\033[0m"
printf "\033[38;2;55;70;58m\033[48;2;40;50;42m${ARROW_RIGHT}\033[0m"
printf "\033[38;2;40;50;42m${ARROW_RIGHT}\033[0m\n"
else
printf "\033[38;2;${COLOR_MODEL}m\033[48;2;50;75;70m${ARROW_RIGHT}\033[0m"
printf "\033[38;2;50;75;70m\033[48;2;40;55;50m${ARROW_RIGHT}\033[0m"
printf "\033[38;2;40;55;50m\033[48;2;30;40;35m${ARROW_RIGHT}\033[0m"
printf "\033[38;2;30;40;35m${ARROW_RIGHT}\033[0m\n"
fi
fi
Step 2: Make It Executable
chmod +x ~/.claude/statusline-command.sh
Step 3: Configure Claude Code
Add this to your ~/.claude/settings.json:
{
"statusLine": {
"type": "command",
"command": "bash ~/.claude/statusline-command.sh"
}
}
If you already have settings, just add the statusLine block to your existing JSON.
Step 4: Restart Claude Code
Close and reopen Claude Code. You should see your beautiful new status line!
Customizing Colors
Using Coolors
I designed my forest gradient using Coolors. This amazing tool lets you:
- Generate random palettes
- Lock colors you like
- Adjust individual colors
- Export in any format
For Powerline segments, you want colors that:
- Progress naturally (dark → light or light → dark)
- Have enough contrast to see the arrow separators
- Match your terminal’s overall theme
My Forest Palette
| Segment | Hex | RGB | Description |
|---|---|---|---|
| Directory | #2f3e46 | 47;62;70 | Darkest - the forest floor |
| Git | #354f52 | 53;79;82 | Deep moss |
| Model | #3e6259 | 62;98;89 | Forest shade |
| Context | #506a56 | 80;106;86 | Dappled sunlight |
| Changes | #5a7861 | 90;120;97 | Lightest - canopy |
Creating Your Own Palette
- Go to Coolors
- Generate or create a 5-color gradient
- Copy the hex codes
- Convert to RGB using any converter (or just extract from the hex)
- Update the
COLOR_*variables in the script
Pro tip: For a cohesive look, check out Starship’s preset gallery. The Gruvbox Rainbow preset was a major inspiration for this design.
Converting Hex to RGB
Hex #2f3e46 becomes RGB 47;62;70:
2f→ 47 (2×16 + 15)3e→ 62 (3×16 + 14)46→ 70 (4×16 + 6)
Or just use an online converter!
Customizing Icons
The Nerd Fonts Cheat Sheet
The ultimate resource for Nerd Font icons is the Nerd Fonts Cheat Sheet. Here you can:
- Search for icons by name
- Preview how they look
- Copy the character directly
- Get the Unicode code point
Converting Unicode to Bash
Here’s where it gets tricky. Bash doesn’t handle \uXXXX the same way JavaScript does. You need to convert Unicode code points to UTF-8 byte sequences.
For characters in the BMP (U+0000 to U+FFFF):
Example: U+E0B0 (Powerline arrow)
- The code point is
E0B0(3 bytes in UTF-8) - Calculate the UTF-8 bytes:
- First byte:
0xE0 | ((0xE0B0 >> 12) & 0x0F)=0xEE - Second byte:
0x80 | ((0xE0B0 >> 6) & 0x3F)=0x82 - Third byte:
0x80 | (0xE0B0 & 0x3F)=0xB0
- First byte:
- Use in bash:
printf '\xee\x82\xb0'
For characters outside BMP (U+10000+):
Example: U+F0993 (from a surrogate pair like \uDB83\uDD93)
These need 4 UTF-8 bytes. Use an online converter or:
# Python one-liner
python3 -c "print(''.join(f'\\x{b:02x}' for b in ''.encode('utf-8')))"
# Output: \xf3\xb0\xa6\x93
Icons Used in This Status Line
| Unicode | UTF-8 Bytes | Purpose |
|---|---|---|
| U+E0B0 | \xee\x82\xb0 | Powerline arrow right |
| U+E0B6 | \xee\x82\xb6 | Powerline rounded left |
| U+F418 | \xef\x90\x98 | Git branch |
| U+F055 | \xef\x81\x95 | Circle plus (lines added) |
| U+F056 | \xef\x81\x96 | Circle minus (lines removed) |
| U+F0993 | \xf3\xb0\xa6\x93 | Files changed |
| U+EE34 | \xee\xb8\xb4 | Sonnet model |
| U+E7D5 | \xee\x9f\x95 | Haiku model |
| U+ED62 | \xee\xb5\xa2 | Opus model (king) |
Finding Your Own Icons
-
Search for what you need (e.g., “git”, “folder”, “clock”)
-
Click the icon to copy it
-
Get the codepoint (e.g.,
f0993) -
Convert to UTF-8 using Python:
python3 -c "print(''.join(f'\\\\x{b:02x}' for b in chr(0xf0993).encode('utf-8')))" -
Use the output in your script
Advanced Customizations
Adding More Segments
Want to add a clock? RAM usage? Custom data? Here’s the pattern:
# Define the color
COLOR_NEW="100;120;100"
# Add the segment
printf "\033[38;2;${PREV_COLOR}m\033[48;2;${COLOR_NEW}m${ARROW_RIGHT}\033[0m"
printf "\033[38;2;${FG}m\033[48;2;${COLOR_NEW}m YOUR_CONTENT \033[0m"
Conditional Segments
The script already shows/hides the git segment based on whether you’re in a repo. You can do the same for any data:
if [ some_condition ]; then
# Show segment
else
# Skip segment or show alternative
fi
Different Themes
Create multiple scripts and switch between them:
~/.claude/statusline-forest.sh
~/.claude/statusline-ocean.sh
~/.claude/statusline-fire.sh
Then update settings.json to use the one you want.
Troubleshooting
Icons Show as Boxes/Question Marks
- Make sure you have a Nerd Font installed
- Configure your terminal to use that font
- Verify with:
echo -e "\ue0b0 \ue0b2 \ue0b6"
Colors Look Wrong
- Ensure your terminal supports true colors
- Test with:
printf "\033[38;2;255;100;0mOrange text\033[0m\n" - If that looks orange, true colors work!
Script Errors
- Make sure
jqis installed:brew install jqorapt install jq - Check script permissions:
chmod +x ~/.claude/statusline-command.sh - Test the script manually:
echo '{}' | ~/.claude/statusline-command.sh
Git Info Not Showing
- Make sure you’re in a git repository
- The script uses
git -Cto work from any subdirectory - Check if git is available:
which git
Resources
- Color Palette Design: Coolors.co
- Starship Presets (inspiration): starship.rs/presets
- Nerd Fonts: nerdfonts.com
- Icon Search: Nerd Fonts Cheat Sheet
- ANSI Escape Codes: Wikipedia
Have questions or want to share your customization? Feel free to reach out!