第 17 章 Status Line / Output Style / 主题
终端配置三件套——主题、Status Line、Output Style——是 Claude Code 里性价比最高的一组个性化:十几分钟配置,换来每天几十次的视觉舒适与信息直达。这一章讲清三件事各自管什么、怎么配、配错了怎么排。
17.1 结论:三件套各管一件事,低成本高收益
| 配置 | 管什么 | 配置位置 | 改变的是什么 |
|---|---|---|---|
| 主题(theme) | 颜色看着舒不舒服 | /theme 或 /config | Claude Code 自身渲染的颜色 token |
| Status Line | 底部状态栏显示什么信息 | settings.json 的 statusLine 键 | 一段 shell 脚本的 stdout |
| Output Style | Claude 回复的角色/语气/格式 | /config 或 outputStyle 字段 | 系统提示词(system prompt) |
三者互不冲突,可独立配置。主题管「眼睛」,Status Line 管「信息一目了然」,Output Style 管「输出形态」。三件套之外,/config 里还有 editorMode、通知通道、tmux 配置等终端层选项,一并归到本章末尾。
一个判断原则:主题和 Status Line 是「看」的配置,改了立刻生效;Output Style 是「说」的配置,改了要 /clear 或重开会话才生效——因为它修改的是系统提示词,而系统提示词只在会话启动时读一次。这个差异是新手最常踩的坑。
17.2 主题:/theme 与 auto 自动检测
17.2.1 内置主题与 auto 检测
/theme 命令(或 /config 里的主题选择器)列出内置预设主题。选 auto 会自动检测终端的明暗背景,Claude Code 的配色随之跟随——只要你的终端本身会跟着 OS 切深浅,auto 就能让 Claude Code 一起跟着切。
注意边界:Claude Code 不控制终端自身的配色。终端的深浅主题由终端应用(iTerm2、Ghostty、Terminal.app 等)决定,Claude Code 只能在终端给定的明暗背景下,调整自己界面的前景色、强调色、diff 配色等。所以「主题不匹配」通常是终端没切深色而 Claude Code 选了暗色预设,或反过来——选 auto 即可让两者联动。
17.2.2 自定义主题
/theme 列表末尾有 New custom theme…,交互式创建:命名 → 逐个挑要覆盖的颜色 token。主题文件是 ~/.claude/themes/<slug>.json,三个字段:
| 字段 | 作用 | 默认 |
|---|---|---|
name | /theme 里显示的标签 | 文件名 slug |
base | 基础预设:dark/light/dark-daltonized/light-daltonized/dark-ansi/light-ansi | dark |
overrides | 要覆盖的颜色 token 映射 | 空 |
颜色值接受 #rrggbb、#rgb、rgb(r,g,b)、ansi256(n)、ansi:<name>(如 ansi:redBright)。未知 token 与非法颜色值会被忽略,笔误不会搞坏渲染。
示例(Dracula 风格,基于 dark 预设覆盖三个 token):
{
"name": "Dracula",
"base": "dark",
"overrides": {
"claude": "#bd93f9",
"error": "#ff5555",
"success": "#50fa7b"
}
}claude token 控制品牌强调色(spinner、助手标签),error/success 控制状态色。Claude Code 会监听 ~/.claude/themes/ 目录变化,编辑器里改了 JSON,运行中的会话即时生效,无需重启。
命令 + 验证:
# 1. 写入主题文件
# (用编辑器保存上面 JSON 到 ~/.claude/themes/dracula.json)
# 2. 在 Claude Code 会话里
/theme # 列表里应出现 "Dracula",选中预期输出:界面强调色变紫,错误信息变红,成功信息变绿。
失败边界:
- 主题文件 JSON 语法错误 → 整个主题被忽略,回退到上一次有效主题,无报错提示。用
jq . ~/.claude/themes/dracula.json先校验语法。 base写错(如拼成Dark)→ 回退到dark,大小写敏感。- 插件也能贡献主题,装了插件后
/theme列表会多出条目;卸载插件即移除。
17.3 Status Line:底部状态栏的自定义脚本
17.3.1 工作原理
Status Line 是 Claude Code 底部的一行可定制状态栏。你在 settings.json 配一个 shell 脚本,Claude Code 把当前会话的 JSON 数据通过 stdin 喂给脚本,脚本的 stdout 就是状态栏显示的内容。
数据流:
Claude Code 会话事件 ──> JSON via stdin ──> 你的脚本 ──> stdout ──> 底部状态栏更新时机:每次助手消息结束后、/compact 完成后、权限模式切换时、vim 模式切换时。更新有 300ms 去抖,连续变更会合并成一次执行。脚本运行中又来新事件,在途执行会被取消。
配置位置:~/.claude/settings.json(用户级)或项目级 .claude/settings.json。关键字段:
| 字段 | 作用 | 默认 |
|---|---|---|
type | 固定 "command" | — |
command | 脚本路径或 inline shell 命令 | — |
padding | 额外水平留白(字符数) | 0 |
refreshInterval | 每 N 秒额外重跑一次(最小 1),用于时钟/后台子代理变更 | 不设,仅事件驱动 |
hideVimModeIndicator | 抑制内置 -- INSERT--(脚本自己渲染 vim.mode 时用) | false |
17.3.2 stdin JSON 字段速查(2026-07-08 核对 v2.1.202+)
完整 schema 见官方文档,本章只列实战常用字段:
| 字段 | 含义 |
|---|---|
model.display_name | 当前模型显示名(Opus/Sonnet/Haiku/Fable) |
workspace.current_dir | 当前工作目录(与 cwd 同值,优先用前者) |
workspace.project_dir | 启动目录(会话中 cd 后与 current_dir 不同) |
workspace.repo.{host,owner,name} | origin 远程解析出的仓库身份(非 git 仓库或缺 origin 时缺省) |
cost.total_cost_usd | 会话累计估算成本(客户端计算,可能与账单有出入) |
cost.total_duration_ms | 会话墙钟时长 |
context_window.used_percentage | 上下文窗口已用百分比(预计算) |
context_window.context_window_size | 上下文窗口上限(200000 或 1000000) |
effort.level | 推理档(low/medium/high/xhigh/max;ultracode 报为 xhigh) |
output_style.name | 当前 output style 名 |
vim.mode | vim 模式(NORMAL/INSERT/VISUAL 等),仅启用 vim 时存在 |
session_id | 会话唯一标识(可做缓存 key) |
rate_limits.five_hour.used_percentage | 5 小时滚动窗口用量百分比(仅 Pro/Max 订阅、首次 API 响应后) |
重要缺失字段:permission_mode 不在 stdin JSON 里(2026-07-08 核对 v2.1.202+)。状态栏会在权限模式切换时刷新,但脚本读不到当前权限模式值。最接近的代理字段是 effort.level 与 output_style.name。本章实战脚本因此显示 effort 档而非权限模式——这是官方 schema 的真实限制,不是脚本写错。
17.3.3 实战:一个 [模型|git分支|成本|effort档] 状态栏
第一步:写脚本 ~/.claude/statusline.sh:
#!/usr/bin/env bash
# ~/.claude/statusline.sh
# Layout: [Opus | main | $0.0421 | effort:high]
set -euo pipefail
input="$(cat)"
# 用 jq 解析,所有字段都给 // 回退,防 null/缺失
model=$(printf '%s' "$input" | jq -r '.model.display_name // "—"')
cost=$(printf '%s' "$input" | jq -r '.cost.total_cost_usd // 0')
effort=$(printf '%s' "$input" | jq -r '.effort.level // "—"')
cwd=$(printf '%s' "$input" | jq -r '.workspace.current_dir // .cwd // ""')
# git 分支:不在 git 仓库则留空
branch=""
if [[ -n "$cwd" ]]; then
branch=$(git -C "$cwd" symbolic-ref --short HEAD 2>/dev/null \
|| git -C "$cwd" rev-parse --short HEAD 2>/dev/null \
|| true)
fi
# ANSI 配色
C_CYAN=$'\033[36m'; C_GREEN=$'\033[32m'; C_YELLOW=$'\033[33m'
C_DIM=$'\033[2m'; C_RESET=$'\033[0m'
cost_fmt=$(printf '$%.4f' "$cost")
parts=("${C_CYAN}${model}${C_RESET}")
[[ -n "$branch" ]] && parts+=("${C_GREEN}${branch}${C_RESET}")
parts+=("${C_YELLOW}${cost_fmt}${C_RESET}")
parts+=("${C_DIM}effort:${effort}${C_RESET}")
# 用 " | " 连接
IFS=' | '
printf '%s' "${parts[*]}"第二步:配置 settings.json(合并进 ~/.claude/settings.json):
{
"statusLine": {
"type": "command",
"command": "~/.claude/statusline.sh",
"padding": 2
}
}第三步:验证(三个层次):
# 1. 脚本可执行
chmod +x ~/.claude/statusline.sh
# 2. 喂模拟 JSON,看输出
echo '{"model":{"display_name":"Opus"},"workspace":{"current_dir":"/Users/mba/claude"},"cost":{"total_cost_usd":0.0421},"effort":{"level":"high"}}' | ~/.claude/statusline.sh
# 预期输出(带 ANSI 颜色):
# Opus | main | $0.0421 | effort:high
# (若当前目录不在 git 仓库,分支段缺省,输出: Opus | $0.0421 | effort:high)
# 3. 进 Claude Code 会话,发一条消息触发刷新,底部应出现状态栏第四步:排错。看不到状态栏时按顺序排查:
disableAllHooks: true会一并禁用 statusLine——检查 settings.json 里没有这个字段或为false。- 工作区信任未接受 → 状态栏显示
statusline skipped · restart to fix,重启并接受信任对话框。 - 脚本输出到 stderr 而非 stdout → 状态栏空白。脚本里所有输出走 stdout。
- 脚本非零退出或无输出 → 状态栏空白。用
claude --debug看首次执行的退出码与 stderr。 jq未安装 →brew install jq(macOS)或apt install jq(Debian)。- 路径含反斜杠(Windows Git Bash)→ 改用正斜杠,如
~/.claude/statusline.sh。
捷径:/statusline 命令接受自然语言,直接生成脚本并写入 settings。例如 /statusline 显示模型名和上下文百分比,带进度条。适合不想手写脚本时快速起步,但生成结果仍建议按上面三步验证一遍。
17.3.4 进阶:缓存慢操作
git status 在大仓库里可能很慢,而状态栏脚本运行频繁。用 session_id 做缓存 key(进程 ID $$ 每次变,不能做 key),5 秒刷新一次:
cache="/tmp/cc-statusline-${session_id}.cache"
if [[ ! -f "$cache" ]] || [[ $(($(date +%s) - $(stat -f %m "$cache" 2>/dev/null || echo 0))) -gt 5 ]]; then
git -C "$cwd" status --porcelain 2>/dev/null > "$cache"
fi
# 读 $cache 而非每次调 gitstat -f %m 是 macOS 写法,Linux 用 stat -c %Y。跨平台脚本里用 date -r "$cache" +%s 更稳。
17.4 Output Style:控制回复的角色与格式
17.4.1 内置风格(2026-07-08 核对)
Output Style 修改的是系统提示词,决定 Claude「以什么角色、什么语气、什么格式」回复。内置共 4 种:
| 风格 | 行为 | 适用 |
|---|---|---|
| Default | 原始系统提示词,高效完成软件工程任务 | 默认,大多数场景 |
| Proactive | 立即执行,对常规决策做合理假设而非停下来问,行动优先于规划 | 比自动模式更强的自主执行引导,不改权限模式仍弹权限提示 |
| Explanatory | 在完成任务的同时提供教学性「Insights」,解释实现选择与代码库模式 | 学习陌生代码库 |
| Learning | 协作式做中学,Claude 不仅给 Insight 还会让你亲手写小段战略代码,在代码里插 TODO(human) 标记 | 教学场景 |
切换:/config → Output style 选菜单,或直接编辑 settings 文件的 outputStyle 字段。/config 菜单选中的值写入项目级 .claude/settings.local.json:
{
"outputStyle": "Explanatory"
}关键限制:Output Style 是系统提示词的一部分,会话启动时读一次。改完必须 /clear 或重开会话才生效。这是 output style 与 theme/statusLine 最大的行为差异——后两者改了立刻可见,output style 不是。
17.4.2 自定义 Output Style
自定义 output style 是一个 Markdown 文件:frontmatter + 自然语言指令。放 ~/.claude/output-styles/<name>.md(用户级),插件则放自己的 output-styles/ 目录。
frontmatter 字段:
| 字段 | 作用 | 默认 |
|---|---|---|
name | 风格名(不写则用文件名) | 文件名 |
description | /config 选择器里显示的描述 | 无 |
keep-coding-instructions | 是否保留 Claude Code 内置软件工程指令 | false |
force-for-plugin | 仅插件风格:插件启用时自动应用,覆盖用户 outputStyle | false |
keep-coding-instructions 是关键选择:
- 改 Claude 怎么说话但还在写代码(如「永远用图回答」)→ 设
true,保留内置工程指令 - Claude 根本不做软件工程(如写作助手、数据分析师)→ 设
false,丢掉内置工程指令,你的指令全权接管
17.4.3 实战:写一个「简短工程向」output style
目标:只给结论与 diff,不废话,适合熟练开发者日常编码。
第一步:写文件 ~/.claude/output-styles/concise-eng.md:
---
name: concise-eng
description: 简短工程向——结论先行,只给 diff 与命令,不寒暄
keep-coding-instructions: true
---
# Concise Engineering Style
你是简短工程向助手。遵守:
## 输出规则
1. **结论先行**:第一句直接给可执行答案,不铺垫。
2. **代码用 diff,命令用代码块**:不解释显而易见的内容。
3. **禁止寒暄**:不要「好的」「当然可以」「我来帮你」;不复述用户问题。
4. **风险与前提**:仅在有非显而易见风险或前提时补充,限一两行。
5. **验证**:给出运行的验证命令及结果摘要,不描述过程。
## 仍然详细的情况
- 用户明确要求「解释」「为什么」时。
- 涉及破坏性操作或安全风险时。
- 首次引入新概念时,可附一句话定义。
## 默认长度
- 简单任务:3-8 行。
- 中等任务:不超过 20 行。
- 复杂任务:结论 + diff + 验证,不写叙述段落。第二步:应用。两种方式:
# 方式一:菜单(官方文档推荐路径)
/config
# 选 Output style → concise-eng
# 方式二:直接命令(本书第 06 章命令表列为内置,v2.1.202+)
/output-style concise-eng写入位置:项目级 .claude/settings.local.json 的 outputStyle 字段(值 "concise-eng")。
第三步:验证(注意必须重开会话或 /clear):
# 1. 切换后 /clear
/clear
# 2. 问一个简单任务
> 在 src/utils.ts 加个 noop 函数导出
# 预期输出(简短工程向):
# 已加。diff:
# +export const noop = () => {};
# 验证:tsc --noEmit src/utils.ts(通过)对比 Default 风格下同一问题的输出(会多出「我来帮你在...」「这个函数的作用是...」「你可以这样使用...」等叙述),差异明显。
第四步:失败边界:
- 切换后输出没变 → 九成是没
/clear或重开会话。Output Style 改系统提示词,只在会话启动时读。 /config选不到自定义风格 → 文件不在~/.claude/output-styles/或 frontmatter 格式错误。用head -5 ~/.claude/output-styles/concise-eng.md检查 frontmatter 三横线闭合。- 输出变得僵硬/残缺 →
keep-coding-instructions: false丢了内置工程指令,Claude 不再自动遵循「修改范围、写注释、验证工作」等纪律。写代码场景务必设true。 - Token 成本上升 → 自定义指令加进系统提示词,增加输入 token;Explanatory/Learning 还会让输出变长。prompt caching 会降低首次后的成本,但首次成本真实存在。
force-for-plugin: true冲突 → 多个启用插件都设了该字段,Claude Code 用第一个加载的,行为不可预测。插件风格慎用此字段。
17.5 终端配置:editorMode 与其他 /config 项
/config 里还有几个终端层选项,归到这里一并讲。
17.5.1 editorMode:vim 键位
/config → Editor mode 选 vim 或 normal,或 settings.json:
{ "editorMode": "vim" }vim 模式支持 NORMAL/VISUAL 子集:hjkl 移动、v/V 选择、d/c/y 配 text object。注意:INSERT 模式下按 Enter 仍提交消息(与标准 vim 不同),换行用 o/O(NORMAL)或 Ctrl+J。vim 按位不可通过 keybindings 文件重映射。
/vim 命令已移除(见第 06 章命令真实性表),正确路径是 /config 或 editorMode 字段。
17.5.2 通知:preferredNotifChannel 与 Notification hook
Claude 完成任务或等权限提示时触发通知事件。默认只在 Ghostty/Kitty/iTerm2 发桌面通知;其他终端设:
{ "preferredNotifChannel": "terminal_bell" }终端响铃。要自定义声音/命令,配 Notification hook(第 14 章):
{
"hooks": {
"Notification": [
{ "hooks": [{ "type": "command", "command": "afplay /System/Library/Sounds/Glass.aiff" }] }
]
}
}17.5.3 Shift+Enter 与 Option 键:/terminal-setup
Shift+Enter 换行支持因终端而异:Ghostty/Kitty/iTerm2/Warp/Apple Terminal/Windows Terminal 开箱即用;VS Code/Cursor/Alacritty/Zed 需跑一次 /terminal-setup 写入终端配置;gnome-terminal/JetBrains 系不可用,用 Ctrl+J 或 \ 加 Enter。
macOS 上 Option 键快捷键(如 Option+Enter 换行、Option+P 切模型)默认不工作,需在终端设置「Use Option as Meta Key」。Apple Terminal/iTerm2 上 /terminal-setup 会帮你开。
17.5.4 tmux 与 fullscreen
tmux 下两件事默认坏:Shift+Enter 不换行、桌面通知与进度条到不了外层终端。~/.tmux.conf 加:
set -g allow-passthrough on
set -s extended-keys on
set -as terminal-features 'xterm*:extkeys'然后 tmux source-file ~/.tmux.conf。显示闪烁或滚动跳跃时,/tui fullscreen 切全屏渲染(对话保留),或设环境变量 CLAUDE_CODE_NO_FLICKER 让其默认全屏。
17.6 失败边界汇总
| 症状 | 根因 | 排查 |
|---|---|---|
| 状态栏空白 | 脚本非零退出 / 输出走 stderr / disableAllHooks: true / 信任未接受 | claude --debug 看退出码与 stderr;检查 settings;接受信任对话框 |
状态栏显示 -- | 字段在首次 API 响应前为 null | 脚本里用 // 0、// "—" 回退 |
| 状态栏不显示权限模式 | schema 不暴露 permission_mode(v2.1.202+ 真实限制) | 显示 effort.level 或 output_style.name 作代理 |
git status 拖慢状态栏 | 脚本频繁运行,大仓库 git 慢 | 用 session_id 做缓存 key,5 秒刷新 |
| Output Style 切换后无变化 | 系统提示词只在会话启动时读 | /clear 或重开会话 |
/config 选不到自定义风格 | 文件位置错 / frontmatter 不闭合 | 确认在 ~/.claude/output-styles/*.md;检查 --- 闭合 |
| 自定义风格后输出残缺 | keep-coding-instructions: false 丢了工程指令 | 写代码场景设 true |
| 主题不匹配 | 终端自身配色与 Claude Code 主题不同步 | 选 auto 让其跟随终端明暗 |
| vim 模式 Enter 提交了消息 | INSERT 模式下 Enter 即提交(设计如此) | 换行用 o/O 或 Ctrl+J |
/vim 命令不存在 | 已移除 | 用 /config → Editor mode 或 editorMode: "vim" |
17.7 配置纪律
三件套的配置文件分散在三处,容易乱。建议:
- 用户级(
~/.claude/):主题themes/、output styleoutput-styles/、statusLine 脚本、settings.json里个人偏好(editorMode、preferredNotifChannel、statusLine)。跨项目通用。 - 项目级(
.claude/):settings.json放团队共享配置(如项目特定的 output style 选择),settings.local.json放个人临时配置(被.gitignore)。 - 版本化:自定义主题 JSON、output style md、statusLine 脚本都建议纳入 dotfiles 仓库,随机器迁移。第 31 章备份迁移会详细讲。
三件套配好一次,后续只是微调。把注意力留给真正重要的事——第 06 章的可执行闭环、第 07 章的 Plan Mode、第 13 章的 code review——这些才是生产力的承重墙。三件套只是让承重墙看着舒服一点。
上一章:Skills 与自定义命令 下一章:调试与排障实战