Skip to content

第 17 章 Status Line / Output Style / 主题

终端配置三件套——主题、Status Line、Output Style——是 Claude Code 里性价比最高的一组个性化:十几分钟配置,换来每天几十次的视觉舒适与信息直达。这一章讲清三件事各自管什么、怎么配、配错了怎么排。

17.1 结论:三件套各管一件事,低成本高收益

配置管什么配置位置改变的是什么
主题(theme)颜色看着舒不舒服/theme/configClaude Code 自身渲染的颜色 token
Status Line底部状态栏显示什么信息settings.jsonstatusLine一段 shell 脚本的 stdout
Output StyleClaude 回复的角色/语气/格式/configoutputStyle 字段系统提示词(system prompt)

三者互不冲突,可独立配置。主题管「眼睛」,Status Line 管「信息一目了然」,Output Style 管「输出形态」。三件套之外,/config 里还有 editorMode、通知通道、tmux 配置等终端层选项,一并归到本章末尾。

一个判断原则:主题和 Status Line 是「看」的配置,改了立刻生效;Output Style 是「说」的配置,改了要 /clear 或重开会话才生效——因为它修改的是系统提示词,而系统提示词只在会话启动时读一次。这个差异是新手最常踩的坑。

17.2 主题:/themeauto 自动检测

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-ansidark
overrides要覆盖的颜色 token 映射

颜色值接受 #rrggbb#rgbrgb(r,g,b)ansi256(n)ansi:<name>(如 ansi:redBright)。未知 token 与非法颜色值会被忽略,笔误不会搞坏渲染。

示例(Dracula 风格,基于 dark 预设覆盖三个 token):

json
{
  "name": "Dracula",
  "base": "dark",
  "overrides": {
    "claude": "#bd93f9",
    "error": "#ff5555",
    "success": "#50fa7b"
  }
}

claude token 控制品牌强调色(spinner、助手标签),error/success 控制状态色。Claude Code 会监听 ~/.claude/themes/ 目录变化,编辑器里改了 JSON,运行中的会话即时生效,无需重启。

命令 + 验证:

bash
# 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 就是状态栏显示的内容。

数据流:

text
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.modevim 模式(NORMAL/INSERT/VISUAL 等),仅启用 vim 时存在
session_id会话唯一标识(可做缓存 key)
rate_limits.five_hour.used_percentage5 小时滚动窗口用量百分比(仅 Pro/Max 订阅、首次 API 响应后)

重要缺失字段:permission_mode 不在 stdin JSON 里(2026-07-08 核对 v2.1.202+)。状态栏会在权限模式切换时刷新,但脚本读不到当前权限模式值。最接近的代理字段是 effort.leveloutput_style.name。本章实战脚本因此显示 effort 档而非权限模式——这是官方 schema 的真实限制,不是脚本写错。

17.3.3 实战:一个 [模型|git分支|成本|effort档] 状态栏

第一步:写脚本 ~/.claude/statusline.sh:

bash
#!/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):

json
{
  "statusLine": {
    "type": "command",
    "command": "~/.claude/statusline.sh",
    "padding": 2
  }
}

第三步:验证(三个层次):

bash
# 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 会话,发一条消息触发刷新,底部应出现状态栏

第四步:排错。看不到状态栏时按顺序排查:

  1. disableAllHooks: true 会一并禁用 statusLine——检查 settings.json 里没有这个字段或为 false
  2. 工作区信任未接受 → 状态栏显示 statusline skipped · restart to fix,重启并接受信任对话框。
  3. 脚本输出到 stderr 而非 stdout → 状态栏空白。脚本里所有输出走 stdout。
  4. 脚本非零退出或无输出 → 状态栏空白。用 claude --debug 看首次执行的退出码与 stderr。
  5. jq 未安装 → brew install jq(macOS)或 apt install jq(Debian)。
  6. 路径含反斜杠(Windows Git Bash)→ 改用正斜杠,如 ~/.claude/statusline.sh

捷径:/statusline 命令接受自然语言,直接生成脚本并写入 settings。例如 /statusline 显示模型名和上下文百分比,带进度条。适合不想手写脚本时快速起步,但生成结果仍建议按上面三步验证一遍。

17.3.4 进阶:缓存慢操作

git status 在大仓库里可能很慢,而状态栏脚本运行频繁。用 session_id 做缓存 key(进程 ID $$ 每次变,不能做 key),5 秒刷新一次:

bash
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 而非每次调 git

stat -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:

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仅插件风格:插件启用时自动应用,覆盖用户 outputStylefalse

keep-coding-instructions 是关键选择:

  • 改 Claude 怎么说话但还在写代码(如「永远用图回答」)→ 设 true,保留内置工程指令
  • Claude 根本不做软件工程(如写作助手、数据分析师)→ 设 false,丢掉内置工程指令,你的指令全权接管

17.4.3 实战:写一个「简短工程向」output style

目标:只给结论与 diff,不废话,适合熟练开发者日常编码。

第一步:写文件 ~/.claude/output-styles/concise-eng.md:

markdown
---
name: concise-eng
description: 简短工程向——结论先行,只给 diff 与命令,不寒暄
keep-coding-instructions: true
---

# Concise Engineering Style

你是简短工程向助手。遵守:

## 输出规则
1. **结论先行**:第一句直接给可执行答案,不铺垫。
2. **代码用 diff,命令用代码块**:不解释显而易见的内容。
3. **禁止寒暄**:不要「好的」「当然可以」「我来帮你」;不复述用户问题。
4. **风险与前提**:仅在有非显而易见风险或前提时补充,限一两行。
5. **验证**:给出运行的验证命令及结果摘要,不描述过程。

## 仍然详细的情况
- 用户明确要求「解释」「为什么」时。
- 涉及破坏性操作或安全风险时。
- 首次引入新概念时,可附一句话定义。

## 默认长度
- 简单任务:3-8 行。
- 中等任务:不超过 20 行。
- 复杂任务:结论 + diff + 验证,不写叙述段落。

第二步:应用。两种方式:

text
# 方式一:菜单(官方文档推荐路径)
/config
# 选 Output style → concise-eng

# 方式二:直接命令(本书第 06 章命令表列为内置,v2.1.202+)
/output-style concise-eng

写入位置:项目级 .claude/settings.local.jsonoutputStyle 字段(值 "concise-eng")。

第三步:验证(注意必须重开会话或 /clear):

text
# 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 modevimnormal,或 settings.json:

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 章命令真实性表),正确路径是 /configeditorMode 字段。

17.5.2 通知:preferredNotifChannel 与 Notification hook

Claude 完成任务或等权限提示时触发通知事件。默认只在 Ghostty/Kitty/iTerm2 发桌面通知;其他终端设:

json
{ "preferredNotifChannel": "terminal_bell" }

终端响铃。要自定义声音/命令,配 Notification hook(第 14 章):

json
{
  "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 加:

text
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.leveloutput_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/OCtrl+J
/vim 命令不存在已移除/config → Editor modeeditorMode: "vim"

17.7 配置纪律

三件套的配置文件分散在三处,容易乱。建议:

  • 用户级(~/.claude/):主题 themes/、output style output-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 与自定义命令 下一章:调试与排障实战