输出风格(Output Styles) 是 Claude Code 中最强大、同时也最容易被低估的功能之一。它们定义了响应是如何被组织和呈现的,本质上是在塑造用户与模型之间的通信协议。
本章将探讨输出风格如何影响 Claude Code 的沟通方式。你将学习如何创建自定义输出风格,如何在用户级或项目级范围内对它们进行作用域控制,以及如何改变响应的组织结构。我们还会讨论输出风格如何与 system prompt 交互,像 YAML 这样的结构化格式会如何改变推理模式,以及如何把自动化工作流直接嵌入到某个风格定义中。
到本章结束时,你将理解:如何去“工程化”Claude Code 的交互模型,而不只是被动消费它的输出。你将能够设计专门化配置,运行带有不同角色的并行会话,对自己的配置进行版本化管理,并通过自定义状态栏来扩展交互界面。
本章将涵盖以下主题:
- 使用 Claude Code 创建一个自定义输出风格
- 创建一个高级项目级输出风格
- 自定义 Claude Code 中的状态栏
- 高级状态栏:显示最后一条用户 Prompt
- AI 编码的未来:一支由专门化 agent 组成的团队
Claude Code 内置的输出风格会随着时间演化。根据你安装的版本不同,你看到的可用 style 可能会比本章中展示的更多。
使用 Claude Code 创建一个自定义输出风格
当你通过 /output-style 列出可用输出风格时,Claude Code 会显示当前激活的 style,以及所有内置 style。
默认情况下,系统内置以下几种:
- Default
- Explanatory
- Learning
下图展示了 Claude Code CLI 中的输出风格选择界面。当前激活的风格会被高亮显示,而内置风格会列在下面。
图 8.1 —— Claude Code CLI 的输出风格选择界面
正如图中所示,CLI 会展示可用风格列表,并标明当前激活的是哪一个。Explanatory 和 Learning 都是由 Anthropic 团队预置的风格。除了使用这些预定义风格之外,你也完全可以创建自己的自定义输出风格。
创建并审查一个新的输出风格
如果要创建一个用户级输出风格,就在下面这个目录中创建一个 Markdown 文件:
~/.claude/output-styles/
如果要创建一个项目级输出风格,就在下面这个位置创建:
.claude/output-styles/
文件结构与 subagent 的定义方式类似:由 YAML frontmatter 加上后面的 Markdown 内容组成。下面这个例子展示的是一个位于 ~/.claude/output-styles/minimal-bullets.md 的文件:
---
description: Concise bullet-point responses with direct communication
---
# Communication Style
- Use bullet points for all responses
- Be direct and to the point
- No unnecessary language or filler
# Response Format
- Lead with the answer
- Use nested bullets for hierarchy
- Skip preamble and transitions
# Tone
- Professional and concise
- No hedging or qualifications
这个文件包含了如下内容:
- 一段 description,把它定义为一种“简洁的、用 bullet point 表达的、直接沟通”的风格,并强调不要有多余语言
- 用展开小节进一步定义 communication style
- 定义 response format 的规范
- 定义 tone 的规范
当这个 style 被生成后,Claude Code 会把这个定义写入磁盘。下图展示了 minimal-bullets 定义被写入磁盘后的样子。选中 minimal-bullets 之后,它就会成为当前激活的输出风格。当你再次查看可用输出风格列表时,这个 style 会被标记出来。
图 8.2 —— 选中了 minimal-bullets 风格
在这个输出风格下,Claude 生成的响应会以 bullet points 形式呈现,整体结构会更直接、更简洁,并且没有 filler。
图 8.3 —— Claude 使用 minimal-bullets 输出风格进行响应
一旦某个 style 被选中,Claude Code 就会把它的指令应用到之后的所有请求中。
输出风格是如何工作的
选择某个输出风格时,Claude Code 实际上会把自己 system prompt 中的某些部分,替换成 style 专属的自定义指令。Claude Code 会移除默认的软件工程类指令,然后用这个 style 中的指令替换掉对应部分。
无论选用哪种输出风格,Claude Code 的核心能力——包括文件操作、脚本执行、追踪等——都仍然可用。
这个被修改过的 system prompt,会随着每一次 Claude Code 发出的请求一起被发送给 LLM。也就是说,本质上仍然是同一个底层模型,只是它在不同 system prompt 下工作而已。
当你通过 /output-style 相关命令切换 style 时,Claude Code 会更新自己内部的 system prompt 模板,并把新的模板应用到后续所有 LLM 调用中。
项目级输出风格只会在某个特定项目中生效。
下面我们来创建一个新的输出风格,把响应格式定义成 YAML。
为什么选择 YAML
把 YAML 作为一种输出风格,本质上是在把沟通从“显式指令”转变成“隐式语义结构”——也就是让格式本身携带意义。
在 YAML 输出中,格式本身就成了一种丰富的沟通协议:缩进、键名选择、顺序和结构决策,全部都在传达意义。因为 YAML 天生支持层级结构,所以它非常适合映射复杂的编码任务。
依赖关系可以通过父子层级表达。优先级可以通过顺序隐含体现。作用域则可以通过嵌套层级表现。也就是说,与其把问题写成一串线性步骤,不如让嵌套 YAML 结构直接把问题空间的逻辑架构编码出来。为了让这件事更具体一点,可以看下面这个真实任务是如何被结构化的。
下面这个例子,就是在启用 YAML 输出风格时,Claude Code 真实返回的一种输出:
Task: "Fix authentication bug"
Priority: "Urgent high"
Complexity: "Medium"
approach:
investigate:
auth_flow: &flow
- login_endpoint
- token_validation
- session_middleware
debugging:
logs: "./auth.log"
reproduce: "invalid_token_scenario"
fix:
dependencies: [*flow]
files_to_modify:
auth.js:
scope: "token refresh logic"
risk: "low"
middleware.js:
scope: "validation checks"
risk: "urgent"
verify:
tests: ["auth_integration", "token_expiry"]
manual_check: "login flow end-to-end"
metadata:
estimated_time: "2 hours"
rollback_plan: "revert commits"
monitoring: "error_rate_dashboard"
我们来拆一下这个结构:
Task定义了任务上下文approach段落表达了调查路径和调试产物fix段落编码了依赖关系和文件级作用域verify段落定义了验证机制metadata段落则承载了一些运行层面的考虑
图 8.4 —— Claude 以 YAML 格式生成结构化任务计划
YAML 会鼓励模型以“关系”和“依赖”的方式去思考,而不是按线性步骤思考。它的层级结构,会把注意力从“顺序指令”转移到“相互关联的组件”上。
当 Claude Code 以嵌套 YAML 的形式输出一个任务时,它给出的就不再只是一个简单待办清单,而是在结构本身中编码了整个问题空间的逻辑架构。关系、作用域、依赖,都会通过嵌套和键组织被表现出来。
图 8.5 —— 通过可定制输出风格实现的人机协作
输出风格打破了“只能有一种固定交互模型”的限制。它让“通信协议本身”也可以被设计和调整。这正体现了 agentic coding 的本质:我们不只是让 AI 给出内容,而是在主动塑造它如何表达信息,以及它如何在开发工作流中参与协作。
因此,对交互方式的控制,并不只来自模型提供方提升模型能力。作为 LLM 的使用者,开发者也可以通过输出风格来定义并掌控通信协议本身。
将 YAML 创建为一种输出风格
一个项目级输出风格可以被配置成:输出简洁的 YAML 响应,而不带多余冗长说明。当这个风格定义在项目级时,它只对当前项目生效。
要创建这个 style,请在项目目录中创建文件:
.claude/output-styles/yaml-concise.md
文件内容如下:
---
description: Concise YAML-formatted responses for structured communication
---
# Response Format
- All responses must be formatted as valid YAML
- Use hierarchy and nesting to express relationships
- Keep values concise — no full sentences unless necessary
# Structure
- Use top-level keys to represent major sections
- Nest subconcepts under their parent context
- Use lists for enumerations and sequences
- Use key-value pairs for properties and attributes
# Tone
- No prose, no filler, no transitional language
- Let the YAML structure carry the meaning
- Prefer short string values over paragraphs
创建完这个文件后,当你运行 /output-style 时,yaml-concise 就会出现在可选输出风格列表中。与此同时,项目的 .claude 目录下还会生成一个新目录,其中会包含一个 YAML 配置文件,用来表示这个新定义的项目级输出风格。选中它之后,这个 style 就会在当前会话中激活。
当 YAML style 处于激活状态时,你可以发出下面这样的请求:
What are Claude Code output styles? Give me an elaborate answer.
返回结果将不再是段落或 bullet point,而是结构化 YAML。层级、键名和缩进本身就在编码这个解释的结构。
下面是一份具有代表性的示例输出:
definition:
what: "Custom response formats for Claude Code CLI"
purpose:
- "Control communication style and structure"
- "Support global or project-level configuration"
location:
global: "~/.claude/output-styles/"
project: "./.claude/output-styles/"
precedence: "Project overrides global"
file_structure:
format: "Markdown with YAML frontmatter"
frontmatter:
description: "Brief style explanation"
content: "System prompt modifications"
functionality:
controls:
- "Response formatting (bullets, YAML, prose)"
- "Communication tone (formal, casual, technical)"
- "Information density (concise, detailed)"
- "Task approach (speed vs thoroughness)"
- "Workflow behaviors"
这个输出结构反映的是概念分组,而不是线性解释顺序。
它强调了如下几类关系:
- 各个 section 变成了顶层 key
- 子概念被嵌套在父级上下文之下
- 配置作用域和优先级通过结构本身体现出来
- 行为控制项被集中归类在同一个 functional category 下
这种方式和 YAML 在 Kubernetes、Docker Compose 这类配置系统中的用法非常相似:结构本身既易读,又保留了语义层级。
一旦激活项目级的 YAML concise style,Claude Code 的响应就会持续以这种结构化格式返回,从而强化一种偏“架构思维”的表达方式,而不是线性叙述。
图 8.6 —— 在 Claude Code 中应用 yaml-concise 输出风格
在这一节中,你已经学会了如何定义和生成一个自定义输出风格,理解 output-style-setup sub-agent 是如何增强你的 prompt 的,以及这些 style 是如何以用户级或项目级 scope 存储的。这说明:输出风格并不是表层格式化选项,而是一类直接塑造 Claude Code 行为的结构化配置文件。理解如何创建和限定输出风格的 scope,是继续向更复杂用法扩展的基础。下一节,我们会在此基础上进一步构建一个更高级的项目级输出风格,并把更结构化的行为直接嵌进去。
创建一个高级项目级输出风格
这一节会在项目级定义一个新的输出风格,并为它扩展出自动文件生成行为。这里的目标是:让 Claude 生成 HTML 格式响应,并且用一种 ASCII 风格博客页面 的形式来组织;同时,把这种行为直接嵌入到输出风格定义中。
定义一个自定义 HTML 输出风格
我们先来创建并检查这个输出风格的配置文件。这个配置的完整示例在仓库中已经提供。仓库链接的获取方式,请参考前言中的 Download the example code files 一节。
在项目中创建一个新的项目级输出风格文件:
.claude/output-styles/retro-ASCII_blog.md
这个 style 的目标,是让响应以 ASCII 风格博客页面的 HTML 形式输出。
输出风格不仅能控制响应“长什么样”,也可以嵌入 workflow 规则。
这个 style 的内容如下:
---
description: Format responses as retro HTML pages with ASCII art styling like a vintage blog
---
Format all responses as complete HTML pages with retro ASCII art blog styling. Follow these guidelines:
HTML Structure
Always provide complete HTML5 documents with proper DOCTYPE, head, and body tags
Use semantic HTML elements (header, main, section, article, aside, footer)
Include a proper HTML title that reflects the content
ASCII Art Styling
Use ASCII art for headers, dividers, and decorative elements
Create borders using characters like ═, ║, ╔, ╗, ╚, ╝, -, |, +, *, #
Add ASCII art banners for section headers
Use monospace fonts throughout for consistent ASCII alignment
Include decorative ASCII elements like stars, lines, and boxes
CSS Requirements
Embed CSS in <style> tags in the HTML head
Use monospace fonts (Courier New, Monaco, Consolas, monospace)
Set background to dark colors (#1a1a1a, #2d2d2d) with light text
Use retro color schemes (green on black, amber on black, etc.)
Style ASCII art elements with appropriate spacing and alignment
Add subtle glow effects or text shadows for retro terminal feel
Content Structure
Format content like a blog post with clear sections
Use ASCII art dividers between sections
Create ASCII art headers for major topics
Include a decorative ASCII footer
Structure technical information in readable blocks
Add ASCII navigation or menu elements when appropriate
Example Elements to Include:
ASCII art title banners
Decorative borders around code blocks
ASCII bullet points and lists
Retro-style ASCII progress bars or indicators
Terminal-style prompts and outputs
ASCII art logos or emblems
Remember to maintain readability while embracing the retro ASCII aesthetic. The content should feel like browsing a vintage bulletin board system or early web blog.
这个输出风格已经远不只是简单的终端格式化。它不再让 Claude 输出 bullet points 或 YAML,而是直接生成完整 HTML 文档,并用复古 ASCII 艺术博客页的形式来呈现。
这些指令被分成了几个部分:
- HTML structure:要求输出完整 HTML5 文档,并使用语义化标签
- ASCII art styling:规定通过 box drawing 字符和等宽字体来建立视觉风格,并保持对齐
- CSS requirements:定义复古终端式审美,包括深色背景、绿字黑底或琥珀字黑底配色,以及轻微 glow 效果
- Content structure:要求内容组织成博客文章形式,带 ASCII 分割线、banner 和装饰性 footer
所有行为都被定义在一个单独 Markdown 文件中,不需要额外代码,也不需要 plugin。只要这个 style 被选中,然后你发出一个 prompt,Claude Code 就会生成对应 HTML 页面,把它写入磁盘,并在浏览器中打开。
使用这个 HTML 输出风格
当 retro-ASCII_blog.md 被选中为当前活动输出风格后,可以发出如下 Prompt:
What are output styles? Provide an elaborate answer.
Show me which output styles I have right now.
此时返回结果会是 HTML。内容本身是合法的 HTML markup,并会直接打印在终端里。由于它是 markup,而不是针对终端可读性优化过的文本,所以在终端上下文里其实并不好读。
这个阶段里,HTML 还没有被写入一个可供浏览器打开的文件。输出只是存在于终端中那段生成出的 markup。
为了让这个结果真正可用,需要再让 Claude Code 把这段 HTML dump 到一个文件中。于是会生成一个名为 output-styles-guide.html 的文件。
用浏览器打开之后,它就会渲染成一个博客式页面,用来解释输出风格是什么。
图 8.7 —— 生成出来的 HTML 页面,用于说明 Claude Code 输出风格
渲染后的页面会展示当前配置好的输出风格,并证明:结构和格式其实都可以完全自定义。这里的 HTML 并不是为了追求视觉精致,而是为了说明:Claude 能生成什么、如何生成,几乎是完全自由的。
这种输出风格也并不只局限于静态页面。它还可以被扩展到一个更大的应用中,比如写入一个 Next.js 项目,让 Claude 的每次响应都在这个应用里生成一个新页面。输出的结构与行为,完全由配置定义,而不是被某种预设模板限制死。
自动化文件生成
现在我们更进一步:把 workflow 逻辑直接嵌进输出风格定义中。
如果每次都还要手工再 prompt 一次,让 Claude 把 HTML 写进文件,那就太重复了。所以,不如把这个行为直接写进 style 定义里。
于是,retro-ASCII_blog.md 会被更新,新增如下这段 workflow 指令:
Workflow
Save the HTML file after writing it, it should have a descriptive name ending with .html
OPEN the generated file in the deault web browser.
输出风格现在不仅可以控制格式,还能编码工作流行为,让 Claude Code 自动保存生成出来的 HTML 文件,并自动在浏览器里打开。
图 8.8 —— 输出风格中的 Workflow 指令
这里没有引入什么复杂逻辑,Prompt 本身依然很简洁。但 Claude Code 已经会根据这些风格定义中的规则,自动完成文件生成相关操作。
保存更新后的输出风格之后,你只需要发出一个很简单的请求,例如:
What are output styles?
这时,Claude 就会自动创建一个名为 output-styles-quick-guide.html 的文件。系统会请求你确认是否要在默认浏览器中打开它,一旦批准,渲染后的 HTML 页面就会立刻显示出来。
换句话说,这套 workflow 已经真正被嵌进了输出风格本身。此后,在这个 style 下产生的每一条响应,都会自动写成一个浏览器可直接打开的 HTML 文件。
同时使用多个输出风格
单独运行一个输出风格,已经足以说明:格式是可以为某种明确用途而被定制的。而更进一步的做法,是同时运行多个 Claude Code 实例,让每个实例都配置成不同的输出风格。
接下来的部分,会展示多个会话如何并行运行,以及这种方式如何在同一个仓库中支持“按任务定制输出格式”。
启动一个新的 Claude Code 实例
在仓库里再打开一个新的终端实例,并启动 Claude Code。这样会创建一个全新的会话,此时还没有选择输出风格。
图 8.9 —— 启动一个新的 Claude Code 会话
然后,从可用风格中选择一个 output style。在这个会话中,我们选择 minimal bullet 风格。
这样,这个会话接下来就会一直用 minimal bullet 格式生成响应。
再开第二个实例,并选择不同输出风格
在同一个仓库中,再打开第二个终端实例,然后再次启动 Claude Code。
这一次,选择另一个不同的输出风格——YAML concise。
现在就形成了两个并行运行的 Claude Code 实例:
- 一个使用 minimal bullets
- 一个使用 YAML concise output
而且每个实例都会维护各自独立的活动输出风格。
图 8.10 —— 选择 YAML-concise 输出风格
多个输出风格并行工作的实际表现
当两个实例并排运行时,每个终端中的响应都会体现出各自选中的风格。也就是说,格式会根据活动 output style 明显不同。
这就建立了一种 workflow:多个 Claude Code 会话并行运行,每个都为某种特定输出格式进行了优化。
图 8.11 —— 两个 Claude Code 会话分别使用不同输出风格
专门化输出风格工作流
当你把这两个实例并排摆出来之后,就会很清楚地看到:每个会话都保持着自己独特的格式行为。你不再是面对一个单体化的、通用型 AI 助手,而是开始拥有多个“为特定任务而配置好”的 Claude Code 助手。
比如:
- 一个偏 review 的会话,可以突出代码差异、安全漏洞和架构问题
- 一个偏 explain 的会话,可以优化成适合教学说明或文档生成的风格
- 一个偏 debug 的会话,则可以专注于错误分析和问题定位,并让输出格式更贴近调试需求
也就是说,每种输出风格都在把 AI 的“认知重心”往特定任务方向上拉。
不过,当你在多个终端窗口之间切来切去时,会有一个现实问题:你并不能一眼看出来当前这个会话到底激活的是哪个输出风格。Claude Code 的界面并不会很显眼地展示这件事。
这个限制在多会话并行时就会变得明显。解决办法,就是用自定义状态栏(custom status line) ,让当前配置一眼可见。
当这些配置都验证通过、并且工作符合预期后,我们再把它们提交到版本控制中。
到这里,你已经把最基础的输出风格机制扩展到了更高级的层面:你定义了一个项目级配置,并把更复杂的格式化逻辑与行为逻辑一起嵌了进去。你也看到了,输出风格已经不只是“响应长什么样”,而是会进一步影响“响应怎么被操作化执行”。有了这个基础,接下来我们就从输出格式控制,进入到运行时界面定制,也就是通过修改 Claude Code 的状态栏来扩展交互体验。
自定义 Claude Code 中的状态栏
状态栏允许你运行任意脚本。Claude Code 会把它当前会话的数据(如模型、上下文占用、成本、Git 信息等)以 JSON 形式通过 stdin 传入你的脚本,然后你可以在脚本里输出任何你想长期显示在终端底部的信息。
配置方式是在 ~/.claude/settings.json 中,把 statusLine 键指向你的脚本;或者你也可以直接使用 /statusline 这个斜杠命令,用自然语言描述你想要的状态栏,让 Claude 帮你自动生成。
这一节我们会讨论:如何通过一个专门命令,以及一个 Python 实现,来配置并实现 Claude Code 中的自定义状态栏。
定义一个自定义状态栏命令
我们先定义一个新的斜杠命令 /statusline。这个命令的 description 会说明:状态栏应该显示当前正在使用的 output style。定义这个命令时使用的 Prompt 如下:
/statusline I want you to create a statusline that displays the current used output-style.
You should implement it in python and run it through uv
这里明确提出了两个实现要求:
- 状态栏必须用 Python 实现
- 它必须通过 uv 包管理器来运行
Claude Code 的状态栏支持执行 shell 命令、shell 脚本、Python 文件和 Node.js 文件。也就是说,它本质上可以运行任何可执行逻辑。这里之所以选择 Python,只是因为更熟悉、更顺手。
初始化状态栏配置
当 /statusline 命令被执行后,Claude Code 会先初始化,并 spawn 出一个 sub-agent,专门负责协助状态栏的创建。
这个 sub-agent 做的第一件事,就是去用户主目录中寻找已有的状态栏配置:
~/.claude/settings.json
它会检查这个文件里是否已经有 statusline 条目。如果没有,就会自动更新这个配置文件。
图 8.12 —— 实现一个自定义 statusline 脚本
更新配置
settings.json 文件中本来就定义了默认模型,在这个例子里,它被设成了 sonnet。接下来,这个配置会被扩展,加上一个新的 statusline 项。
一个具有代表性的配置如下:
{
"model": "sonnet",
"statusline": {
"type": "command",
"command": "uv run ~/.claude/statusline.py"
}
}
这里,type 被设置为 command,而 command 指定的是:通过 uv 去运行 statusline.py 这个脚本。
默认情况下,这个脚本会被创建在用户主目录中的:
~/.claude/statusline.py
当然,只要配置里写对执行路径,这个脚本也完全可以存放在其他任意位置。
实现状态栏逻辑
statusline.py 文件中包含的,就是决定状态栏显示什么的逻辑。
Claude Code 会通过标准输入(stdin)把运行时信息传给这个脚本。脚本读取这些输入后,把它们解析成 JSON。然后用 json.load 把数据装进一个字典中,这样我们就能访问 Claude Code 提供的全部运行时信息。
图 8.13 —— 状态栏脚本通过 Claude Code 读取 JSON 输入
一个最简实现如下:
import json
import sys
input_data = json.load(sys.stdin)
style = input_data.get("output_style", "default")
print(style)
可用键里有一个叫 output_style。脚本从中提取出当前激活输出风格的名称。如果当前没有定义输出风格,那么脚本就默认显示 "default"。
脚本把结果写到标准输出(stdout)中。Claude Code 会读取这个 stdout 内容,并把它显示到状态栏里。
当输出风格切换时,Claude Code 传入 stdin 的值也会相应变化,因此状态栏会同步反映出新的 style。
ANSI 颜色支持与格式化
状态栏本身支持 ANSI 颜色格式。如果你修改 Python 脚本,就可以控制输出在终端中的视觉样式,比如颜色、加粗等。
例如,你可以把 print 改成这样:
print(f"\033[1;32m{style}\033[0m")
这里的数字序列就是 ANSI escape code,用于控制终端格式。在这个例子里,状态栏会以绿色加粗文字显示。
当活动输出风格发生变化时,状态栏也会同步更新。因为所有逻辑都由脚本驱动,所以它可以动态反映当前配置,以及你对它施加的各种格式化规则。
图 8.14 —— 状态栏显示当前激活的输出风格
扩展状态栏功能
既然状态栏的显示逻辑本质上是脚本驱动的,那它理论上就可以显示任何当前运行环境中可获得的信息。
例如,它完全可以接外部系统、股票价格、新闻数据流,或者任何动态抓取到的内容。
更复杂的输出风格相关功能,也可以通过继续扩展这个脚本逻辑来实现。
在这一节中,你已经实现了一个基于 Python 脚本的自定义状态栏,并把它真正集成进了 Claude Code 的配置中。你学会了运行时信息是如何通过标准输入传递进来的,也学会了如何提取其中的结构化数据(例如当前激活的输出风格),以及如何把动态值显示在界面上。这说明 Claude Code 的可扩展性并不止于输出格式,它甚至允许你通过可执行逻辑来塑造整个开发环境本身。
在这个基础上,下一节会继续扩展状态栏能力:我们将读取 transcript 数据,并从中提取最后一条用户 Prompt。
高级状态栏:显示最后一条用户 Prompt
在用户主目录下,.claude 目录中包含一个 projects 子目录。projects 下的每一个子目录,都对应一个项目,并保存这个项目的会话历史和 session 数据。目录名本身映射的是项目路径,其中的路径分隔符(例如 /)会被替换成 -。
图 8.15 —— Claude projects 目录,用于存储 session 数据
在每个项目目录内部,会有若干 JSONL 文件用来存储会话日志。每个文件都通过一个 UUID 来标识。这些 JSONL 文件中,保存的是某个会话里完整的消息序列。
如果你打开其中一个 JSONL 文件,会发现其中每一行都是一个 JSON 对象,分别对应一条消息。当用户发出一条新的消息时,一个新的 JSON 对象就会被追加到这个文件中。比如,如果用户发送了 "hello",那么文件中就会新增一个条目,类似这样:
"role": "user""content": "hello"
随后才会追加 assistant 的响应。
图 8.16 —— 以 JSONL transcript 存储用户 Prompt
Claude 会把所有用户 Prompt 都存到这些 JSONL 文件中。我们的目标,是进一步扩展状态栏,让它能够显示当前 session 中用户最后发送的一条 Prompt。这条 Prompt 必须从 transcript 文件中取,而这个文件路径会通过状态栏脚本输入中的 transcript_path 键提供给我们。
这里要注意:只显示真正的用户 Prompt。像状态栏相关命令调用、assistant 响应等内容,都必须排除掉。
所有实现仍然都保留在原有的 statusline.py 文件里。
定义状态栏需求
这里会再定义一条 /statusline 指令,把状态栏扩展出一个新字段:显示当前 session 中最后一条用户 Prompt。
当 Claude Code 执行状态栏命令时,它会通过标准输入把结构化的运行时数据传给状态栏脚本。这个 JSON payload 里就包含像 transcript_path 这样的字段,它指向当前会话对应的 JSONL transcript 文件。
脚本接下来要做的事情,就是从输入中读取 transcript_path,打开对应 JSONL 文件,然后找到最新的一条用户消息。那条消息就会被显示在状态栏中。这里依然只看真实用户 Prompt,不看 assistant 响应,也不看命令类调用。
下面这条 /statusline 指令,就是为了把状态栏扩展成可以显示当前 session 最近一条用户 Prompt:
/statusline I want you to display also the last prompt from the user in the current session.
You should get the prompt from the file example in the transcript_path. /path/to/transcript.jsonl
Remember the user prompt will be a message with role="user".
Remember no commands at all responses, just user prompts in this example.
在演示的例子里,transcript 文件里最近一条用户 Prompt 是 "hello",因此它最终会显示在状态栏中。这里再次强调:应该只显示真正的用户 Prompt;像 /statusline 命令调用本身,以及 assistant 响应这类同样会被写进日志的内容,都必须被排除。也正因为如此,脚本需要明确做过滤,只保留合法用户 Prompt。
此外,这条指令还明确要求:所有逻辑都必须写进已有的 statusline.py 文件里,不能再额外创建别的脚本或 shell 工具。这样一来,这项功能就能完整地被收敛在状态栏实现内部。
访问 Transcript Path
在 statusline.py 里,结构化输入已经被加载成一个字典。脚本会从中读取 transcript_path 键——这个键我们知道是存在的。然后把这个路径传给一个专门负责获取最后用户 Prompt 的函数。
于是,状态栏脚本会先拿到 transcript 文件路径,再从对应 session log 中提取最后一条用户 Prompt。
图 8.17 —— 读取 transcript path,从而提取最后一条用户 Prompt
这个函数返回 prompt 之后,脚本再把它打印到状态栏输出中。
实现“获取最后一条用户 Prompt”的逻辑
这个函数的工作流程如下:
- 先确认 transcript 文件路径是否存在
- 打开并读取该路径下的 JSONL 文件
- 逐行遍历整个文件
- 把每一行解析成 JSON 对象
- 检查其中的
message字段 - 查看
message里的role字段 - 如果
role是user,就提取content字段
下面这段 Python 函数,会读取 transcript 文件,解析 JSONL 条目,并取出最近一条有效的用户 Prompt:
import json
import sys
import os
def get_last_user_prompt(transcript_path):
"""
Extract the last user prompt from the transcript file.
"""
try:
if not os.path.exists(transcript_path):
return "No transcript found"
with open(transcript_path, "r") as f:
content = f.read().strip()
if not content:
return "Empty transcript"
# Split by lines and process each JSON object
lines = content.split("\n")
for line in reversed(lines):
try:
entry = json.loads(line)
# Entry has 'message' and not a command
if entry.get("type") == "message" and entry.get("role") == "user":
message_content = entry.get("message", {}).get("content", "")
# Skip command messages starting with /
if message_content.startswith("/"):
continue
return message_content
except json.JSONDecodeError:
continue
return "No user prompt found"
except Exception as e:
return f"Error reading transcript: {e}"
命令形式的占位消息,以及 assistant 响应,都会被跳过。只有真正有效的用户 Prompt 会被保留下来。遍历过程中一旦找到最近的一条有效用户 Prompt,就会把它作为结果返回。
到这里,statusline.py 文件就已经承担了三件明确的事情:
- 从标准输入读取运行时结构化信息
- 从中提取
transcript_path - 打开对应 JSONL transcript 文件,扫描并找出最近一条合法用户 Prompt,再把它输出到标准输出中
测试并完成这项实现
在完成“提取并显示最后一条用户 Prompt”的逻辑之后,下一步就是确认它是否真的按预期工作。也就是说,我们需要验证:
- 新 transcript 条目是否确实会被正确追加
- 只有有效用户 Prompt 会被提取
- 状态栏会不会在每轮交互之后都稳定更新
验证实现
当你发送一条新消息时,JSONL transcript 文件里就会追加一条新记录。等 assistant 的响应也被记录完之后,状态栏就会更新,显示刚刚提交的那条 Prompt。
反复进行这个过程,可以确认:
- 每条新消息都会追加一个新的 JSONL 条目
- 状态栏中显示的 prompt 会同步更新
- 脚本始终能正确提取最近一条有效用户 Prompt
你还可以再切换一次 output style(例如改成 YAML concise),确认这项新功能依然正常工作。状态栏会继续正确显示最后一条 Prompt,不受影响。
图 8.18 —— 状态栏展示 transcript 中最新的用户 Prompt
更新输出标签
前面几节中,我们已经分别看过:如何通过 output styles 控制 Claude Code 的表达方式,以及如何通过 status line 去观察和监控当前运行时状态。这两种机制结合在一起,其实已经为我们塑造 Claude Code 的运行方式和沟通方式,提供了一套完整基础。
在有了这些能力之后,我们就可以开始往前看:当这些机制继续被叠加和扩展时,agentic coding 的未来可能长什么样。届时,我们不再依赖单个 assistant session,而是让多个专门化 agent 协作,每个 agent 都拥有自己的角色、上下文,以及输出行为。
AI 编码的未来:一支由专门化 Agent 组成的团队
随着 agentic development workflow 的不断演化,单一一个 assistant session 往往已经不够应对复杂任务。更自然的方向,是让多个专门化 agent 协作,每个 agent 都负责某个明确角色或领域。结合前面介绍过的配置技巧——例如 output style 和 runtime status line——我们就可以开始把这些 agent 组织成一个协同系统,而不是只用一个通用型助手。
Agentic Coding 与多个实例
Agentic coding 的一种具体体现,就是同时运行多个 Claude Code 实例,而每个实例都拥有自己的:
- output style
- context
- role
这样一来,你不再依赖一个通用型 session,而是把职责分配给多个专门化实例。
这其实很像一个小型创业团队的结构。
图 8.19 —— 以专门化创业团队为比喻的 agent 角色图
在一个小型创业团队里,不同类型的工作会被自然路由到不同专家手里:
- UI 改动交给前端工程师 Vinay
- 后端改动交给 Rajesh
- 部署问题交给 DevOps 工程师 Alex
每个人都有自己的明确职责和技能组合,而且他们通常也会以符合自己工作领域的方式表达与沟通。这里提到的所有名字都只是为了示意工作流角色的虚构名字,并不指代任何真实人物。
例如:
- 一个偏 DevOps 的实例,可以使用 YAML 风格输出
- 一个偏后端的实例,可以采用 OpenAPI specification 风格
- 一个偏文档的实例,可以采用结构化、适合学习的输出风格
每一种 output style 都是在 system 层配置的,并且会直接影响响应的生成方式。除此之外,一个实例还可以绑定自己特定的 commands、agents 以及上下文约束。
这些实例还可以被赋予与职责相匹配的名字,就像团队成员一样。
命名与基于角色的上下文
每一个 Claude Code 实例都可以代表一个具名角色,例如:
frontend-engineerbackend-engineerdevopssecurity-review
这个名字会同时反映:
- 它的 output style
- 它的上下文
- 它负责的任务类型
于是,在不同终端窗口之间切换,本质上就相当于在不同“团队成员”之间切换。安全相关任务就交给 security-focused 实例处理;UI 任务就交给 frontend-focused 实例处理。
这种结构带来了受控的上下文边界,以及清晰的职责分工。多个专门化 Claude Code 实例,就像一组协调好的 agent,一起参与开发 workflow。
在本章最后这一节中,你已经看到:多个 Claude Code 实例如何并行运行,并且每个都被配置成不同输出风格和不同上下文焦点。你也看到了目录级配置是如何影响它们的行为的,以及这种专门化 session 是如何映射到真实开发团队中的角色协作模型上的。
这也正是本章的核心思想:Claude Code 并不是一个固定不变的单一界面,而是一个可以被塑造成面向特定任务 agent 的可配置系统。
总结
在本章中,你学习了 Claude Code 的输出风格是如何工作的,以及如何在用户级或项目级范围内创建、审查并应用这些风格。你也进一步理解了:当选择某种 output style 时,Claude Code 的 system prompt 会如何变化,以及像 YAML 和 HTML 这样的结构化格式,又是怎样改变响应的生成方式与消费方式的。
本章还把这种配置能力继续扩展到了 workflow 控制:我们把文件生成行为嵌进了输出风格定义中;同时,也通过一个 Python 脚本实现了自定义 status line,让它读取运行时输入以及 transcript 历史。
这些内容之所以重要,是因为它们让你能够直接控制 Claude Code 如何沟通,而不仅仅是控制它生成什么。你不必再把模型输出看作固定 prose,而是可以把响应结构、语气以及 workflow 行为,都纳入开发环境的一部分进行定义。这样一来,你就可以根据不同任务来定制 Claude Code 会话,运行多个专门化会话并行协作,并把这些配置一起纳入可重复、可版本化的工作流中。
在下一章中,我们将进入 agent skills,讨论它们如何作为一种机制,进一步扩展 AI agent 的能力。