Appearance
Status Line:自定义底部状态栏
Status Line 是 Claude Code 底部可以完全自定义的信息栏,运行你配置的 shell 脚本并显示其输出。脚本通过 stdin 接收 JSON 会话数据,可展示模型名、上下文进度条、会话费用、git 状态、速率限制等任意信息。支持多行输出、ANSI 颜色和 OSC 8 可点击链接。用 /statusline 命令让 Claude 自动生成脚本是最快的入门方式。
Status Line 是 Claude Code 底部可以完全自定义的信息栏。它运行你配置的任何 shell 脚本,把 JSON 会话数据传入脚本,把脚本输出内容显示出来。
常见用途:
- 实时监控上下文窗口使用量(避免突然被压缩)
- 追踪会话费用
- 多会话并行时显示当前会话信息
- 始终显示 git 分支和状态
如果你是从 settings.json 配置指南 过来的,先记住三件事:statusLine 写在 settings 里;脚本路径必须能被当前系统执行;脚本输出到 stdout 的内容就是底部状态栏看到的内容。
快速上手
方法一(推荐):用 /statusline 命令自动生成
直接描述你想显示什么,Claude Code 会自动生成脚本文件并更新 settings:
text
/statusline show model name and context percentage with a progress bar
/statusline 显示模型名、目录、git 分支和上下文进度条方法二:手动配置
在 ~/.claude/settings.json(或项目设置)中添加:
json
{
"statusLine": {
"type": "command",
"command": "~/.claude/statusline.sh",
"padding": 2
}
}padding 字段(可选)在状态栏内容两侧添加额外空格(字符数),默认 0。这是相对缩进,不是到终端边缘的绝对距离。
refreshInterval 字段(可选)每隔 N 秒重新运行一次脚本(最小值 1),不依赖事件触发。适合显示时钟或后台 subagent 修改了 git 状态时主会话处于空闲的场景。不设置则只在事件触发时运行。
最常见的三个配置目标是:显示当前模型、显示上下文百分比、显示 git 分支。先用 /statusline 生成脚本,再按下面的数据字段微调,比从零手写更稳。
或者直接内联命令(用 jq 解析 JSON):
json
{
"statusLine": {
"type": "command",
"command": "jq -r '\"[\\(.model.display_name)] \\(.context_window.used_percentage // 0)% context\"'"
}
}删除 Status Line:运行 /statusline delete(或 clear/remove),或手动删除 settings.json 里的 statusLine 字段。
工作原理
Claude Code 运行你的脚本,通过 stdin 传入 JSON 会话数据,显示脚本打印到 stdout 的内容。
- 更新时机:每次 Claude 回复后、权限模式变更时、vim 模式切换时(有 300ms 防抖)
- 多行输出:每行 echo 对应一行显示
- 颜色:支持 ANSI 转义码
- 链接:支持 OSC 8 转义序列(可点击链接,需终端支持)
- Status Line 在本地运行,不消耗 API token
可用数据字段
脚本通过 stdin 接收的 JSON:
| 字段 | 说明 |
|---|---|
model.id, model.display_name | 当前模型 ID 和显示名称 |
workspace.current_dir | 当前工作目录(推荐用此字段) |
workspace.project_dir | Claude Code 启动时的目录(可能与 cwd 不同) |
workspace.added_dirs | 通过 /add-dir 或 --add-dir 额外添加的目录(空数组若无) |
workspace.git_worktree | 当前目录在 linked git worktree 内时的 worktree 名称(主工作树中不存在此字段) |
cwd | 当前工作目录(同 workspace.current_dir) |
session_name | 用 --name 或 /rename 设置的会话名称(未设置时不存在此字段) |
cost.total_cost_usd | 会话总费用(美元) |
cost.total_duration_ms | 会话总时长(毫秒) |
cost.total_api_duration_ms | 等待 API 响应的总时长(毫秒) |
cost.total_lines_added/removed | 代码增删行数 |
context_window.used_percentage | 上下文窗口使用百分比(预计算好的) |
context_window.remaining_percentage | 剩余百分比 |
context_window.context_window_size | 最大上下文大小(token 数,默认 200000,1M 上下文时为 1000000) |
context_window.total_input_tokens | 会话累计输入 token |
context_window.total_output_tokens | 会话累计输出 token |
context_window.current_usage | 最近一次 API 调用的 token 明细(第一次 API 调用前为 null) |
exceeds_200k_tokens | 是否超过 20 万 token(固定阈值,与实际上下文窗口大小无关) |
rate_limits.five_hour.used_percentage | 5 小时限额使用百分比(0-100,仅 Pro/Max 订阅,首次 API 响应后出现) |
rate_limits.seven_day.used_percentage | 7 天限额使用百分比(0-100) |
rate_limits.five_hour.resets_at | 5 小时窗口重置时间(Unix 秒) |
rate_limits.seven_day.resets_at | 7 天窗口重置时间(Unix 秒) |
session_id | 会话唯一标识 |
transcript_path | 对话记录文件路径 |
version | Claude Code 版本 |
output_style.name | 当前输出风格名称 |
vim.mode | Vim 模式(NORMAL/INSERT,仅启用 vim 模式时存在) |
agent.name | Agent 名称(使用 --agent 时存在) |
worktree.name/path/branch | Worktree 信息(--worktree 会话时存在) |
字段缺失说明:以下字段在特定条件下不存在于 JSON 中(不是 null,而是完全缺失):
session_name:仅当通过--name或/rename设置后才出现workspace.git_worktree:仅在 linked git worktree 中存在vim:仅启用 vim 模式后存在agent:仅使用--agent时存在worktree:仅--worktree会话时存在rate_limits:仅 Pro/Max 订阅且首次 API 响应后存在
脚本中建议用 jq -r '.rate_limits.five_hour.used_percentage // empty' 这类方式安全处理可能缺失的字段。
current_usage 字段说明
json
{
"input_tokens": 8500,
"output_tokens": 1200,
"cache_creation_input_tokens": 5000,
"cache_read_input_tokens": 2000
}used_percentage 只基于输入 token 计算:input_tokens + cache_creation_input_tokens + cache_read_input_tokens,不含 output_tokens。
实用示例
以下示例保存为脚本后需要 chmod +x 赋权,再在 settings.json 中配置路径。
上下文进度条(Bash)
bash
#!/bin/bash
input=$(cat)
MODEL=$(echo "$input" | jq -r '.model.display_name')
PCT=$(echo "$input" | jq -r '.context_window.used_percentage // 0' | cut -d. -f1)
BAR_WIDTH=10
FILLED=$((PCT * BAR_WIDTH / 100))
EMPTY=$((BAR_WIDTH - FILLED))
BAR=""
[ "$FILLED" -gt 0 ] && printf -v FILL "%${FILLED}s" && BAR="${FILL// /▓}"
[ "$EMPTY" -gt 0 ] && printf -v PAD "%${EMPTY}s" && BAR="${BAR}${PAD// /░}"
echo "[$MODEL] $BAR $PCT%"Git 状态 + 颜色(Python)
python
#!/usr/bin/env python3
import json, sys, subprocess, os
data = json.load(sys.stdin)
model = data['model']['display_name']
directory = os.path.basename(data['workspace']['current_dir'])
GREEN, YELLOW, RESET = '\033[32m', '\033[33m', '\033[0m'
try:
subprocess.check_output(['git', 'rev-parse', '--git-dir'], stderr=subprocess.DEVNULL)
branch = subprocess.check_output(['git', 'branch', '--show-current'], text=True).strip()
staged_output = subprocess.check_output(['git', 'diff', '--cached', '--numstat'], text=True).strip()
modified_output = subprocess.check_output(['git', 'diff', '--numstat'], text=True).strip()
staged = len(staged_output.split('\n')) if staged_output else 0
modified = len(modified_output.split('\n')) if modified_output else 0
git_status = f"{GREEN}+{staged}{RESET}" if staged else ""
git_status += f"{YELLOW}~{modified}{RESET}" if modified else ""
print(f"[{model}] 📁 {directory} | 🌿 {branch} {git_status}")
except:
print(f"[{model}] 📁 {directory}")费用 + 时长(Node.js)
javascript
#!/usr/bin/env node
let input = '';
process.stdin.on('data', chunk => input += chunk);
process.stdin.on('end', () => {
const data = JSON.parse(input);
const model = data.model.display_name;
const cost = data.cost?.total_cost_usd || 0;
const durationMs = data.cost?.total_duration_ms || 0;
const mins = Math.floor(durationMs / 60000);
const secs = Math.floor((durationMs % 60000) / 1000);
console.log(`[${model}] 💰 $${cost.toFixed(2)} | ⏱️ ${mins}m ${secs}s`);
});双行状态栏(颜色进度条 + git)
bash
#!/bin/bash
input=$(cat)
MODEL=$(echo "$input" | jq -r '.model.display_name')
DIR=$(echo "$input" | jq -r '.workspace.current_dir')
COST=$(echo "$input" | jq -r '.cost.total_cost_usd // 0')
PCT=$(echo "$input" | jq -r '.context_window.used_percentage // 0' | cut -d. -f1)
DURATION_MS=$(echo "$input" | jq -r '.cost.total_duration_ms // 0')
CYAN='\033[36m'; GREEN='\033[32m'; YELLOW='\033[33m'; RED='\033[31m'; RESET='\033[0m'
if [ "$PCT" -ge 90 ]; then BAR_COLOR="$RED"
elif [ "$PCT" -ge 70 ]; then BAR_COLOR="$YELLOW"
else BAR_COLOR="$GREEN"; fi
FILLED=$((PCT / 10)); EMPTY=$((10 - FILLED))
printf -v FILL "%${FILLED}s"; printf -v PAD "%${EMPTY}s"
BAR="${FILL// /█}${PAD// /░}"
MINS=$((DURATION_MS / 60000)); SECS=$(((DURATION_MS % 60000) / 1000))
BRANCH=""
git rev-parse --git-dir > /dev/null 2>&1 && BRANCH=" | 🌿 $(git branch --show-current 2>/dev/null)"
echo -e "${CYAN}[$MODEL]${RESET} 📁 ${DIR##*/}$BRANCH"
COST_FMT=$(printf '$%.2f' "$COST")
echo -e "${BAR_COLOR}${BAR}${RESET} ${PCT}% | ${YELLOW}${COST_FMT}${RESET} | ⏱️ ${MINS}m ${SECS}s"Windows PowerShell 配置
json
{
"statusLine": {
"type": "command",
"command": "powershell -NoProfile -File C:/Users/username/.claude/statusline.ps1"
}
}powershell
$input_json = $input | Out-String | ConvertFrom-Json
$model = $input_json.model.display_name
$cwd = $input_json.cwd
$used = $input_json.context_window.used_percentage
$dirname = Split-Path $cwd -Leaf
if ($used) {
Write-Host "$dirname [$model] ctx: $used%"
} else {
Write-Host "$dirname [$model]"
}性能技巧:缓存慢操作
Status line 频繁触发。git status 在大型仓库里可能很慢。用缓存文件避免每次都运行:
bash
CACHE_FILE="/tmp/statusline-git-cache"
CACHE_MAX_AGE=5 # 秒
# 检查缓存是否过期
if [ ! -f "$CACHE_FILE" ] || [ $(($(date +%s) - $(stat -f %m "$CACHE_FILE" 2>/dev/null || stat -c %Y "$CACHE_FILE"))) -gt $CACHE_MAX_AGE ]; then
# 更新缓存
git rev-parse --git-dir > /dev/null 2>&1 && echo "$(git branch --show-current)" > "$CACHE_FILE" || echo "" > "$CACHE_FILE"
fi
BRANCH=$(cat "$CACHE_FILE")使用固定文件名(如
/tmp/statusline-git-cache),不要用$$或PID——每次 status line 调用是新进程,PID 每次不同,缓存永远不会被复用。
调试技巧
手动测试脚本:
bash
echo '{"model":{"display_name":"Opus"},"context_window":{"used_percentage":25},"cost":{"total_cost_usd":0.05},"workspace":{"current_dir":"/home/user/project"}}' | ~/.claude/statusline.sh常见问题:
- 不显示:确认脚本有执行权限(
chmod +x);确认脚本输出到 stdout;disableAllHooks: true时 status line 也会禁用 - 显示
--或空值:第一次 API 响应前某些字段为 null,用// 0提供回退值 - 上下文百分比异常:用
used_percentage而非累计 token 数计算;累计 token 可能超过上下文窗口大小 - OSC 8 链接不可点击:需要 iTerm2、Kitty、WezTerm 等支持 OSC 8 的终端;Terminal.app 不支持
- ANSI 转义码显示乱码:简化为纯文本输出,多行 + 转义码更容易出现渲染问题
- 工作区信任:未接受工作区信任对话框时,status line 不会运行,显示
statusline skipped · restart to fix
相关文档
常见问题
Q: 状态栏不显示,怎么开启?
A: 运行 /statusline 命令生成配置,或在 settings.json 中设置 "statusLine": {"type": "command", "command": "~/.claude/statusline.sh"}。如果在 VS Code 集成终端中使用,还需要确保终端支持并已接受工作区信任对话框,否则会显示 statusline skipped · restart to fix。
Q: 状态栏显示的信息可以自定义吗?
A: 可以。状态栏支持自定义脚本输出——在 settings.json 中配置 statusline.command 指向你的脚本,脚本输出会显示在状态栏中。也可以通过内置模板配置显示模型名称、git 分支、工作目录等预设信息。
Q: 状态栏显示 ANSI 乱码怎么处理?
A: 将状态栏脚本的输出改为纯文本,移除 ANSI 颜色转义码。状态栏在某些终端下对转义码的处理方式与常规输出不同,纯文本最兼容。
Q: 怎么在状态栏显示 token 用量?
A: 优先读取 context_window.used_percentage 显示上下文百分比;如果要显示最近一次请求的明细,再读取 context_window.current_usage.input_tokens、cache_creation_input_tokens 和 cache_read_input_tokens。不要只看累计 token 数,因为累计值可能超过当前上下文窗口。