# 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)