使用 Claude Code 时,你有没有过这样的体验:一口气让它改了几十个文件,月底看账单才发现花了多少钱;长对话聊到一半被"自动压缩",之前敲定的 SDK 配置、接口约定、踩坑结论被丢得七七八八;想看一眼当前在哪个分支、有没有未提交的改动,还得手动敲
git branch/git status。这三个痛点,靠 Claude Code 的自定义状态栏(Status Line)就能一次性解决。本文从零开始,带你搭一个"专属仪表盘",把每次对话的成本、剩余上下文、Git 分支与改动状态,实时钉在终端底部,再也不用手动查。
目录
- 一、先说说这三个痛点
- 二、状态栏是什么,怎么工作
- [三、3 分钟快速上手](#三、3 分钟快速上手 "#%E4%B8%893-%E5%88%86%E9%92%9F%E5%BF%AB%E9%80%9F%E4%B8%8A%E6%89%8B")
- 四、状态栏能拿到哪些数据
- 五、实战:解决三大痛点的完整状态栏
- 六、进阶技巧
- 七、常见坑与排错
- 八、总结
一、先说说这三个痛点
痛点 1:成本黑洞,月底才见分晓
Claude Code 是按 token 计费的,会话过程中每多一次大改、每多一轮自检,成本都在悄悄累积。但默认界面上看不到任何费用信息,你只能凭感觉估------"应该没花多少吧"。等账单出来才发现,一个下午的重构已经烧掉了好几美元。
如果能把"本次会话累计花费"实时钉在眼前,那种"再让它多改一轮"的手会自然收住。
痛点 2:上下文压缩的"信息蒸发"
长对话是所有 AI 编程助手的宿命。一旦上下文逼近窗口上限,Claude Code 会触发自动压缩(auto-compact):把历史对话摘要化,腾出空间继续干活。
问题是------摘要永远会丢细节。前两轮你确认过的 SDK 版本、某个接口的参数约定、某个踩坑后得出的结论,压缩之后可能只剩下"用户提到过 xxx"。等模型真用到的细节发现没了,要么靠记忆硬编,要么回滚重来,非常痛苦。
如果能在上下文即将逼近红线之前就看到剩余余量,你就能主动决定:是及时收尾、手动换会话,还是先让它把关键信息写进项目文档再继续。
痛点 3:Git 状态全靠手动
在多个分支之间横跳、改了文件忘记 commit 是常态。每次想确认当前分支、有没有未暂存/未提交的改动,都得手动敲 git branch、git status、git diff --stat,既打断思路又容易漏。
如果这些信息常驻终端底部,随会话实时刷新,你就能一直知道自己"站在哪、手里有什么牌"。
二、状态栏是什么,怎么工作
Claude Code 的 状态栏(Status Line) 是终端底部一条可完全自定义的栏。它的工作方式非常简单直观:
- Claude Code 把当前会话的 JSON 数据 通过 stdin 管道传给一个脚本;
- 你的脚本解析 JSON、按需加工(算进度条、拼字符串、读 git 状态);
- 脚本打印到 stdout 的文本,就是状态栏最终显示的内容。
几个值得记住的特性:
- 纯本地运行,不消耗 API token:脚本跑在你自己机器上,白嫖的实时信息。
- 更新时机:每次新的助手消息之后、权限模式变化、Vim 模式切换时触发;更新有 300ms 的防抖合并。如果脚本还没跑完又触发新更新,正在执行的脚本会被取消。
- 空闲会"静默" :当主会话空闲(比如在等后台 subagent 干活)时,事件驱动会停更。这时需要设置
refreshInterval定时刷新,保证 Git 状态这类外部信息依然实时。
三、3 分钟快速上手
方式一:用 /statusline 命令(最省事)
在 Claude Code 里直接发命令,用自然语言描述你想要的效果,它会自动生成脚本并帮你写好配置:
bash
/statusline 显示模型名、上下文使用百分比和一个进度条
它会在 ~/.claude/ 下生成脚本并自动更新 settings.json。想删掉也一样简单:
arduino
/statusline delete
方式二:手动配置(可控性最强)
在用户设置文件 ~/.claude/settings.json(或项目级 settings)里加一个 statusLine 字段:
json
{
"statusLine": {
"type": "command",
"command": "~/.claude/statusline.sh",
"padding": 2
}
}
type固定为"command",表示"运行一条 shell 命令";command指向脚本路径,也可以直接写内联命令 (比如jq一行流);padding可选,控制状态栏内容的额外水平缩进,默认0;refreshInterval可选,单位秒(最小1),让脚本在事件驱动之外再按固定间隔重跑。
以 jq 一行流为例,不用建脚本文件也能显示模型名和上下文百分比:
json
{
"statusLine": {
"type": "command",
"command": "jq -r '\"[\\(.model.display_name)] \\(.context_window.used_percentage // 0)% context\"'"
}
}
脚本的三个硬性要求
- 可执行 :
chmod +x ~/.claude/statusline.sh; - 输出到 stdout,不是 stderr;
- 足够快:慢脚本会阻塞状态栏刷新,直到它跑完。
四、状态栏能拿到哪些数据
Claude Code 通过 stdin 传给脚本的完整 JSON 结构长这样:
json
{
"cwd": "/current/working/directory",
"session_id": "abc123...",
"session_name": "my-session",
"transcript_path": "/path/to/transcript.jsonl",
"model": {
"id": "claude-opus-4-6",
"display_name": "Opus"
},
"workspace": {
"current_dir": "/current/working/directory",
"project_dir": "/original/project/directory",
"added_dirs": [],
"git_worktree": "feature-xyz"
},
"version": "2.1.90",
"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": 8,
"remaining_percentage": 92,
"current_usage": {
"input_tokens": 8500,
"output_tokens": 1200,
"cache_creation_input_tokens": 5000,
"cache_read_input_tokens": 2000
}
},
"exceeds_200k_tokens": false,
"rate_limits": {
"five_hour": { "used_percentage": 23.5, "resets_at": 1738425600 },
"seven_day": { "used_percentage": 41.2, "resets_at": 1738857600 }
},
"vim": { "mode": "NORMAL" },
"agent": { "name": "security-reviewer" },
"worktree": {
"name": "my-feature",
"path": "/path/to/.claude/worktrees/my-feature",
"branch": "worktree-my-feature",
"original_cwd": "/path/to/project",
"original_branch": "main"
}
}
常用字段速查表:
| 字段 | 说明 |
|---|---|
model.id / model.display_name |
当前模型标识 / 展示名 |
workspace.current_dir |
当前工作目录(与 cwd 同值,推荐用这个) |
workspace.project_dir |
启动 Claude Code 时的项目目录 |
workspace.git_worktree |
位于链接 worktree 时的 worktree 名 |
cost.total_cost_usd |
本次会话累计花费(美元) |
cost.total_duration_ms |
会话开始以来的墙钟总时长(毫秒) |
cost.total_api_duration_ms |
等待 API 响应的时间(毫秒) |
cost.total_lines_added / total_lines_removed |
新增 / 删除的代码行数 |
context_window.context_window_size |
上下文窗口上限(默认 200000) |
context_window.used_percentage |
已用上下文百分比(预计算) |
context_window.remaining_percentage |
剩余上下文百分比(预计算) |
context_window.total_input_tokens / total_output_tokens |
会话累计 token 数 |
context_window.current_usage |
最近一次 API 调用的 token 明细 |
exceeds_200k_tokens |
最近一次响应总 token 是否超 20 万 |
rate_limits.five_hour / seven_day |
5 小时 / 7 天速率限制用量与重置时间 |
session_id |
会话唯一标识 |
session_name |
自定义会话名(--name / /rename 设置后才有) |
transcript_path |
对话记录文件路径 |
version |
Claude Code 版本 |
vim.mode |
Vim 模式下的当前模式 |
agent.name |
--agent 模式下的 agent 名 |
worktree.* |
--worktree 会话的 worktree 信息 |
几个容易踩的坑:
session_name、workspace.git_worktree、vim、agent、worktree、rate_limits这些字段可能压根不在 JSON 里,脚本要优雅处理缺失;context_window.current_usage在会话首次 API 调用前是null;used_percentage/remaining_percentage在会话早期也可能是null;- 处理缺失/null 的标准姿势是 jq 的 fallback:
.context_window.used_percentage // 0。
理解 used_percentage 的计算口径 :它只统计"输入类" token,即 input_tokens + cache_creation_input_tokens + cache_read_input_tokens,不包含 output tokens。如果你要自己手算百分比,务必用同一个公式,否则数值会对不上。
五、实战:解决三大痛点的完整状态栏
字段到痛点的映射
| 痛点 | 用到的字段/命令 |
|---|---|
| 每次对话成本 | cost.total_cost_usd(累计花费)+ cost.total_duration_ms(耗时) |
| 上下文余量防压缩 | context_window.used_percentage + remaining_percentage(配进度条和颜色阈值) |
| Git 分支与状态 | 脚本内跑 git branch --show-current / git diff --cached --numstat / git diff --numstat |
完整脚本
保存为 ~/.claude/statusline.sh:
bash
#!/bin/bash
# Claude Code 状态栏:成本 + 上下文余量 + Git 状态
# 输入:Claude Code 通过 stdin 传入的 JSON 会话数据
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)
REMAIN=$(echo "$input" | jq -r '.context_window.remaining_percentage // 0' | cut -d. -f1)
DURATION_MS=$(echo "$input" | jq -r '.cost.total_duration_ms // 0')
# ANSI 颜色(终端需支持)
CYAN='\033[36m'; GREEN='\033[32m'; YELLOW='\033[33m'; RED='\033[31m'; RESET='\033[0m'
# 按上下文占用切换进度条颜色:<70 绿,70-89 黄,>=90 红
if [ "$PCT" -ge 90 ]; then BAR_COLOR="$RED"
elif [ "$PCT" -ge 70 ]; then BAR_COLOR="$YELLOW"
else BAR_COLOR="$GREEN"; fi
# 生成 10 格进度条:█ 已用,░ 剩余
BAR_WIDTH=10
FILLED=$((PCT * BAR_WIDTH / 100))
EMPTY=$((BAR_WIDTH - FILLED))
BAR=""
[ "$FILLED" -gt 0 ] && printf -v F "%${FILLED}s" && BAR="${F// /█}"
[ "$EMPTY" -gt 0 ] && printf -v E "%${EMPTY}s" && BAR="${BAR}${E// /░}"
# 时长:毫秒 -> m s
DURATION_SEC=$((DURATION_MS / 1000))
MINS=$((DURATION_SEC / 60))
SECS=$((DURATION_SEC % 60))
# 成本:保留两位小数
COST_FMT=$(printf '$%.2f' "$COST")
# ---- Git 状态(非 git 仓库时静默跳过)----
BRANCH=""
GIT_STATUS=""
if git rev-parse --git-dir > /dev/null 2>&1; then
BRANCH=$(git branch --show-current 2>/dev/null)
STAGED=$(git diff --cached --numstat 2>/dev/null | wc -l | tr -d ' ')
MODIFIED=$(git diff --numstat 2>/dev/null | wc -l | tr -d ' ')
[ -n "$STAGED" ] && [ "$STAGED" -gt 0 ] && GIT_STATUS="${GREEN}+${STAGED}${RESET}"
[ -n "$MODIFIED" ] && [ "$MODIFIED" -gt 0 ] && GIT_STATUS="${GIT_STATUS}${YELLOW}~${MODIFIED}${RESET}"
fi
# ---- 输出(两行)----
# 第一行:模型 + 目录 + Git 分支/改动
echo -e "${CYAN}[$MODEL]${RESET} 📁 ${DIR##*/} | 🌿 $BRANCH $GIT_STATUS"
# 第二行:上下文进度条 + 已用/剩余 + 成本 + 耗时
echo -e "${BAR_COLOR}${BAR}${RESET} ${PCT}% used / ${REMAIN}% left | ${YELLOW}💰 $COST_FMT${RESET} | ⏱️ ${MINS}m ${SECS}s"
然后:
bash
chmod +x ~/.claude/statusline.sh
配置文件
~/.claude/settings.json:
json
{
"statusLine": {
"type": "command",
"command": "~/.claude/statusline.sh",
"refreshInterval": 5,
"padding": 2
}
}
refreshInterval: 5 是关键:它让脚本每 5 秒强制刷新一次,这样后台 subagent 改代码、你切了分支但会话空闲时,Git 状态也能跟上,不会停留在旧画面。
最终效果
终端底部会出现类似这样的两行常驻信息:
bash
[Opus] 📁 my-app | 🌿 feature/auth +2 ~5
████████░░ 42% used / 58% left | 💰 $0.08 | ⏱️ 7m 3s
- 第一行:当前模型、项目文件夹、Git 分支;
+2表示 2 个文件已暂存(绿色),~5表示 5 个文件已修改(黄色); - 第二行:上下文进度条(红色阈值自动告警)、已用/剩余百分比、本次会话累计花费、会话已耗时。
一眼扫过去,三个痛点全部覆盖:钱花了多少、上下文还剩多少、代码处于什么状态,全都不用再手动查。
六、进阶技巧
1. 缓存 Git 命令,避免大仓库卡顿
状态栏脚本在活跃会话里跑得很频繁,大仓库里 git status / git diff 可能很慢。方案是把 Git 信息写进缓存文件,5 秒内不重复执行。
缓存文件命名有个讲究:必须用 session_id(会话期间稳定、跨会话唯一),而不是 $$ 或 pid------进程号每次调用都会变,缓存就失效了。
bash
SESSION_ID=$(echo "$input" | jq -r '.session_id')
CACHE_FILE="/tmp/statusline-git-cache-$SESSION_ID"
CACHE_MAX_AGE=5
cache_is_stale() {
[ ! -f "$CACHE_FILE" ] || \
[ $(($(date +%s) - $(stat -f %m "$CACHE_FILE" 2>/dev/null || stat -c %Y "$CACHE_FILE" 2>/dev/null || echo 0))) -gt $CACHE_MAX_AGE ]
}
if cache_is_stale; then
if git rev-parse --git-dir > /dev/null 2>&1; then
BRANCH=$(git branch --show-current 2>/dev/null)
STAGED=$(git diff --cached --numstat 2>/dev/null | wc -l | tr -d ' ')
MODIFIED=$(git diff --numstat 2>/dev/null | wc -l | tr -d ' ')
echo "$BRANCH|$STAGED|$MODIFIED" > "$CACHE_FILE"
else
echo "||" > "$CACHE_FILE"
fi
fi
IFS='|' read -r BRANCH STAGED MODIFIED < "$CACHE_FILE"
(stat -f %m 是 macOS 写法,Linux 用 stat -c %Y,上面的 || 已做了兼容。)
2. 多行状态栏
脚本里每个 echo / print 就是一行,想要多少行都行。上面的实战脚本就是两行示例。注意:带转义码的多行输出比纯文本更容易出现渲染毛刺,出问题就简化成纯文本。
3. 颜色阈值告警
用 ANSI 转义码给数值上色,让"健康度"一目了然:
bash
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
4. 显示速率限制(Claude.ai Pro/Max 订阅者)
rate_limits 只对 Claude.ai 订阅用户出现,且要在会话首次 API 响应后才有。用 // empty 优雅处理缺失:
bash
FIVE_H=$(echo "$input" | jq -r '.rate_limits.five_hour.used_percentage // empty')
WEEK=$(echo "$input" | jq -r '.rate_limits.seven_day.used_percentage // empty')
LIMITS=""
[ -n "$FIVE_H" ] && LIMITS="5h: $(printf '%.0f' "$FIVE_H")%"
[ -n "$WEEK" ] && LIMITS="${LIMITS:+$LIMITS }7d: $(printf '%.0f' "$WEEK")%"
[ -n "$LIMITS" ] && echo "[$MODEL] | $LIMITS"
5. 可点击链接(OSC 8)
用 OSC 8 转义序列可以把文本变成可点击链接(macOS 用 Cmd+点击,Windows/Linux 用 Ctrl+点击),比如直接链到 GitHub 仓库。注意 printf '%b' 处理转义比 echo -e 更可靠:
bash
REMOTE=$(git remote get-url origin 2>/dev/null | sed 's/git@github.com:/https:\/\/github.com\//' | sed 's/\.git$//')
if [ -n "$REMOTE" ]; then
REPO_NAME=$(basename "$REMOTE")
printf '%b' "[$MODEL] 🔗 \e]8;;${REMOTE}\a${REPO_NAME}\e]8;;\a\n"
fi
需要 iTerm2 / Kitty / WezTerm 这类支持超链接的终端;macOS 自带 Terminal.app 不支持。如果链接文字出现了但点不了,试试启动前强制开启:
bash
FORCE_HYPERLINK=1 claude
6. Windows 配置
Windows 上状态栏命令通过 Git Bash 运行,可以在里面再调 PowerShell,也可以直接跑 Bash 脚本:
json
{
"statusLine": {
"type": "command",
"command": "powershell -NoProfile -File C:/Users/username/.claude/statusline.ps1"
}
}
7. Subagent 状态栏
subagentStatusLine 可以自定义 agent 面板里每个 subagent 的展示行,输入是一个 JSON 对象,包含 tasks 数组(每个任务有 id、name、status、tokenCount、cwd 等字段)。按 {"id": "<task id>", "content": "<行内容>"} 逐行输出即可覆盖。
七、常见坑与排错
| 症状 | 原因与解法 |
|---|---|
| 状态栏不出现 | ① 脚本没 chmod +x;② 输出到了 stderr 而非 stdout;③ disableAllHooks 被设为 true;④ 当前目录未接受工作区信任 (会提示 statusline skipped · restart to fix,重启并接受信任即可);⑤ 用 claude --debug 查看首次调用的退出码和 stderr |
显示 -- 或空白 |
字段在会话早期是 null。用 jq fallback:.xxx // 0;多条消息后仍为空就重启 Claude Code |
| 上下文百分比不对 | 用预计算的 used_percentage,别用 total_input_tokens(那是会话累计值,会超过窗口);注意百分比仅按输入类 token 计算;它可能与 /context 命令的数值有细微差异(计算时机不同) |
| 状态栏卡住/不刷新 | 脚本太慢会阻塞更新直到跑完。优化:缓存 git 命令、精简逻辑;设置 refreshInterval 让空闲期也刷新 |
| OSC 8 链接点了没反应 | 终端不支持(Terminal.app);或没被自动识别,用 FORCE_HYPERLINK=1 强制;SSH/tmux 可能剥掉转义序列 |
出现 \e]8;; 之类的乱码 |
用 printf '%b' 替代 echo -e |
| 复杂转义导致花屏 | 简化成纯文本或多行普通输出 |
八、总结
Claude Code 的状态栏是一个被低估的"白嫖"功能:本地运行、不耗 token、可无限定制。通过一个不到 40 行的脚本,就能把三个高频痛点全部消灭:
- 成本透明 :
cost.total_cost_usd实时显示,花钱有数; - 上下文可控:进度条 + 颜色阈值预警,在自动压缩之前主动收手或换会话,保住关键细节;
- Git 常驻 :分支 + 暂存/修改状态一眼可见,配合
refreshInterval保证实时。
动手改脚本时记住三条黄金法则:输出到 stdout、处理 null( // 0)、保持脚本足够快。剩下的,交给你的想象力------时钟、天气、速率限制、可点击的仓库链接......状态栏什么都能放。
参考: