Files
gh-obra-superpowers-develop…/skills/working-with-claude-code/references/statusline.md
2025-11-30 08:44:51 +08:00

203 lines
5.7 KiB
Markdown

# 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 300ms
* 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
}
}
```
## 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'; }
# Use the helpers
MODEL=$(get_model_name)
DIR=$(get_current_dir)
echo "[$MODEL] 📁 ${DIR##*/}"
```
## 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)