# Status line configuration¶
¶
> Create a custom status line for Claude Code to display contextual information¶
¶
Make Claude Code your own with a custom status line that displays at the bottom of the Claude Code interface, similar to how terminal prompts (PS1) work in shells like Oh-my-zsh.¶
¶
## Create a custom status line¶
¶
You can either:¶
¶
* Run `/statusline` to ask Claude Code to help you set up a custom status line. By default, it will try to reproduce your terminal's prompt, but you can provide additional instructions about the behavior you want to Claude Code, such as `/statusline show the model name in orange`¶
¶
* Directly add a `statusLine` command to your `.claude/settings.json`:¶
¶
```json theme={null}¶
{¶
"statusLine": {¶
"type": "command",¶
"command": "~/.claude/statusline.sh",¶
"padding": 0 // Optional: set to 0 to let status line go to edge¶
}¶
}¶
```¶
¶
## How it Works¶
¶
* The status line is updated when the conversation messages update¶
* Updates run at most every 300 ms¶
* The first line of stdout from your command becomes the status line text¶
* ANSI color codes are supported for styling your status line¶
* Claude Code passes contextual information about the current session (model, directories, etc.) as JSON to your script via stdin¶
¶
## JSON Input Structure¶
¶
Your status line command receives structured data via stdin in JSON format:¶
¶
```json theme={null}¶
{¶
"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¶
}¶
}¶
}¶
```¶
¶
## Example Scripts¶
¶
### Simple Status Line¶
¶
```bash theme={null}¶
#!/bin/bash¶
# Read JSON input from stdin¶
input=$(cat)¶
¶
# Extract values using jq¶
MODEL_DISPLAY=$(echo "$input" | jq -r '.model.display_name')¶
CURRENT_DIR=$(echo "$input" | jq -r '.workspace.current_dir')¶
¶
echo "[$MODEL_DISPLAY] 📁 ${CURRENT_DIR##*/}"¶
```¶
¶
### Git-Aware Status Line¶
¶
```bash theme={null}¶
#!/bin/bash¶
# Read JSON input from stdin¶
input=$(cat)¶
¶
# Extract values using jq¶
MODEL_DISPLAY=$(echo "$input" | jq -r '.model.display_name')¶
CURRENT_DIR=$(echo "$input" | jq -r '.workspace.current_dir')¶
¶
# Show git branch if in a git repo¶
GIT_BRANCH=""¶
if git rev-parse --git-dir > /dev/null 2>&1; then¶
BRANCH=$(git branch --show-current 2>/dev/null)¶
if [ -n "$BRANCH" ]; then¶
GIT_BRANCH=" | 🌿 $BRANCH"¶
fi¶
fi¶
¶
echo "[$MODEL_DISPLAY] 📁 ${CURRENT_DIR##*/}$GIT_BRANCH"¶
```¶
¶
### Python Example¶
¶
```python theme={null}¶
#!/usr/bin/env python3¶
import json¶
import sys¶
import os¶
¶
# Read JSON from stdin¶
data = json.load(sys.stdin)¶
¶
# Extract values¶
model = data['model']['display_name']¶
current_dir = os.path.basename(data['workspace']['current_dir'])¶
¶
# Check for git branch¶
git_branch = ""¶
if os.path.exists('.git'):¶
try:¶
with open('.git/HEAD', 'r') as f:¶
ref = f.read().strip()¶
if ref.startswith('ref: refs/heads/'):¶
git_branch = f" | 🌿 {ref.replace('ref: refs/heads/', '')}"¶
except:¶
pass¶
¶
print(f"[{model}] 📁 {current_dir}{git_branch}")¶
```¶
¶
### Node.js Example¶
¶
```javascript theme={null}¶
#!/usr/bin/env node¶
¶
const fs = require('fs');¶
const path = require('path');¶
¶
// Read JSON from stdin¶
let input = '';¶
process.stdin.on('data', chunk => input += chunk);¶
process.stdin.on('end', () => {¶
const data = JSON.parse(input);¶
¶
// Extract values¶
const model = data.model.display_name;¶
const currentDir = path.basename(data.workspace.current_dir);¶
¶
// Check for git branch¶
let gitBranch = '';¶
try {¶
const headContent = fs.readFileSync('.git/HEAD', 'utf8').trim();¶
if (headContent.startsWith('ref: refs/heads/')) {¶
gitBranch = ` | 🌿 ${headContent.replace('ref: refs/heads/', '')}`;¶
}¶
} catch (e) {¶
// Not a git repo or can't read HEAD¶
}¶
¶
console.log(`[${model}] 📁 ${currentDir}${gitBranch}`);¶
});¶
```¶
¶
### Helper Function Approach¶
¶
For more complex bash scripts, you can create helper functions:¶
¶
```bash theme={null}¶
#!/bin/bash¶
# Read JSON input once¶
input=$(cat)¶
¶
# Helper functions for common extractions¶
get_model_name() { echo "$input" | jq -r '.model.display_name'; }¶
get_current_dir() { echo "$input" | jq -r '.workspace.current_dir'; }¶
get_project_dir() { echo "$input" | jq -r '.workspace.project_dir'; }¶
get_version() { echo "$input" | jq -r '.version'; }¶
get_cost() { echo "$input" | jq -r '.cost.total_cost_usd'; }¶
get_duration() { echo "$input" | jq -r '.cost.total_duration_ms'; }¶
get_lines_added() { echo "$input" | jq -r '.cost.total_lines_added'; }¶
get_lines_removed() { echo "$input" | jq -r '.cost.total_lines_removed'; }¶
get_input_tokens() { echo "$input" | jq -r '.context_window.total_input_tokens'; }¶
get_output_tokens() { echo "$input" | jq -r '.context_window.total_output_tokens'; }¶
get_context_window_size() { echo "$input" | jq -r '.context_window.context_window_size'; }¶
¶
# Use the helpers¶
MODEL=$(get_model_name)¶
DIR=$(get_current_dir)¶
echo "[$MODEL] 📁 ${DIR##*/}"¶
```¶
¶
### Context Window Usage¶
¶
Display the percentage of context window consumed. The `context_window` object contains:¶
¶
* `total_input_tokens` / `total_output_tokens`: Cumulative totals across the entire session¶
* `used_percentage`: Pre-calculated percentage of context window used (0-100)¶
* `remaining_percentage`: Pre-calculated percentage of context window remaining (0-100)¶
* `current_usage`: Current context window usage from the last API call (may be `null` if no messages yet)¶
* `input_tokens`: Input tokens in current context¶
* `output_tokens`: Output tokens generated¶
* `cache_creation_input_tokens`: Tokens written to cache¶
* `cache_read_input_tokens`: Tokens read from cache¶
¶
For acYou can use the pre-calcurlate context percentage, use `current_usage` which reflects the actual d `used_percentage` and `remaining_percentage` fields directly, or calculate from `current_usage` for more control.¶
¶
**Simple approach using pre-calculated percentages:**¶
¶
```bash theme={null}¶
#!/bin/bash¶
input=$(cat)¶
¶
MODEL=$(echo "$input" | jq -r '.model.display_name')¶
PERCENT_USED=$(echo "$input" | jq -r '.context _window state:.used_percentage // 0')¶
¶
echo "[$MODEL] Context: ${PERCENT_USED}%"¶
```¶
¶
**Advanced approach with manual calculation:**¶
¶
```bash theme={null}¶
#!/bin/bash¶
input=$(cat)¶
¶
MODEL=$(echo "$input" | jq -r '.model.display_name')¶
CONTEXT_SIZE=$(echo "$input" | jq -r '.context_window.context_window_size')¶
USAGE=$(echo "$input" | jq '.context_window.current_usage')¶
¶
if [ "$USAGE" != "null" ]; then¶
# Calculate current context from current_usage fields¶
CURRENT_TOKENS=$(echo "$USAGE" | jq '.input_tokens + .cache_creation_input_tokens + .cache_read_input_tokens')¶
PERCENT_USED=$((CURRENT_TOKENS * 100 / CONTEXT_SIZE))¶
echo "[$MODEL] Context: ${PERCENT_USED}%"¶
else¶
echo "[$MODEL] Context: 0%"¶
fi¶
```¶
¶
## Tips¶
¶
* Keep your status line concise - it should fit on one line¶
* Use emojis (if your terminal supports them) and colors to make information scannable¶
* Use `jq` for JSON parsing in Bash (see examples above)¶
* Test your script by running it manually with mock JSON input: `echo '{"model":{"display_name":"Test"},"workspace":{"current_dir":"/test"}}' | ./statusline.sh`¶
* Consider caching expensive operations (like git status) if needed¶
¶
## Troubleshooting¶
¶
* If your status line doesn't appear, check that your script is executable (`chmod +x`)¶
* Ensure your script outputs to stdout (not stderr)¶
¶
¶
---¶
¶
> To find navigation and other pages in this documentation, fetch the llms.txt file at: https://code.claude.com/docs/llms.txt