38 · 插件参考手册:把自己那套配置,打成一个能发出去的包
给一个插件跑一下 claude plugin details,输出里常有一行数字值得留意:这个插件每个会话常驻占 ~180 token,里头两个 skill 触发时各自再吃掉 ~2400 和 ~1800 token。
就这么个看着人畜无害的小插件,光「挂在那儿什么都没干」就先占了一截工作台。这时候就能意识到:插件不是个黑盒——它由几类明确的组件拼成,每一类占多少、放哪儿、怎么触发,全是有据可查的。你把这套结构吃透,才谈得上「自己造一个、还造得干净」。
第 24 篇我们已经把「用别人的插件」走通了:加市场、装插件、/reload-plugins 生效、装前看信任。这一篇不重复那些,专啃更硬的一块——插件的内部构造和开发发布。说白了,第 24 篇是「会开车」,这一篇是「会拆发动机、还能自己攒一台」。
这一篇偏「参考手册」,信息密度会比前面高。你不用一次记全,先跟着把一个能跑的插件造出来、发出去,剩下的字段表当字典随用随查。
看完这一篇,你会拿到:
- 插件的标准目录长相,以及那条「
.claude-plugin/里只放plugin.json」铁律背后的完整结构 plugin.json清单的字段全景:必填的、元数据、组件路径、用户配置、依赖,一张表查到底- 插件能打包的全部组件(skill / command / agent / hook / MCP / LSP / monitor)各自放哪、有什么限制
${CLAUDE_PLUGIN_ROOT}这几个路径变量为什么必须用、不用会怎样- 从零造一个插件、本地测、建市场、发给团队的完整链路,全程给命令和预期输出
- 版本管理和依赖这两个发布时绕不开的坑,怎么填
01 先把插件的「骨架」摆正:标准目录长相
第 24 篇你已经见过插件最简的样子——一个 plugin.json 加几个组件文件夹。但要自己造一个像样的插件,得先把完整骨架看清楚,不然加到一半就乱。
先给结论:一个插件就是一个文件夹,里头一个「清单文件」定身份,其余按组件类型分门别类摆在根目录下。
类比:一套乐高积木。 一盒乐高里有两样东西——一本拼装说明书,告诉你这套叫什么、有哪些零件;几个分格的零件盒,按类型把积木块装好(轮子一格、窗户一格)。插件就是这么个结构:plugin.json 是那本说明书,skills/、agents/、hooks/ 这些文件夹是分格零件盒。说明书有它专属的位置,零件盒全摊在外面——这就是下面那条铁律的由来。
官方给的完整插件目录长这样(我删掉了不常用的,留核心):
my-plugin/
├── .claude-plugin/ # 元数据目录
│ └── plugin.json # 清单(说明书)——只有它放这儿
├── skills/ # Skills,每个一个 <名字>/SKILL.md
│ └── code-reviewer/
│ └── SKILL.md
├── commands/ # Skills 的扁平 .md 写法(老形式)
│ └── status.md
├── agents/ # Subagent 定义
│ └── security-reviewer.md
├── hooks/ # Hook 配置
│ └── hooks.json
├── .mcp.json # MCP server 定义
├── .lsp.json # LSP server 配置
├── bin/ # 加进 PATH 的可执行文件
├── scripts/ # Hook 和工具脚本
└── settings.json # 插件的默认设置
这里有条官方用警告框圈起来、新手必踩的铁律,我替你钉死:
.claude-plugin/目录包含plugin.json文件。所有其他目录(commands/、agents/、skills/、output-styles/、themes/、monitors/、hooks/)必须在 plugin 根目录,而不是在.claude-plugin/内。
说白了:.claude-plugin/ 这个文件夹里只准躺着 plugin.json 一个东西,skills/、agents/、hooks/ 全部摆在它的外面、跟它平级。这个坑第 24 篇就提过——第一次打包很容易手贱把 skills/ 塞进 .claude-plugin/,结果插件能加载、skill 死活不出现,排查半天才发现是位置摆错。记住乐高那个画面:说明书归说明书的盒,零件盒全摆外头。
还有个容易被忽略的点,官方写得很明确:插件根目录里的 CLAUDE.md 不会被当成项目上下文加载。插件想给 Claude 喂指令,得通过 skill、agent、hook 这些组件,不能靠在插件里塞一个 CLAUDE.md。这跟第 18 篇讲的项目级 CLAUDE.md 是两码事,别搞混。
💡 一句话总结:插件 = 一本说明书(
.claude-plugin/plugin.json)+ 根目录下分格的零件盒(各组件文件夹);铁律就一条——.claude-plugin/里只放plugin.json,别的文件夹全摆根目录。
02 plugin.json:这份「清单」每个字段管什么
骨架摆正了,来拆那本说明书——plugin.json。它声明插件的身份和配置,是整个插件的核心。
先记一个反直觉但很省心的事实:清单是可选的。 官方原话——如果你省略 plugin.json,Claude Code 会自动去默认位置(skills/、agents/ 这些)找组件,连插件名都从文件夹名推出来。只有当你需要写元数据、或自定义组件路径时,才需要这份清单。 但凡你想正经发布,肯定要写,所以咱们按写的来讲。
类比:报关单。 一批货物出关,得附一份报关单——里头写清这批货叫什么名字、谁发的、版本批次、装了哪些东西。海关(Claude Code)照着这份单子核对、登记、上架。plugin.json 就是插件的报关单:名字、作者、版本、装了哪些组件,全在这一张纸上说清。
唯一的必填字段
如果你写了清单,只有一个字段是必填的:
| 字段 | 类型 | 说明 |
|---|---|---|
name | string | 唯一标识符,kebab-case(小写加连字符)、不带空格 |
name 为什么这么关键?因为它就是组件的命名空间(namespace)前缀。一个叫 plugin-dev 的插件里有个 agent 叫 agent-creator,在界面里会显示成 plugin-dev:agent-creator;skill 调用就是 /plugin-dev:xxx。命名空间是插件防撞名的根本机制——你装十个插件,各家的 skill 都带自家前缀,不会打架。
元数据字段(描述插件「是什么」)
这些不影响功能,但发布时该填,让用户看得明白:
| 字段 | 干什么 |
|---|---|
displayName | 界面里显示的人类可读名,能带空格大小写;省了就回退用 name |
version | 语义版本号(semantic versioning)。设了它,用户只在你提版本号时才收到更新(这是个大坑,第 08 节细说) |
description | 一句话说清插件干嘛,浏览/安装时显示 |
author | 作者信息(name / email / url) |
homepage / repository / license | 文档地址 / 源码地址 / 许可证 |
keywords | 发现标签,帮人搜到你 |
组件路径字段(指明组件「在哪」)
默认情况下组件就放在 skills/、agents/ 这些标准位置,你完全可以不写这些字段。只有当你想把组件放到非标准路径时才用:
| 字段 | 指向什么 |
|---|---|
skills | 额外的 skill 目录(追加到默认 skills/) |
commands / agents / outputStyles | 自定义路径(替换默认目录) |
hooks / mcpServers / lspServers | 配置文件路径,或直接内联写在这儿 |
dependencies | 这个插件依赖的其他插件(第 08 节讲) |
这里藏着一个特别容易栽的细节,官方专门列了「路径行为规则」:有的字段是「替换默认」,有的是「追加到默认」。
- 替换默认:
commands、agents、outputStyles。一旦你写了commands,默认的commands/目录就不再被扫描了。想保留默认还加别的,得显式列上:"commands": ["./commands/", "./extras/"]。 - 追加到默认:
skills。默认skills/永远会被扫描,你在skills字段里列的目录是跟它一起加载的。
这个坑很容易踩:给一个插件加了 "agents": ["./extra-agents/reviewer.md"],想着「再加一个 agent」,结果原来 agents/ 目录里那俩 agent 全不见了——因为 agents 是替换不是追加。改成把三个都列进数组才好。记不住就查这张规则,别凭感觉。
一份带元数据的完整清单大概长这样:
{
"name": "deployment-tools",
"displayName": "Deployment Tools",
"version": "1.2.0",
"description": "Deployment automation tools",
"author": { "name": "Dev Team", "email": "dev@company.com" },
"license": "MIT",
"keywords": ["deployment", "ci-cd"]
}
💡 一句话总结:
plugin.json是插件的报关单,唯一必填的是name(它定命名空间);组件路径字段里要分清「替换默认」(commands/agents)和「追加默认」(skills),搞反了组件会凭空消失。
03 插件能打包哪些组件:七类零件认全
这是本篇最该记牢的一节——插件这个盒子,到底能装哪七类零件。第 24 篇粗讲过几类,这里把官方支持的全列清,标明各自放哪、有什么独有的限制。
类比:乐高那几格零件盒,每格只装一种件。 轮子格、窗户格、人仔格——分门别类才拼得快。插件的组件也是一格一类:
| 组件 | 放哪 | 一句话作用 | 触发方式 |
|---|---|---|---|
| Skills | skills/<名字>/SKILL.md | 可调用的专项能力(第 26 篇) | 你 /插件名:skill名,或 Claude 自动调 |
| Commands | commands/*.md | skill 的扁平老写法,新插件用 skills | 同上 |
| Agents | agents/*.md | 专项 subagent(第 23 篇) | 出现在 /agents,Claude 派或你点 |
| Hooks | hooks/hooks.json | 事件触发的自动动作(第 33 篇) | 生命周期事件自动触发 |
| MCP servers | .mcp.json | 连外部服务(第 22 篇) | 启用即自动起,工具混进工具箱 |
| LSP servers | .lsp.json | 实时代码智能(跳定义、查引用) | 处理代码时自动用,需另装语言服务器 |
| Monitors | monitors/monitors.json | 后台监视日志/状态,有动静通知 Claude | 插件激活时自动起(实验性) |
几类需要单独点几句,都是官方文档里写明、但容易漏的限制:
Agents 在插件里被「削权」了。 这点很关键。官方明确:出于安全原因,插件提供的 agent 不支持 hooks、mcpServers 和 permissionMode 这三个 frontmatter 字段。 也就是说,插件里的 subagent 不能自己偷偷挂 hook、起 MCP、或改权限模式——这是防止你装个插件,它的 agent 在背后给你换权限。它支持的字段包括 name、description、model、effort、maxTurns、tools、disallowedTools、skills、memory、background、isolation 这些(isolation 唯一合法值是 "worktree")。
Hooks 能监听的事件巨多。 插件 hook 跟你自己写的 hook(第 33 篇)监听的是同一批生命周期事件——从 SessionStart(会话开始)、PreToolUse(工具调用前,能拦)、PostToolUse(调用成功后),到 Stop(回答结束)、SessionEnd(会话终止),官方列了三十个。新手不用记全,记住「几乎任何时机都能挂个动作」就行,具体留到第 33 篇。
Hook 类型不止「跑脚本」。 除了最常见的 command(跑 shell 命令),还有 http(把事件发到一个 URL)、mcp_tool(调 MCP 工具)、prompt(用模型评估一段提示)、agent(跑个 agentic 验证器)。
Monitors 是实验性的。 它让插件在后台盯着日志或状态,有新行就当通知喂给 Claude,不用你开口让它监视。实验性,架构可能变,且只在交互式会话里跑、需要 Claude Code v2.1.105 以上。新手了解有这么个东西即可。
还有两类「半组件」值得知道:bin/ 目录里的可执行文件,插件启用时会被加进 Bash 工具的 PATH,能当裸命令直接调;settings.json 是插件的默认设置,但目前只支持 agent 和 subagentStatusLine 两个键——其中设 agent 能让插件启用时直接把某个自定义 agent 顶成主线程,等于「装上这个插件就换了套人设」。
💡 一句话总结:插件能装七类零件——skill / command / agent / hook / MCP / LSP / monitor,各有固定位置;重点记两条限制:插件里的 agent 不许带 hook/MCP/权限模式(安全削权)、monitor 是实验性的。
04 ${CLAUDE_PLUGIN_ROOT}:为什么路径必须用变量,不能写死
这一节单拎出来,因为它是自己造插件时最高频的报错来源,而道理一句话能说透。
先看场景:你的插件里有个 hook 要跑 scripts/format.sh,或者 MCP server 要 node server.js。你想当然地写绝对路径 /Users/你/my-plugin/scripts/format.sh——完蛋,这条路在别人机器上根本不存在,而且就算在你机器上,插件每次更新缓存目录都会变。
官方的解法是给你三个路径变量,在 hook 命令、MCP/LSP 配置、skill/agent 内容里都会被自动替换:
| 变量 | 指向 | 用来 |
|---|---|---|
${CLAUDE_PLUGIN_ROOT} | 插件安装目录的绝对路径 | 引用插件自带的脚本、二进制、配置 |
${CLAUDE_PLUGIN_DATA} | 插件的持久数据目录(更新后保留) | 放 node_modules、缓存、跨版本要保留的状态 |
${CLAUDE_PROJECT_DIR} | 项目根目录 | 引用项目里的脚本/配置 |
类比:活页夹里写「本夹位置」,而不是抄死页码。 想象一份会被反复重新装订的活页夹,你要在里头写「去附录那页」。如果你写死「第 87 页」,一重新装订页码全乱;聪明的做法是写「本夹的附录」这种相对本夹的占位说法。${CLAUDE_PLUGIN_ROOT} 就是这个「本店地址」占位符——不管插件被装到哪、更新到第几版,它永远指向当前这一版的根目录。
所以插件里引用自带脚本,标准写法长这样(注意双引号,防路径带空格):
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "\"${CLAUDE_PLUGIN_ROOT}\"/scripts/format-code.sh"
}
]
}
]
}
}
这里有个官方反复强调的硬规矩,值得贴脑门上:
当 plugin 更新时,此路径会更改。前一个版本的目录在更新后约七天内保留在磁盘上以进行清理,但应将其视为临时的,不要在此处写入状态。
翻译一下:${CLAUDE_PLUGIN_ROOT} 是临时的,别往里写要长期保留的东西(比如装好的依赖、缓存)——那些该写进 ${CLAUDE_PLUGIN_DATA},因为数据目录跨版本保留。常见的翻车是把插件装的 node_modules 放进 ROOT,结果插件一更新依赖全没了,得重装。自带的脚本用 ROOT,要保留的状态用 DATA,这条分清就不出事。
还有个相关坑,官方在「插件缓存」那节专门讲:已安装的插件不能引用自己目录外的文件。你写 ../shared-utils 这种往外跳的相对路径,安装后会失效——因为插件被装时是整个复制进缓存(~/.claude/plugins/cache)的,外面的文件根本没被复制过去。要跨插件共享文件,得用符号链接,这是进阶话题,新手先记住「别往插件外引用」。
💡 一句话总结:插件里引用路径必须用
${CLAUDE_PLUGIN_ROOT}这类变量,不能写死绝对路径(每次更新都变);自带脚本用ROOT、要保留的状态用DATA,且绝不引用插件目录外的文件。
05 动手:从零造一个能跑的插件,再本地测
讲了四节构造,该真上手了。下面带你亲手造一个最小但完整的插件、本地加载、跑通它的 skill——全程不依赖任何复杂环境,跟着抄就行。我们造一个 my-greeter 插件,带一个打招呼的 skill。
第一步:用官方脚手架命令起一个插件骨架
最省事的不是手动建目录,而是用官方的 plugin init 命令,它会把骨架搭好:
claude plugin init my-greeter --with skills
--with skills 表示顺便搭一个示例 skill 文件夹。这条命令会在 ~/.claude/skills/my-greeter/ 下建好 .claude-plugin/plugin.json 和一个启动用的 SKILL.md。
预期:终端提示插件骨架已创建,告诉你建在了 ~/.claude/skills/my-greeter/。
这里有个官方设计的便利:放在
~/.claude/skills/下、带plugin.json清单的文件夹,下个会话会自动作为my-greeter@skills-dir加载,不用建市场、不用安装。这种叫「skills 目录插件」,是开发自用插件最轻的路子。
第二步:看看脚手架生成了什么
直接列一下目录(注意用绝对路径):
ls -R ~/.claude/skills/my-greeter
预期:你会看到 .claude-plugin/plugin.json 和 skills/(或一个 SKILL.md)。确认 plugin.json 在 .claude-plugin/ 里、skill 在外面——这就是第 01 节那条铁律的实物。
第三步:写一个属于自己的 skill
打开(或新建)~/.claude/skills/my-greeter/skills/hello/SKILL.md,内容写成:
---
description: 用热情的语气跟用户打招呼
---
# Hello Skill
热情地跟名叫 "$ARGUMENTS" 的用户打招呼,问问今天能帮上什么忙。语气友好、鼓励一点。
$ARGUMENTS 是占位符——它会捕获你在 skill 名后面打的任何文字。这是给 skill 传参的标准做法(第 26、27 篇讲过 skill,这里复用)。
第四步:本地加载这个插件
开发期不用建市场,用 --plugin-dir 直接加载本地插件目录,这是官方专给开发测试的标志:
claude --plugin-dir ~/.claude/skills/my-greeter
预期:Claude Code 正常启动。敲 /help,能在插件命名空间下看到你的 skill 列出来。
第五步:喊起你的 skill,亲眼看它跑
插件 skill 永远带命名空间,所以这么调(后面跟个名字当参数):
/my-greeter:hello Walter
预期:Claude 用一段热情的、带上「Walter」这个名字的话回应你。看到它按你写的 description 和正文打了招呼,说明这个插件不光建对了、它带的 skill 真能用了。
第六步:改了 skill,热重载看效果
把 SKILL.md 的正文改两句(比如让它用中文加 emoji),然后不用重启,在 Claude Code 里敲:
/reload-plugins
预期:重新跑一遍 /my-greeter:hello Walter,能看到改动生效了。
⚠️ 一个官方写明的区别:改
SKILL.md当前会话立即生效;但改 hooks、.mcp.json、agents/这些,得/reload-plugins或重启才生效。别改了 hook 发现没反应就以为写错了,先 reload 一下。
跑通这六步,你就把「造骨架 → 写组件 → 本地加载 → 调用 → 热重载」这条插件开发的完整内循环亲手走了一遍。以后造任何插件,本质都是这套流程,只是组件更多。
💡 一句话总结:
claude plugin init起骨架、--plugin-dir本地加载、/reload-plugins热重载——这三条命令是插件开发的内循环;放进~/.claude/skills/的还能免市场免安装自动加载。
06 把插件发出去:建一个市场
自用的插件,放 ~/.claude/skills/ 或 --plugin-dir 就够了。但要发给团队、发给社区,得走「市场(marketplace)」这一层——第 24 篇你是市场的「消费者」,这一节当一回市场的「店主」。
先理清两个长得像、极易混的概念,官方专门用 Note 框区分过:
| 概念 | 是什么 | 在哪定义 |
|---|---|---|
| 市场源(marketplace source) | 去哪拿那本「商品目录」(marketplace.json) | 用户 /plugin marketplace add 时,或设置里 |
| 插件源(plugin source) | 目录里每个插件本体从哪拿 | marketplace.json 里每个插件条目的 source 字段 |
类比:商场 vs 商场里每件商品的供货地。 「市场源」是这家商场开在哪、目录册从哪取;「插件源」是目录册里每件商品实际从哪个工厂发货。两者完全可以不在一处——商场目录可以挂在 A 仓库,里头某件商品从 B 工厂直发。
市场的核心是一个文件:仓库根目录下的 .claude-plugin/marketplace.json。它声明市场名、所有者、和插件清单。最小的一个长这样:
{
"name": "my-plugins",
"owner": { "name": "Your Name" },
"plugins": [
{
"name": "my-greeter",
"source": "./plugins/my-greeter",
"description": "A friendly greeting plugin"
}
]
}
每个插件条目至少要 name 和 source(从哪拿这个插件)。source 支持好几种来源,这是市场最实用的部分:
| 插件源类型 | 怎么写 | 适合 |
|---|---|---|
| 相对路径 | "./plugins/my-greeter" | 插件就在市场同一个仓库里(最常见) |
| github | { "source": "github", "repo": "owner/repo" } | 插件在另一个 GitHub 仓库 |
| git-subdir | 给 url + path | 插件在某个大仓库(monorepo,多项目合一仓库)的子目录,稀疏克隆省带宽 |
| npm | { "source": "npm", "package": "@org/plugin" } | 作为 npm 包发布的插件 |
动手:把第 05 节那个插件,装进一个本地市场试试。 假设你按上面的结构建好了 my-marketplace/(里头 .claude-plugin/marketplace.json + plugins/my-greeter/),在 Claude Code 里:
/plugin marketplace add ./my-marketplace
/plugin install my-greeter@my-plugins
预期:第一条提示市场添加成功;第二条把插件装上。然后 /my-greeter:hello 就能调了——这条链路跟第 24 篇你装别人插件时一模一样,只不过这次货是你自己的。
发布前一定先验证,官方给了专门命令:
claude plugin validate ./my-marketplace
预期:检查 marketplace.json 的 schema、有没有重复插件名、源路径有没有非法的 ..、版本对不对得上。指向市场目录时它只查 marketplace.json;要连 skill/agent 的 frontmatter 一起查,得指向具体插件目录(claude plugin validate ./my-marketplace/plugins/my-greeter)。
真要发给团队,把这个市场仓库推到 GitHub,同事一句 /plugin marketplace add owner/repo 就能加。想自动让团队装,可以在项目的 .claude/settings.json 里写 extraKnownMarketplaces,同事信任项目目录时会被提示安装——这块属于团队配置,新手先知道有这条路即可。
💡 一句话总结:发布走市场——根目录建
.claude-plugin/marketplace.json,列出插件和它们的source(相对路径/github/npm 等);分清「市场源」(目录从哪来)和「插件源」(每个插件从哪来);发布前claude plugin validate。
07 一组对照:自用、本地测、正式发布,三条路别走错
造插件的人最常犯的不是写错代码,是用错了「分发方式」——明明只是自己试,却去吭哧建市场;或者要发团队了,还在用只对自己生效的 --plugin-dir。这一节一张表把三条路钉清。
| 你的处境 | 该用 | 命令 | 特点 |
|---|---|---|---|
| 纯自用、想随手改随手用 | skills 目录插件 | 放进 ~/.claude/skills/<名>/(带 plugin.json) | 自动加载,免市场免安装,改 SKILL.md 立即生效 |
| 开发中、反复测一个本地包 | --plugin-dir | claude --plugin-dir ./my-plugin | 直接加载,不入库;可多次指定加载多个;.zip 也行 |
| 发给团队/社区 | 市场 | marketplace.json + /plugin install | 能版本管理、能自动更新、能共享 |
几个用起来才知道的细节:
--plugin-dir 是开发利器,但只管当前这一次会话。 你这次启动加载了,关掉再开就没了——它不写进任何配置。好处是干净:测完插件,关掉会话就一干二净,不留痕迹。开发时一个顺手的做法是一直挂着一个 --plugin-dir 的会话,改完 /reload-plugins,比每次重装市场快太多。官方还有个贴心设计:--plugin-dir 的本地副本,会临时盖过同名的已装市场插件——所以你能拿本地改动直接覆盖测试一个线上插件,不用先卸载。
skills 目录插件有个范围陷阱。 放 ~/.claude/skills/(个人级)的,每个项目都能用;但放项目 .claude/skills/ 的(项目级),官方明确警告:它只从你启动 Claude Code 的那个目录加载,不会像普通 skill 那样往仓库根目录上找。所以从子目录启动会漏掉根目录的插件——要么从仓库根启动,要么 /reload-plugins。
别一上来就建市场。 这是过度工程的典型。官方的建议很实在:先用 .claude/ 散装或 --plugin-dir 快速迭代,准备好共享了再转成插件、建市场。一个插件通常要在 --plugin-dir 下改十几轮才稳定,这期间建市场纯属给自己找麻烦——每改一次还得提交、刷新市场。
💡 一句话总结:三条路别走错——自用塞
~/.claude/skills/、开发用--plugin-dir、发布才建市场;--plugin-dir只活一次会话(干净),发布前先在前两条路上把插件迭代稳。
08 发布绕不开的两个坑:版本管理与依赖
插件能跑、能装,不代表能「发好」。版本管理和依赖是发布时两个最容易翻车的地方,官方都用警告框圈过,这一节专门填。
坑一:设了 version,推新提交却没人更新
这是最反直觉、最坑人的一个。Claude Code 怎么判断「插件有没有新版本」?它按这个顺序取版本号:
plugin.json里的version- 市场条目里的
version - 都没有的话,用 git 提交的 SHA
关键就在这儿。官方警告说得很重:
设置
version会固定 plugin。如果plugin.json声明"version": "1.0.0",推送新提交而不改变该字符串对现有用户没有任何作用,因为 Claude Code 看到相同的版本并保留缓存副本。
翻译成大白话:你一旦写死了 "version": "1.0.0",光往仓库推新代码是没用的——用户那边版本号没变,/plugin update 会回你「已是最新」,缓存压根不刷新。 你必须每次发版都手动把版本号往上提(1.0.1、1.1.0……)。
所以官方给了两种策略,二选一,别混:
| 策略 | 怎么做 | 更新行为 | 适合 |
|---|---|---|---|
| 显式版本 | plugin.json 里设 version,每次发版手动提 | 用户只在你提版本号时收到更新 | 有稳定发布节奏的正式插件 |
| 提交 SHA 版本 | 不写 version,git 托管 | 每推一个新提交都算新版本,用户自动拿到 | 内部、团队、快速迭代的插件 |
还有个加倍坑的:别在 plugin.json 和市场条目里都写 version。 官方明确——plugin.json 的值会无声地盖过市场条目的,你在 marketplace.json 里改了版本可能根本不生效,因为被那个陈旧的 plugin.json 版本号压住了。
显式版本这个坑很容易栽:一个团队内部插件设了 "version": "1.0.0",改了好几次代码推上去,同事一直反馈「怎么没更新」。你很容易以为是市场没刷新,折腾半天才反应过来——版本号没动,Claude Code 当然认为没变化。内部插件一律不写 version、让它用 SHA,推一次同事更新一次,就清净了。结论:快速迭代的内部插件别设 version,稳定发布的正式插件才设、且每次记得提。
坑二:依赖怎么声明
如果你的插件 A 必须有插件 B 才能工作,用 dependencies 字段声明:
{
"name": "my-plugin",
"dependencies": [
"helper-lib",
{ "name": "secrets-vault", "version": "~2.1.0" }
]
}
声明后,装/启用你的插件时,Claude Code 会自动把依赖也装上/启上。版本可以用 semver(语义版本范围)约束(像 ~2.1.0),免得依赖出个大版本把你的插件搞崩。卸载时,claude plugin uninstall --prune 能顺手清掉那些「只为满足依赖而自动装、现在没人要」的插件;你手动直接装的插件永远不会被 prune 碰。
类比:配料表里标「需另购的配件」。 一份家具说明书末尾写着「本款需另购 M4 螺丝包(2.1 规格)」——你照单备齐配件,家具才装得起来。dependencies 就是插件的这张配件清单:它把「我需要谁、要哪个版本」写明,Claude Code 照单自动备齐。
💡 一句话总结:发布两个坑——设了
version就必须每次发版手动提,否则用户收不到更新(快速迭代干脆别设、用 SHA);依赖用dependencies声明、可加 semver 约束,装你的插件时会自动连依赖一起装。
09 小结
这一篇把插件从「会用」推进到「会造、会发」——它本质就是一盒乐高:一本说明书(plugin.json)定身份,几格零件盒(组件文件夹)装能力,整盒打包就能发给任何人。
把核心要点串起来回顾:
| 你要搞清的事 | 关键点 |
|---|---|
| 目录骨架 | .claude-plugin/ 里只放 plugin.json,其余组件全摆根目录 |
| 清单字段 | 唯一必填 name(定命名空间);组件路径分「替换」(agents/commands)和「追加」(skills) |
| 能装哪些组件 | skill/command/agent/hook/MCP/LSP/monitor 七类;插件里的 agent 被削权(无 hook/MCP/权限模式) |
| 路径怎么写 | 必须用 ${CLAUDE_PLUGIN_ROOT} 等变量,不写死、不引用目录外文件;状态放 DATA 不放 ROOT |
| 开发内循环 | plugin init 起骨架 → --plugin-dir 加载 → /reload-plugins 热重载 |
| 发布 | 建 marketplace.json,分清市场源/插件源,claude plugin validate 验证 |
| 两个坑 | 设了 version 必须每次提;依赖用 dependencies 声明 |
你现在应该能: 看懂任何一个插件的目录在干嘛、自己从零搭一个能跑的插件骨架、用 --plugin-dir 本地测、再建个市场把它发给团队;也清楚 ${CLAUDE_PLUGIN_ROOT} 为什么不能写死、version 那个「不提就不更新」的坑怎么躲。第 24 篇你学会了消费别人的插件,这一篇你成了能生产插件的人——把自己那套攒了好久的配置打成一个包发出去,从此不再是只能抄别人的。
到这里,Claude Code 的「扩展 + 配置 + 打包分发」这条线就齐全了。从第 18 篇的 CLAUDE.md、第 22 篇的 MCP、第 23 篇的 subagent,到第 24、38 这两篇的插件——你不光会用这些工具,还会把它们组装、打包、交付给别人。
下一篇 39「实战入门」——前面三十多篇全是「一个个功能拆开讲」,你手里的零件已经堆成山了。下一篇不再讲新功能,而是把这些零件第一次串成一条完整的实战路径:拿一个真实的小需求,从开工到交付走一遍,让你亲眼看见「学过的东西怎么拧成一股绳干活」。想想看——你现在会的每一招,单独使都顺手,但真打一仗时,该先抽哪把、再接哪把?
39 · 实战入门:拿一个真需求,从开工到交付走一整趟
说句实话,大多数人以为 AI 写代码就是「一句话然后等结果」——说清楚需求,Claude 自己跑完,你接过来用。这条路听起来顺,踩一次坑就知道哪里断了:
方向跑偏了、顺手多改了三个文件、说好的 bug 修完照崩……最后花在收拾的时间,比自己动手还多。
不是工具不够聪明,是这趟流程里少了几个关键交接棒。
说白了,这就是「学过每个动作」和「能把动作连成一趟」之间的鸿沟。 你练过打方向、练过看后视镜、练过点刹车,但第一次独自上路,得把这些动作按正确的顺序连起来才叫会开车。这一篇不教任何新功能,只干一件事——带你把已经会的零件,第一次连成一条能跑通的实战路径。
我们挑的任务小到不能再小,但五脏俱全:给一个数单词频率的小脚本加个功能,顺手修个 bug。麻雀虽小,从开工到交付那条完整的路,一步都不缺。
看完这一篇,你会拿到:
- 一条「开工 → 探索 → 规划 → 动手 → 验证 → 交付」的标准实战路径,每一步该敲什么、看什么
- 一个能照着抄的真实小任务(数单词的脚本加
--top N、修空参数崩溃),全程命令 + 预期输出 - 「先让它探索、再让它动手」这条铁律为什么是新手最该养成的肌肉记忆
- 怎么用 plan mode(详见第 20 篇)让它先出方案再砸代码,以及怎么审查它给你的 diff
- 一张「老手怎么走 vs 新手怎么走」的对照表,把最常踩的顺序坑标出来
01 先看全景:一趟实战,就这六步
动手之前,先把整趟路在脑子里过一遍。一个真实任务从接到手到交付,无论大小,骨架都是这六步:

类比:接力赛的交接棒。 这六步就是六个交接棒的人:探索把「我看懂了什么」交给规划,规划把「打算怎么改」交给动手,动手把「改了什么」交给验证。任何一棒掉了棒,整趟都得返工——新手翻车,九成是某个交接没做,最典型的就是「没探索就直接让它动手」,棒还没拿稳就开跑。
这六步不是我编的,它就是官方快速开始(quickstart)和常见工作流(common workflows)两篇文档拼起来的实操顺序。官方那句话点得很到位:
在进行更改之前,让 Claude 理解您的代码。
这六步还能压缩,但不能跳。 熟手会把「探索 + 规划」合成一句话、把「验证 + 交付」连成一个动作,看起来像三步——但每一步都还在,只是节奏快了。新手最爱犯的不是「走得慢」,而是直接把中间四步全删了,只剩「说需求 → 拿结果」,等于把棒从第一个人手里直接扔到终点线,中间没人接。这一篇剩下的篇幅,就是带你把这六步在一个真实任务上踏踏实实走一遍,每一棒都亲手交一次。我会在每步开头标清「这一步对应前面哪一篇学过的东西」,让你边走边把零件对上号。
💡 一句话总结:一趟实战的骨架永远是「开工 → 探索 → 规划 → 动手 → 验证 → 交付」六步,像接力赛一样棒棒得交到位;新手最常掉的那一棒,是「没让它探索就直接动手」。
02 准备:造一个练手的小项目
为了让你能原样照着跑,我们不碰任何真实的大项目,先花两分钟造一个最小的练手场。它只有一个 Python 脚本加一个文本文件,不依赖任何第三方库,有 python3 就能跑(Mac / Linux 自带;Windows 装了 Python 即可)。
第一步:建目录、进去、放两个文件
在终端里执行(这一步是纯手动准备,还没动用 Claude Code):
mkdir wordcount-demo && cd wordcount-demo
新建一个 wordcount.py,内容如下(这就是我们要改的「祖传代码」,故意写得糙一点):
import sys
from collections import Counter
def count_words(path):
with open(path) as f:
text = f.read()
words = text.lower().split()
return Counter(words)
def main():
path = sys.argv[1]
counts = count_words(path)
for word, n in counts.items():
print(f"{word}: {n}")
if __name__ == "__main__":
main()
再建一个 sample.txt 当测试数据:
the quick brown fox the lazy dog the fox
第二步:手动跑一遍,确认它能用
python3 wordcount.py sample.txt
预期输出(顺序可能略有不同,数字一定一样):
the: 3
quick: 1
brown: 1
fox: 2
lazy: 1
dog: 1
看到这些计数 = 脚本正常工作,练手场搭好了。这个脚本有两个毛病,正好当我们的任务:
- 缺个功能:我想只看「最高频的前 N 个词」,现在它一股脑全打出来。
- 藏个 bug:你试试不带文件名直接跑
python3 wordcount.py,它会甩你一脸IndexError崩溃,而不是好好提示你「该传个文件」。
第三步:把它纳入 git(这一步很关键,别跳)
git init && git add . && git commit -m "init: 一个简陋的数词脚本"
预期:末尾出现一行类似 2 files changed 的提交确认(wordcount.py 和 sample.txt 各记一笔)。看到它 = 你已经有了一个干净的「原点」,后面无论 Claude 把代码改成什么样,你都能一键退回这里。
为什么开工前一定先 git commit?因为它是你最硬的那张后悔药。第 37 篇讲过检查点(checkpoint)能倒带 Claude 的编辑,但检查点和 git 是两套东西、各管一段(第 37 篇专门掰过)。开工前一个干净的 git 提交,是你「无论后面怎么折腾都能一键回到原点」的地基——没提交就让它大改、改完想反悔却没有干净基线可对比,是很常见的亏,所以雷打不动先提交再开工。
💡 一句话总结:练手场就一个糙脚本 + 一个文本文件,有
python3就能跑;它故意留了「缺功能」和「藏 bug」两个活儿;开工前先git commit一次,给自己留最硬的后悔药。
03 开工:在项目目录里启动,先写一份最小的 CLAUDE.md
环境有了,正式开第一棒——开工。这一步对应第 02 篇(启动)、第 07 篇(第一次跑通)、第 12 / 18 篇(CLAUDE.md)。
第一步:在项目根目录启动 Claude Code
你得在 wordcount-demo 这个目录里敲 claude,而不是在别处。Claude Code 默认拿「你启动它的那个目录」当工作区——站错地方,它读的就是别的项目的文件。
claude
预期:看到 Claude Code 的欢迎屏,底部显示当前目录是 wordcount-demo。这就是第 07 篇带你跑通过的那个起点。
第二步:先给它一份「最小可用」的 CLAUDE.md
第 18 篇反复强调过一句话:最没用的 CLAUDE.md 是写了三百行 Claude 一条没听的那种。所以练手项目别贪多,三五行说清最要紧的规矩就够。我们这个小脚本,规矩其实就两条:用什么跑、改完怎么验。在会话里直接让它生成(也可以手写,但让它写更省事):
帮我在项目根目录建一个 CLAUDE.md,写清两条:
1. 这是个纯标准库的 Python 命令行小工具,不要引入任何第三方依赖
2. 每次改完代码,用 python3 wordcount.py sample.txt 跑一遍验证不报错
预期:Claude 会先把要写的内容给你看,再请求批准写文件(第 20 篇讲的权限机制——它动文件前一定先问你)。批准后,项目根目录多出一个 CLAUDE.md,内容大致长这样:
# wordcount-demo
一个数文本里单词频率的命令行小工具。
## 技术约束
- 纯 Python 标准库,**不要引入任何第三方依赖**。
## 验证
- 每次改完代码,跑一遍确认不报错:`python3 wordcount.py sample.txt`
短,但两条最要紧的规矩都钉死了。别嫌它简陋——三五行能管住的事,不必写三十行。
这里你可能想到第 12 篇的
/init。区别在:/init是让 Claude 自己扫一遍代码库、自动生成一份较完整的说明书,适合有点规模的真实项目;咱们这个脚本就两个文件,手动指明那两条核心规矩反而更准、更短。两条路都对,看项目大小挑。
为什么开工就花这一步写 CLAUDE.md?因为它是给后面所有交接棒定的「总规矩」。等下你让它加功能,它会自动记得「别引第三方库」;改完它会自动记得「跑一遍验证」——你只说一次,整场都生效,不用每个指令都复读。这就是 CLAUDE.md 最实在的价值:把「每次都要嘱咐的话」固化成它每会话自动加载的背景。
💡 一句话总结:开工 = 站对目录敲
claude+ 写一份三五行的最小 CLAUDE.md 把核心规矩定死;练手小项目手动指明两条规矩,比/init扫全库更准更短。
04 探索:先让它「看懂」,别急着让它「动手」
这是整趟路最该养成肌肉记忆、也最容易被新手跳过的一棒——探索。对应第 16 篇「四个最常用的活儿」里的第一类。
先说结论:拿到任务的第一句话,不是「给我改」,而是「先看懂」。
开头那个愣住的场景,犯的就是这个错——一上来就想敲「给脚本加个 --top 参数」。坏在哪? Claude 对你的代码一无所知,它会一边猜一边改,猜错了就给你改出一堆四不像。正确的开法是先派它去摸清现状:
先别改任何代码。给我讲讲 @wordcount.py 现在是怎么工作的,
入口在哪、有没有什么明显的问题或者容易崩的地方?
注意两个细节:
- 开头那句 「先别改任何代码」,是给它划一道线——这一棒只许看、不许动。第 15 篇讲过,把边界说清,它就不会越界。
- 那个
@wordcount.py,是用@直接把文件内容塞进对话(第 16、17 篇提过的@引用),省得它再去翻一道。
预期:Claude 会读完文件,给你一段讲解——大致会说:这是个用 Counter 数词频的脚本,入口是 main(),它从 sys.argv[1] 取文件路径,然后大概率会主动点出那个隐患:如果不传文件名,sys.argv[1] 会越界崩溃。
看到没——你还没提那个 bug,它探索的时候自己就发现了。这就是「先探索」白赚的好处:它不光看懂了现状,还顺手帮你把问题摸出来了。这一棒交得漂亮,下一棒(规划)才有谱。
这个脚本只有十几行,探索一句就够;但真实项目里,探索往往要「由宽到窄」问几层。 官方常见工作流里给的探索套路就是这个节奏:先问全局,再钻局部——
先给我这个代码库的整体结构和它是干嘛的(先别改任何代码)
处理用户登录的逻辑在哪几个文件?它们怎么配合的?
第一句拿到「全局地图」,第二句顺着地图钻进你要改的那块。为什么不一上来就问细节? 因为它对项目越没概念,越容易把「看起来相关」的文件当成「真正相关」的——先给它一张全局地图,它后面定位才准。进一个没碰过的中等项目,雷打不动先来这么两三句,宁可多花两分钟探索,也不让它带着错误的全局印象去改。
类比:第一次独自上路前,先绕车走一圈。 老司机上车前会下意识扫一眼——轮胎瘪没瘪、后面有没有障碍、镜子角度对不对。这一圈花不了十秒,但能避开「直接挂挡撞上没看见的柱子」。让 Claude 先探索,就是上路前这一圈——十秒钟的「看一眼」,省掉的是后面「改错了推倒重来」的半小时。
探索阶段读文件会吃上下文(第 19 篇讲过工作台塞满会变蠢)。任务大、要翻一堆文件时,可以让它派个 subagent 去探索(第 23 篇)——子代理在自己的窗口里翻,只把结论递回来,你的主对话不被一堆文件内容灌满。小任务用不上,知道有这条路即可。
💡 一句话总结:拿到任务第一句话永远是「先别改、先看懂」;让它探索不仅省掉瞎猜乱改,还常常白赚一个「它主动帮你发现的问题」——这一棒,新手最该练成本能。
05 规划:让它先出方案,你点头了再砸代码
探索完,它懂了现状,也知道你要干嘛。但还差一步——让它先把「打算怎么改」摆出来给你看,你认可了再动手。这一棒对应第 20 篇里的 plan mode(计划模式)。
为什么不直接让它改?因为 「它理解的方案」未必是「你想要的方案」。让它先讲一遍打算,是花一分钟堵住「方向就跑偏了还一路改到底」的最便宜的保险。
方式一:直接让它先说方案、别动手
最简单的,一句话约束它:
我想给这个脚本加一个 --top N 参数,只显示最高频的前 N 个词;
顺手把不传文件名就崩溃的问题也修了。
先告诉我你打算怎么改、动哪几个地方,等我说「开始」你再动手。
预期:它会回你一份计划,类似——用 argparse 替掉手写的 sys.argv、加一个 --top 选项、用 Counter.most_common(N) 取前 N 个、不传文件名时由 argparse 自动报友好提示而不是崩溃。它停在这儿等你拍板,不会擅自改文件。
方式二:正经用 plan mode
如果是更大的任务,更稳妥的是切到官方的计划模式——它会强制Claude 不编辑源代码、只产出方案,不批准就一行都不改(但它仍可运行 shell 命令做探索)。两种进法(第 20 篇讲过):
claude --permission-mode plan
或者在会话里按 Shift+Tab 循环切到 plan mode。官方对它的定位很清楚:
Claude 读取文件并提出计划,但在您批准前不进行任何编辑。
这两种方式的区别,一张表看清:
| 做法 | 怎么约束它 | 强制程度 | 适合 |
|---|---|---|---|
| 一句话叫它先说方案 | 靠你在提示里写「先别动手」 | 软约束(它一般会听,但没拦死) | 小改动、你盯着的时候 |
| plan mode | 模式层面禁止编辑源代码(shell 命令仍可跑) | 硬约束(批准前源代码一行都改不了) | 大改动、不放心、想认真审方案 |
一个实用的习惯:像这个 --top 这么小的改动,方式一一句话就够;但凡涉及多文件、或心里没底的改动,一律 Shift+Tab 切 plan mode——让模式替你把住「没点头不许动」这道闸,比盯着省心。给一个不熟的项目做较大改动时,要是图快没切 plan mode,它很可能一口气改了四个文件、方向还跟你想的不一样,回退花的时间够看三遍方案了。所以拿不准就 plan。
💡 一句话总结:动手前让它先出方案、你点头再改;小改动一句「先别动手」就行,大改动 / 没底的改动用
Shift+Tab切 plan mode 硬性锁住「批准前一行不改」。
06 动手 + 审查:放它改,但每一处 diff 你都过一眼
方案点头了,第六棒(其实是动手和审查连着的一棒)——让它改,同时你盯着每一处改动。对应第 20 篇的权限确认。
第一步:给它开绿灯
方案可以,开始改吧。
预期:Claude 开始编辑 wordcount.py。关键来了——它每改一处,会把那段 diff(改动对照:删了哪几行、加了哪几行)摆到你面前请求批准(除非你开了「全部接受」模式,新手强烈别开)。第 20 篇讲过这套权限机制,这一步就是它真正落地的时刻。
第二步:认真看 diff,别无脑回车
这是新手最容易松懈的地方——diff 划过去看都不看就一路 y。我的铁律是:每一处改动至少扫一眼「它动的是不是我让它动的地方」。这个任务里你该看到的改动大致是:
- import sys
+ import argparse
- def main():
- path = sys.argv[1]
- counts = count_words(path)
- for word, n in counts.items():
+ def main():
+ parser = argparse.ArgumentParser(...)
+ parser.add_argument("path", ...)
+ parser.add_argument("--top", type=int, default=None, ...)
+ args = parser.parse_args()
+ counts = count_words(args.path)
+ items = counts.most_common(args.top) if args.top else counts.most_common()
+ for word, n in items:
扫一眼确认三件事:① 它确实在加 --top 和改入参(符合方案);② 没顺手乱动 count_words 那个本来就好的函数;③ 没偷偷引入第三方库(CLAUDE.md 立的规矩)。 对得上,就批准。
怎么快速扫一段 diff? 不用逐字读,盯三类信号就够:红行(-,删了什么)别有你舍不得删的;绿行(+,加了什么)别有你没要的依赖或没让加的功能;改动的范围别超出你说的那几个地方。这个任务里红行删的是手写 sys.argv、绿行加的是 argparse 和 --top,范围只在 main() 里——全在预期内,放心批。
关于那个「全部接受」模式,给新手一句忠告:练手阶段别开。 quickstart 里提过你可以「为会话启用全部接受模式」(也就是第 20 篇的 acceptEdits),开了它就不再逐处问你、自己一路改下去。省事,但代价是你彻底交出了「事中拦截」这道窗口。 比较稳的做法是只在两种情况开:一是改动已经在 plan mode 里逐行看过方案、心里有数;二是一堆机械的重复改动(比如批量改个变量名)。头一两个月,老老实实一处一处看,把「读 diff」的眼力练出来再谈放飞。
为什么审查这一步省不得? 因为 AI 改代码不是「对或错」的二极管,它常常「大体对、细节偏」——可能多改了你没让改的地方,可能用了你不想要的写法。第 20 篇那句话值得再贴一遍:
Claude Code 在修改文件前始终请求许可。
这道许可不是走过场,它是你「事中拦截」的唯一窗口——一旦批了、改下去了,就得靠第 37 篇的检查点或 git 去「事后倒带」,成本高一截。事中扫一眼 diff,永远比事后回滚划算。
💡 一句话总结:动手阶段放它改、但每处 diff 都过一眼——确认「动的是该动的、没乱碰好代码、没违反 CLAUDE.md」;这道批准是你事中拦截的唯一窗口,无脑回车等于把后悔药留给事后。
07 验证:跑给你看,别信「我改好了」
代码改完了,它八成会跟你说一句「已经改好了,加上了 --top 参数,也修复了崩溃问题」。这句话你一个字都别信,直到你亲眼看它跑通。 这是整趟路的倒数第二棒,也是新手最爱省的一棒。
先说结论:「它说改好了」不算数,「跑一遍对了」才算数。 这正是项目规范里那条「改完主动验证、不要只改不验」的硬要求,落到实操就是——亲手把验收标准跑一遍。
第一步:验证新功能(--top)
python3 wordcount.py sample.txt --top 3
预期输出(按词频从高到低,只出前 3 个):
the: 3
fox: 2
quick: 1
看到只剩前三、且是按频率排好序的 = 新功能成了。(the 出现 3 次、fox 2 次,第三名是任意一个出现 1 次的词。)
第二步:验证旧功能没被改坏(回归)
加了新参数,老用法不能崩——不带 --top 时得跟原来一样全打出来:
python3 wordcount.py sample.txt
预期:跟第 02 节那份原始输出一致(六个词全在)。一致 = 没有「修好新的、碰坏旧的」。
第三步:验证 bug 真的修了
这步最关键——重现当初那个崩溃,看它现在是不是好好提示而不是甩 traceback:
python3 wordcount.py
预期:不再是那串 IndexError 崩溃,而是一行干净的用法提示,类似:
usage: wordcount.py [-h] [--top TOP] path
wordcount.py: error: the following arguments are required: path
从「程序崩了甩你一脸 traceback」变成「明确告诉你少传了 path」——这就是 bug 修好的铁证。三步全过,这趟活儿才算真的成了。
想再稳一档?让它把验证「钉成一个测试」。 上面三步是你手动跑、这次过了就完事;但同一个 bug,下次别人一改代码可能又崩回去。更稳的做法是让 Claude 顺手写个小测试,把「不传文件名要友好报错」这条变成可重复跑的关卡——官方常见工作流里专门有「修复 bug 时先写一个能重现它的测试,再让测试通过」这套(项目规范里那条「写重现 bug 的测试再让它通过」也是这个意思):
给「不传文件名时不崩溃、而是退出码非 0 并打印用法提示」写一个测试,再确认它通过。
预期:Claude 写一小段测试(用 subprocess 跑脚本、断言退出码和输出),然后跑给你看绿灯。这一步把「我这次跑过了」升级成「以后每次都能自动验」——对一次性练手是锦上添花,对真实项目几乎是必备。小任务你嫌重可以跳,但心里得有这根弦。
为什么对「亲手跑」这么轴?因为被「我改好了」坑过的人不止一两个。 让它修一个边界情况,它信誓旦旦说修好了,没跑就提交,结果那个边界根本没覆盖到——它改的是「看起来相关」的另一处。所以认一个死理:AI 说的「完成」是假设,你跑出来的「通过」才是事实。 这跟项目规范里那句「凡声称已验证,必须真的跑一遍」是一个意思。
💡 一句话总结:验证 = 亲手跑三遍——新功能对不对、旧功能有没有被改坏、bug 是不是真修了;「它说改好了」是假设,「你跑出来对了」才是事实,这一棒省不得。
08 交付:让它写提交信息,把成果存进库
三步验证全过,最后一棒——交付,把这次成果稳稳存进 git。对应第 07 篇尾巴提过的「对话式 Git」。
第一步:先看一眼到底改了什么
我改了哪些文件?给我一个改动概览。
预期:Claude 跑 git status / git diff,告诉你这次只动了 wordcount.py,新增了 --top 参数、把入参改成 argparse。交付前再确认一次「改动范围跟预期一致」,是临门一脚的复查。
第二步:让它生成提交信息并提交
用一句话描述清楚这次改动,提交它。
预期:Claude 会先把它拟的提交信息(commit message)给你看——类似「feat: 给 wordcount 加 —top N 参数并用 argparse 修复缺参崩溃」——再请求批准执行 git commit。这又是第 20 篇那道权限闸:它动你的 git 历史前,照样先问你。
这里插一句重要的边界:
git commit它会先把要提交的内容给你确认;但git push(推到远程)是另一回事。把成果推上 GitHub 之类的远程仓库前,务必你自己心里有数、亲自把关——这是第 43 篇「Git 工作流」要细讲的,这里你先记住:本地提交可以放手让它代劳,推远程这一步自己捏在手里。
第三步:确认提交成功
显示我最后 1 次提交。
预期:它跑 git log -1,你能看到刚才那条提交信息和改动。看到它 = 这趟活儿正式交付,从开工到入库全程闭环。
走到这儿,你回头看看:从一个崩溃、功能也不全的糙脚本,到一个带 --top、缺参数还会友好提示的小工具,全程你只敲了六七句自然语言——但每一句都卡在那六步的正确位置上。这就是「把零件连成一趟」的样子。
💡 一句话总结:交付 = 先看改动概览 → 让它拟提交信息并
commit(它会先给你确认)→git log验证入库;记住边界——本地 commit 可放手,push 远程自己把关(留给第 43 篇)。
09 改岔了怎么办:干净地退回去,别在烂摊子上硬补
上面那趟走得顺,是因为这里故意挑了个小任务。真实任务多半没这么乖——验证那一步常常是红的:功能没实现对、或者它把别处改坏了。这时候新手的本能反应往往是错的:对着已经改乱的代码,再让它「在这基础上修一下」。
别这么干。 在一个已经偏了的状态上反复打补丁,越补越乱——它每次都带着上一版的错误上下文,很容易把窟窿越捅越大。正确的处理是:先干净地退回到一个已知正确的点,再带着「这次该怎么说得更清楚」重开一次。 这正好把第 37 篇的检查点和第 02 节那个开工前的 git 提交派上用场。
退回有两档,看你改到哪一步了:
| 退回档位 | 用什么 | 退到哪 | 适合 |
|---|---|---|---|
| 轻档:撤销刚才的编辑 | 第 37 篇的检查点,/rewind | Claude 改这一批文件之前 | 改岔了一两处、刚发现就想撤 |
| 重档:回到开工原点 | git,git restore . / git reset --hard | 你开工前那个干净提交 | 整个方向都偏了、想从零重来 |
轻档最常用:在会话里敲 /rewind,它能把 Claude 这一轮的文件编辑倒带回去(第 37 篇专门讲过它的边界——能回文件、回对话,但别拿它当 git 使)。重档是兜底:要是改得面目全非、检查点也理不清了,就回到第 02 节那个开工提交——这就是当初为什么坚持「开工前先 commit」,那一个干净提交,就是你永远能逃回去的原点。
退回去之后别急着原样重说一遍。先想想这次为什么偏了——十有八九是探索没做够、或者指令给得太含糊(第 15 篇讲的「话说清」)。一条经验:第一次让它改偏了,90% 是那句指令里漏了关键约束,比如没说清「只改这个函数、别动别的」。退回原点、把那句话补具体,第二次往往就顺了。退回不是失败,是止损——比在烂摊子上硬补省太多事。
💡 一句话总结:改岔了第一反应是「干净退回」,不是「在烂摊子上硬补」;轻档用
/rewind撤编辑、重档用 git 回开工原点(开工前那次 commit 就是干这个的);退回后先补清指令再重开,别原样重说。
10 一组对照:老手怎么走 vs 新手怎么走
同样这六步,老手和新手走出来天差地别——差的全在那几个「省掉的交接棒」上。我把最常见的坑并排列出来,你对着自查:
| 环节 | ❌ 新手常踩 | ✅ 老手怎么走 |
|---|---|---|
| 开工 | 随便哪个目录就敲 claude,不写 CLAUDE.md | 站对项目目录,先写三五行最小 CLAUDE.md 定规矩 |
| 探索 | 上来就「给我改」,跳过看懂 | 第一句永远「先别改、先看懂」,让它先摸现状 |
| 规划 | 直接让它动手,方向偏了才发现 | 让它先出方案、点头再改;没底就 plan mode |
| 动手 | diff 看都不看一路 y | 每处 diff 扫一眼:动的对不对、有没有越界 |
| 验证 | 信「我改好了」就完事 | 亲手跑三遍:新功能、旧功能、bug 各验一遍 |
| 交付 | 改完晾着,或不看范围直接提交 | 先看改动概览、让它拟提交信息、log 确认入库 |
这张表的精髓就一句:新手把六步压成两步(说需求 → 拿结果),老手老老实实走六步。 刚上手那阵子谁都爱抄近道,吃过几次「方向跑偏 + 没验证就提交」的连环亏,才慢慢把这六步走顺。最该先练成本能的是头尾两棒——开头的「先探索」和结尾的「亲手验证」,这两棒守住,翻大车的概率就低一大半。
还有个常被问的:「每次都这么六步,不嫌麻烦?」 不嫌,因为任务越小,每步越快——咱这个练手任务,六步全走完也就十分钟。而且熟了以后,探索和规划常常能合并成一句话(「先看懂 @file 再告诉我你打算怎么改 X,别动手」)。流程是骨架,不是镣铐;骨架记牢了,怎么打快板是你的事。
💡 一句话总结:老手 vs 新手的差距全在「省没省掉交接棒」;最该练成本能的是头尾两棒——开头「先探索」、结尾「亲手验证」;任务越小每步越快,六步是骨架不是镣铐。
11 小结
这一篇没教任何新功能,只干了一件事——带你把前面三十八篇学的零件,第一次在一个真实小任务上连成一趟完整的实战路径。
先把整趟你敲过的话连起来回放一遍,你会发现就这六七句、每句卡在一个交接棒上:
# 开工后(先定规矩)
帮我建个 CLAUDE.md:纯标准库别引第三方依赖;改完跑 python3 wordcount.py sample.txt 验证
# 探索(先看懂、别动手)
先别改任何代码。讲讲 @wordcount.py 怎么工作的、有没有容易崩的地方?
# 规划(出方案、等点头)
我想加 --top N 只看高频前 N 个词,顺手修不传文件名就崩溃的问题。先说方案,等我说开始再动手。
# 动手(点头放行,然后逐处审 diff)
方案可以,开始改吧。
# 验证(亲手跑,不信它说的)
(回终端跑:--top 3 / 不带 top / 不带文件名,三条各验一遍)
# 交付(看范围 → 提交 → 确认)
我改了哪些文件? → 用一句话描述这次改动,提交它。 → 显示我最后 1 次提交。
看清楚没——真正的「实战」就是这几句自然语言,难的从来不是话术,是把每句话放对位置。 把这趟路的六步串起来回顾:
| 步骤 | 这一步干什么 | 用到的前篇 | 一句话关键点 |
|---|---|---|---|
| 开工 | 站对目录启动 + 写最小 CLAUDE.md | 02 / 07 / 12 / 18 | 核心规矩说一次,全场生效 |
| 探索 | 让它先看懂代码、别动手 | 16 | 第一句永远「先别改、先看懂」 |
| 规划 | 让它出方案、你点头 | 20(plan mode) | 没底就 Shift+Tab 硬锁「批准前不改」 |
| 动手 | 放它改、每处 diff 过一眼 | 20(权限确认) | 事中拦截比事后回滚划算 |
| 验证 | 亲手跑通,别信「我改好了」 | 16 / 37 | 跑出来的「通过」才是事实 |
| 交付 | 看范围 → 拟提交信息 → 入库 | 07 | 本地 commit 可放手,push 自己把关 |
你现在应该能: 拿到任何一个「帮我给某个东西加个功能 / 修个 bug」的真实小需求,不再对着终端发懵不知先敲哪句——心里默念那六步(开工、探索、规划、动手、验证、交付),一棒一棒交到位地走下来;尤其守住头尾两棒「先探索、后验证」,让 Claude 既不瞎猜乱改、改完也确实跑得通。这套流程跑顺了,前面学的所有零件才算真正活了过来,能拧成一股绳替你干活。
这一篇是个分水岭——从这儿往后,咱们默认你「会把零件连成一趟」了,后面几篇会在这条实战路径上继续加新本事。
下一篇 40「Chrome:让它操作浏览器」——这一趟实战,Claude 干的全是「本地文件 + 命令行」的活。但真实工作里,多少事得在浏览器里完成:填个表单、点几下页面、抓一段网页上的数据、对着真实渲染的界面调样式。下一篇就给它接上浏览器这只「手」,让它从「只会改代码」迈向「能替你点鼠标」。想想看——当 Claude 不光能改你的代码、还能亲自打开浏览器替你操作时,它能帮你干的活,又要宽一大圈了。
40 · Chrome:让它操作浏览器
⚠️ 实验性功能,可能随版本变化。 本篇讲的 Chrome 集成目前处于测试版(beta),命令、前置版本、支持的浏览器都以官方文档为准,后续版本可能调整。
兄弟们,今天聊一个能让 Claude Code「长出手」的功能——操作浏览器。
前面三十九篇里,Claude 干的活基本都在「文件 + 命令行」这一亩三分地:读你的代码、改你的文件、跑你的脚本。但真实开发里有一大堆事是离不开浏览器的——改完登录表单得打开页面点一下试试、报了个 bug 得看浏览器控制台(console)里红色的报错、设计稿还原得对着浏览器一像素一像素比。这些事,以前你只能自己切到 Chrome 手动来,然后把看到的复制回来喂给 Claude。
现在不用了。 接上 Chrome 集成,你在终端里说一句「打开 localhost:3000,用错误数据提交那个表单,看看报错提示对不对」,Claude 自己就把浏览器开了、表单填了、报错读了,回头告诉你结果。「改代码」和「在浏览器里验代码」第一次能在同一个对话里从头到尾搞定,不用来回切窗口。
我第一次接上它那天,盯着自己那个 Chrome 自动弹出新标签页、鼠标点搜索框、一个字一个字敲进去,愣是看了一会儿——那种「它真的在替我点」的感觉,跟之前在沙箱里跑命令完全是两码事。
这么说吧:前面 MCP(详见第 22 篇)是给它接上了数据库、Jira 这些数据源;Chrome 集成是给它接上了你天天在用的那个浏览器本身——连着你所有的登录态。这一篇就讲清楚它能干嘛、怎么接、有哪些坑、以及操作你「真浏览器」这件事的安全边界在哪。
看完这一篇,你会拿到:
- 一句话讲明白 Chrome 集成是什么、它和 MCP / computer use 各管哪一块
- 接上它的完整步骤(装扩展、
--chrome启动、前置版本和套餐要求),以及哪些浏览器 / 环境不支持 - 六类高频用例(实时调试、设计验证、填表单、扒数据……,选自官方列出的典型工作流),每类配一句你真实会怎么用
- 操作「真浏览器」相对沙箱的风险在哪、官方给了哪些护栏、你自己该守哪几条
- 一个能照着跑、给了预期结果的最小实战:接上 Chrome 让它读一次页面
01 先搞懂:它到底是什么、能干什么
先给结论:Chrome 集成 = 让 Claude Code 借用你已经登录好一切的那个 Chrome,替你开网页、点按钮、填表单、读页面。
关键词是「你已经登录好的那个」。官方说得很直接:
Claude 为浏览器任务打开新标签页,并共享您浏览器的登录状态,因此它可以访问您已登录的任何网站。浏览器操作在实时可见的 Chrome 窗口中运行。
把这句话拆开,有三个点对小白特别重要:
- 开的是新标签页,不是另起一个陌生浏览器——它就在你眼前那个 Chrome 里干活。
- 共享你的登录态——你 Gmail、Notion、公司后台都登录着,它直接就能进,不用你再配什么 API、贴什么 token。
- 窗口实时可见——它点哪、填哪你全看得见,不是在后台偷偷摸摸。
类比:叫了个代驾。 你今晚喝了点酒,叫个代驾把你送回家。代驾开的不是他自己的车,是你这台车——车里插着你的 ETC、储物格放着你的停车卡、导航里存着你家地址,这些他全能直接用,你不用重新给他办一张卡。但方向盘你随时能要回来:遇到要刷脸的小区门禁(代驾刷不了),他停下让你来。Claude 操作浏览器就是这么个「代驾」——开的是你那台登录好一切的浏览器,该它干的它干,遇到登录页、验证码(CAPTCHA)这种它过不了的,它停下来喊你。
那它具体能干哪些活?官方列了一串,我挑出小白最有体感的几类,配上「你真实会怎么用」:
- 实时调试:直接读浏览器控制台的报错和页面 DOM 状态,然后回头就把导致报错的代码改了——这是它和 MCP 最不一样的地方,能「看见」浏览器里发生了啥。
- 设计验证:照 Figma 稿写完 UI,打开浏览器比一比对不对得上(衔接第 17 篇讲的还原设计稿)。
- 网页应用测试:测表单校验、查视觉有没有变形、验用户流程走不走得通。
- 操作已登录的应用:直接在 Gmail、Notion、Google Docs 里写东西、改东西,不用 API 连接器。
- 扒数据:把页面上的列表(名称、价格、库存)抽成结构化数据,存成本地 CSV。
- 录 GIF:把一段浏览器操作录成 GIF,用来记录或者分享「这事儿是怎么发生的」。
举个我自己印象最深的场景:有回调一个前端的诡异 bug,页面加载时控制台报一个 undefined,我对着代码看了快半小时也没看出哪错了。接上 Chrome 后我就甩了句「打开 dashboard 页,把加载时控制台里的报错念给我听,再定位是哪段代码」——它读完报错、顺着调用栈找到了一个没做空值判断的地方,前后不到两分钟。换以前我得自己开 F12、复制报错、再贴回终端描述一遍,光来回倒腾就比这久。
💡 一句话总结:Chrome 集成让 Claude 借用你那台登录好一切的浏览器开网页、读控制台、填表单、扒数据——「改代码」和「在浏览器里验」第一次能在同一个对话里完整跑通。
02 它和 MCP、computer use 各管哪一块
接之前先把一个容易混的事捋清:Claude 操作「外部世界」有好几条路,Chrome 集成只是其中一条。三条路别搞混了,不然你会纠结「这事该用哪个」。
官方在 computer use 那页讲了一个优先级顺序——Claude 干外部的活,会从最精准的工具往最笨重的工具试:
如果您有该服务的 MCP server,Claude 会使用它。如果任务是 shell 命令,Claude 会使用 Bash。如果任务是浏览器工作且您已设置 Claude in Chrome,Claude 会使用它。如果以上都不适用,Claude 会使用 computer use。
类比:能打电话办的事就别专门跑一趟。 同一件事,能发个消息说清的就发消息(最快),发消息说不清就打个电话(慢一点),电话也办不了才亲自上门跑一趟(最慢最费事)。Claude 也是这个排序——先试最省事的,最省事的够不着才升级到更重的手段。
三条路对照着看,你就知道各自的主场:
| 手段 | 干什么 | 什么时候轮到它 | 本篇是它吗 |
|---|---|---|---|
| MCP(详见第 22 篇) | 连数据库、Jira、Slack 这些有接口的服务 | 服务有现成 MCP server,最精准,优先用 | 否 |
| Chrome 集成 | 操作浏览器里的网页:点、填、读控制台、扒数据 | 活儿是网页操作、又装了 Chrome 集成 | 是 |
| computer use | 控制本机原生 app:点 macOS 应用、看屏幕、截图 | 上面都够不着(原生应用、模拟器、没 API 的工具) | 否,见下方 |
computer use(让 Claude 用你的电脑) 是兄弟篇,这里顺带提一句让你有个数。它比 Chrome 集成更「广」也更「慢」——Chrome 集成只能碰浏览器,computer use 能控制整个 macOS 桌面:打开原生 app、点任意按钮、截你的屏。官方原话:
屏幕控制保留用于其他工具无法到达的事物:原生应用、模拟器和没有 API 的工具。
几个关键差别记住就行(都以官方文档为准):
- computer use 目前是研究预览版,只在 macOS 上的 CLI 可用(Windows 用桌面 app 那条线,见第 10 篇),要 Pro / Max 套餐,且不支持
-p非交互模式。 - 它在
/mcp菜单里以一个叫computer-use的内置 server 出现,默认关着,要手动启用。 - 它跑在你真实的桌面上,会请求 macOS 的「辅助功能」和「屏幕录制」权限。
一句话分工:有接口走 MCP,网页里的事走 Chrome,连原生桌面都得碰才上 computer use。这一篇专讲中间那条——Chrome。
💡 一句话总结:Claude 碰外部世界从精准到笨重三条路——MCP(有接口的服务)→ Chrome(浏览器网页)→ computer use(整个 macOS 桌面);本篇专讲 Chrome 这条,它的主场是浏览器里的操作。
03 怎么接上:装扩展、--chrome 启动
接 Chrome 集成,比接一个普通 MCP server 还简单——核心就两步:装个 Chrome 扩展,启动时带个 --chrome 标志。但有几个前置条件不满足就是接不上,先把门槛摆清楚。
先对四个前置条件
官方列了四条硬要求,差一条都连不上,挨个对一遍:
| 前置条件 | 具体要求 | 怎么查 |
|---|---|---|
| 浏览器 | Google Chrome 或 Microsoft Edge | 别的浏览器不行,见下方「不支持清单」 |
| Chrome 扩展 | 「Claude in Chrome」扩展 v1.0.36 或更高 | chrome://extensions 里看 |
| Claude Code 版本 | v2.0.73 或更高 | 终端跑 claude --version |
| 套餐 | 直接的 Anthropic 计划(Pro / Max / Team / Enterprise) | /status 看订阅 |
最后一条套餐最容易栽,单独强调一下。官方明确:
Chrome 集成不可通过 Amazon Bedrock、Google Cloud Vertex AI 或 Microsoft Foundry 等第三方提供商获得。如果您仅通过第三方提供商访问 Claude,则需要单独的 claude.ai 账户来使用此功能。
翻成人话:你要是走 Bedrock / Vertex / Foundry 这些第三方接入(第 05 篇讲过),或者只用 API key,这功能用不了——它只认直接的 Anthropic 订阅。这点和桌面 app、computer use 一个脾气,记住就行。
哪些浏览器 / 环境不支持
这张「不支持清单」我专门拎出来,因为踩了会很懵:
- 浏览器:目前只支持 Chrome 和 Edge。Brave、Arc、以及其他基于 Chromium 的浏览器都不支持——别看它们也是 Chromium 内核就想当然。
- 环境:不支持 WSL(Windows 子系统 Linux)。你在 WSL 里跑 Claude Code 想接 Windows 上的 Chrome,这条路目前不通。
Arc 这个坑我亲自踩过。我日常主力浏览器就是 Arc(同样 Chromium 内核),想当然以为装上扩展就能用,结果 /chrome 死活连不上,扩展也装了、版本也对,就是不通。折腾了二十来分钟才翻到文档里那行小字「尚不支持 Brave、Arc 或其他基于 Chromium 的浏览器」——白忙活。后来老老实实单独装了个 Chrome 专门给它用,才秒连上。
装扩展 + 启动
前置条件齐了,正式接:
第一步:装「Claude in Chrome」扩展。 去 Chrome 应用商店搜「Claude」装上(Edge 也是在 Chrome 应用商店装同一个)。
装扩展、访问 Chrome 应用商店在国内一般需要「魔法上网」;扩展本身要连 Anthropic,网络不通时也连不上。
第二步:带 --chrome 启动 Claude Code。 在终端:
claude --chrome
或者你已经在一个会话里了,直接敲 /chrome 启用,不用退出重开。
就这两步。 接上之后,任何时候敲 /chrome 都能:检查连接状态、管理权限、重新连接扩展、选用哪个已连接的浏览器。要是同时连了多个浏览器,浏览器操作一开始 Claude 会问你用哪个。
不想每次都打 --chrome?
嫌每个会话都加 --chrome 烦,可以设成默认:运行 /chrome,选「默认启用」。
但官方专门提醒了一句代价,值得你想清楚再开:
在 CLI 中默认启用 Chrome 会增加上下文使用,因为浏览器工具始终被加载。如果您注意到上下文消耗增加,请禁用此设置,仅在需要时使用
--chrome。
说白了:默认启用 = 浏览器那套工具每次会话都常驻,会吃掉一截上下文窗口(第 19 篇讲过工作台塞满会变蠢)。一般来说更稳的做法是不设默认,需要操作浏览器的会话才临时 --chrome——大多数纯改代码的活根本用不上浏览器,没必要让它一直占着地方。
顺带一提:如果你主力在 VS Code 扩展(第 08 篇)里干活,只要装了 Chrome 扩展,浏览器自动化就直接可用,不用加任何标志——这点比 CLI 省心。
网站权限从哪管
还有个细节:Claude 能浏览、点击、输入哪些网站,是从 Chrome 扩展那边继承的。官方:
网站级权限从 Chrome 扩展程序继承。在 Chrome 扩展程序设置中管理权限,以控制 Claude 可以浏览、点击和输入的网站。
也就是说,控制它能碰哪些站,去 Chrome 扩展的设置里调,不在 Claude Code 这边。这是它的第一道闸,下一节讲安全会再提。
💡 一句话总结:接 Chrome 就两步——装「Claude in Chrome」扩展 + 用
--chrome启动(或会话里/chrome);但先对齐四个前置(浏览器、扩展版本、CC 版本、Anthropic 订阅),且 Brave / Arc / 其他 Chromium、WSL 都不支持。
04 典型用例:六类活儿,照着抄
接上只是开始,会用才值钱。官方给了一串示例工作流,我按「你大概率会遇到」的顺序,把六类最实用的拎出来,每类给一条可以直接照着改的指令。这些指令都是用自然语言说的,你照着套自己的场景就行。
用例一:测本地网页应用
开发时改完一个功能,让它直接帮你在浏览器里验:
我刚改了登录表单的校验逻辑。打开 localhost:3000,
用一组无效数据提交表单,看看错误提示有没有正确出现。
它会导航到你的本地服务器、跟表单交互、把观察到的结果报给你。这大概是用得最多的一类——改完前端不用自己切浏览器手点,它替你跑一遍验证流程。
用例二:用控制台日志调试
让它读浏览器控制台帮你定位问题。这里有个官方给的诀窍:别让它「把所有控制台输出都给我」,日志太长会刷屏——告诉它你要找的模式:
打开 dashboard 页面,检查页面加载时控制台里有没有报错。
它会读控制台消息,按你说的模式或错误类型过滤,不会把一大堆无关日志全倒给你。
用例三:批量填表单
重复的数据录入最适合丢给它:
我有一个客户联系人表格在 contacts.csv 里。对每一行,
打开 crm.example.com 的 CRM,点「添加联系人」,
把姓名、邮箱、电话填进去。
它读你的本地文件、操作网页界面、一条条录进去。说句实话,这类「机械重复」的活儿是它最香的用武之地——你只要把数据准备好,剩下的它照着填。
用例四:直接在已登录的应用里写东西
这类最能体现「共享登录态」的爽:
根据最近的几个 commit 起草一份项目进展更新,
加到我那份 Google Doc(docs.google.com/document/d/abc123)里。
它打开文档、点进编辑器、把内容敲进去。Gmail、Notion、Sheets——凡是你已经登录的网页应用都吃这套,不用配任何 API。
用例五:从网页扒结构化数据
把页面上散着的信息抽成规整的数据:
打开商品列表页,把每件商品的名称、价格、库存状态抽出来,
存成一个 CSV 文件。
它导航到页面、读内容、编译成结构化格式存到本地。
用例六:录一段操作 GIF
想给同事演示「这功能怎么走」,让它录:
录一个 GIF,展示怎么走完整个结账流程,
从把商品加进购物车一直到确认页。
它把这段交互序列录下来、存成 GIF 文件。写文档、提 issue 配个动图,比打一堆字描述清楚多了。
把这六类对照「以前怎么干」摆一下,你就知道它省在哪:
| 场景 | ❌ 没有 Chrome 集成 | ✅ 有 Chrome 集成 |
|---|---|---|
| 验证前端改动 | 自己切浏览器手点、看效果、回来描述 | 一句话让它打开页面跑一遍报结果 |
| 调控制台报错 | F12 开控制台、复制报错、贴回终端 | 让它直接读控制台、过滤出报错 |
| 批量录数据 | 一条条手动复制粘贴进网页 | 喂个 CSV,它照着逐行填 |
| 在 Notion / Docs 写 | 自己整理好再粘进去 | 让它直接进文档写(共享登录态) |
提醒: /mcp 选 claude-in-chrome 能看到这些浏览器工具的完整列表,想知道它到底有哪些「手上的动作」,去那儿翻。官方还列了「多站点工作流」这类用例,这里略过,有兴趣可自行在 /mcp → claude-in-chrome 里探索。
💡 一句话总结:六类高频用例——测本地应用、读控制台调 bug、批量填表单、在已登录应用里写、扒页面数据、录演示 GIF,每类一句自然语言指令就能让它干,核心都是「省掉你手动切浏览器那一段」。
05 安全:操作「真浏览器」的风险在哪
这一节最不能跳过——因为它操作的是你真实的、登录着一切的浏览器,不是一个用完即焚的沙箱。这跟前面 Claude 在沙箱里跑命令(第 21 篇)是完全不同的信任边界。
风险到底在哪
回到「代驾」那个比方:代驾开的是你那台插着 ETC、放着停车卡的车。方便是真方便,但风险也实打实——他在你车里、用着你所有的卡。Chrome 集成同理:它共享你的登录态,意味着它能进的,是你登录着的所有网站——你的邮箱、你的公司后台、你的银行页面(只要你登录着)。
具体两类风险你得有数:
- 登录态等于钥匙串:它访问网站不需要再认证,你登录了什么,它就够得着什么。让它去某个页面操作时,心里要清楚这台浏览器上还登录着哪些敏感账号。
- 提示注入(prompt injection):这个第 21 篇专门讲过——网页内容里可能藏着「写给 AI 看」的恶意指令。它读一个页面时,页面上某段文字可能在偷偷指挥它干别的。操作浏览器时这个风险格外真实,因为它读的全是外部的、你控制不了的网页内容。
官方给了哪些护栏
好在 Chrome 集成不是「敞开了让它乱来」,内置了几道闸:
- 遇到登录 / 验证码会停下喊你:碰到登录页或 CAPTCHA,它暂停、要你手动处理,不会替你瞎填、瞎点过。
- 操作实时可见:它在一个你看得见的 Chrome 窗口里干活,点哪填哪你全程盯得到,不对劲随时能掐。
- 网站权限可控:上一节说的,在 Chrome 扩展设置里限定它能碰哪些网站——这是你最该用起来的一道闸,把它能动的范围圈小。
你自己该守的几条
官方护栏之外,还有几条操作真浏览器的土规矩值得记下来:
| 场景 | 该怎么办 |
|---|---|
| 让它操作浏览器前 | 先想清楚这台 Chrome 上还登录着哪些敏感账号 |
| 涉及钱 / 不可逆操作(下单、转账、删数据) | ⚠️ 自己来,别交给它,或全程死盯每一步 |
| 给它操作的网站范围 | ✅ 在扩展设置里圈小,只放它确实需要的站 |
| 让它访问陌生 / 不可信网页 | ⚠️ 警惕提示注入,内容里的「指令」别让它照单全收 |
总原则就一条:它在浏览器里点的每一下都是「真的」——不像沙箱里跑错了删个容器重来,浏览器里点了「确认付款」就是真付了。所以越是不可逆、越是涉及钱的操作,越要自己把着方向盘,让它干那些「错了也好收拾」的活。
这跟前面所有篇章的安全主线是一根弦:便利和风险成正比。Chrome 集成把便利拉满了——直接用你登录态——那对应的,你得把「它能碰什么」这道闸也守紧。
💡 一句话总结:Chrome 集成操作的是你登录着一切的真浏览器,不是沙箱——风险在「登录态即钥匙」和「网页里的提示注入」;官方护栏有「遇登录 / 验证码停手、操作可见、网站权限可控」,你自己则要圈小网站范围、把不可逆和涉钱操作攥在自己手里。
06 动手:接上 Chrome,让它读一次页面
光看不练假把式。下面带你跑一个最小实战:接上 Chrome,让它打开一个网页、读点东西回来。全程不碰你的敏感账号,专门拿来验证「接通了没」。
前提:你得是 Pro / Max / Team / Enterprise 直接订阅(不是 Bedrock / Vertex / API key),装好 Chrome 或 Edge。装扩展、访问网页可能需要「魔法上网」。
第一步:装「Claude in Chrome」扩展
在 Chrome 应用商店搜「Claude」,装上官方扩展。装完去 chrome://extensions 确认它已启用、版本 ≥ 1.0.36。
✅ 自验:扩展列表里能看到「Claude」且是开启状态。
第二步:确认 Claude Code 版本够新
claude --version
预期:打印的版本号 ≥ 2.0.73。低了就先升级(npm update -g @anthropic-ai/claude-code 或按第 02 篇的方式更新),否则接不上。
第三步:带 --chrome 启动
claude --chrome
进去后敲 /chrome 看状态:
/chrome
预期:显示 Chrome 已连接、扩展状态正常。如果提示没检测到扩展,按官方排查:确认扩展已装并启用 → 确认 CC 是最新 → 确认 Chrome 在运行 → /chrome 选「重新连接扩展程序」。第一次启用时它会装一个本机消息传递配置,Chrome 要重启一次才读得到——头一回连不上,先重启 Chrome 再试。
第四步:让它打开页面读点东西
连上后,给它一条「只读、不碰敏感账号」的指令(官方文档站正好拿来练手):
打开 code.claude.com/docs,点一下搜索框,
输入「hooks」,把出现的结果告诉我。
预期:你会看见你那个 Chrome 弹出新标签页、自动导航过去、点搜索框、敲字——全程肉眼可见(这就是第 05 节说的「操作实时可见」)。然后它把搜到的结果列回终端。看到浏览器真的动起来、结果回来了 = 接通成功。
如果操作到一半浏览器没反应了,官方提示先查有没有弹出的对话框(alert / confirm)挡着页面——JavaScript 对话框会卡住浏览器事件;手动关掉再让它继续。长时间不动后断连,就
/chrome选「重新连接扩展程序」(扩展的后台 service worker 会进空闲状态)。
跑通这四步,你就把「装扩展 → 启动 → 验连接 → 让它操作页面」这条完整链路走了一遍。以后让它干任何浏览器的活,本质都是这套,无非把第四步换成你真实的任务。
💡 一句话总结:动手就四步——装扩展、
claude --chrome启动、/chrome验连接、给一条只读指令看浏览器真动起来;头回连不上多半是扩展没装好或 Chrome 没重启,按官方那串排查走一遍。
07 小结
这一篇给 Claude Code 接上了你天天在用的那个浏览器——从「只会摸文件和命令行」,到能开网页、读控制台、填表单、扒数据,「改代码」和「在浏览器里验」这两件事终于能在一个对话里从头到尾跑完。
把核心串起来回顾:
| 你要做的事 | 关键点 |
|---|---|
| 理解它是什么 | 借用你登录好一切的真 Chrome,开新标签页操作,实时可见 |
| 分清它和别的工具 | MCP(有接口)→ Chrome(网页)→ computer use(整个桌面) 三条路,从精准到笨重 |
| 接上它 | 装「Claude in Chrome」扩展 + --chrome 启动;对齐扩展 / CC 版本、要 Anthropic 直接订阅 |
| 知道哪不支持 | Brave / Arc / 其他 Chromium、WSL 都不行,只支持 Chrome / Edge |
| 会用 | 测本地应用、读控制台、批量填表单、在已登录应用写、扒数据、录 GIF |
| 守住安全 | 操作的是真浏览器(非沙箱):圈小网站权限、不可逆和涉钱操作自己来、警惕提示注入 |
你现在应该能: 讲清 Chrome 集成是什么、它和 MCP / computer use 各管哪一块,独立把它接上(装扩展 + --chrome),用自然语言指令让它干六类常见的浏览器活儿,并且清楚操作真浏览器的风险在哪、该守哪几条闸。这一接,Claude Code 从「本地代码助手」又往前迈了一步——能直接替你操作那个你最常打交道的窗口了。
下一篇 41「并行任务」——这一篇让一个 Claude 能操作浏览器了,但活儿一多,你会发现一个会话串着干还是慢:它开浏览器测着 A 功能,你 B、C 两个需求只能干等着。下一篇换个思路:怎么让多个任务真正并行铺开、各干各的、互不打扰。想想看:如果改前端、跑测试、扒数据这三件事能同时进行,而不是排队等一个 Claude 来回切,是不是又能省下一大段时间?
41 · 并行任务:让几个 Claude 同时开工,而不是排队
说出来有点丢人,但我自己第一次想「并行干活」时,干的就是这么一件蠢事:开了两个终端,都 cd 到同一个项目目录,一个让 Claude 改前端登录页,另一个让它顺手修一个后端的 bug。
心里还美滋滋地想:「这不双倍效率嘛。」
结果呢——两边都在改 package.json,一边刚写进去的依赖,被另一边的改动直接覆盖回滚了;git status 一看,工作区乱成一锅粥,谁改的哪行根本分不清。我那天花了比「老老实实一件件干」多得多的时间,才把两边的改动手动捋开,越捋越火大。就是那回我才明白:并行不是「多开几个窗口」这么简单,核心是「别让它们踩到同一块地」。
其实 Claude Code 早就备好了正经的并行工具——--worktree 给每个会话一份隔离的代码副本,--bg 把任务甩到后台批量跑,claude agents 给你一块总控台盯着它们。这一篇,咱们把上面那个坑连根填平,再带你把这几套手段亲手跑一遍。
看完这一篇,你会拿到:
- 一句话讲清「为什么要并行」,以及并行的两个前提:任务互相独立、不抢同一份文件
- 官方四种并行方式(子代理 / 代理视图 / 代理团队 / 动态工作流)一张表分清,知道该挑哪个
- 用
--worktree给每个会话一份隔离副本,再不互相覆盖——附.worktreeinclude、清理这些坑点 - 用
claude agents和--bg把任务甩到后台、一块屏幕盯进度,只在需要时介入 - 用
claude -p(无头模式,headless)把任务写进脚本批量跑,配--bare启动更快 - 那条最重要的判断线:什么时候值得并行、什么时候反而把自己绕进去
01 先想清楚:并行到底解决什么问题,前提是什么
先给结论:并行解决的是「几件互不相干的活,不想排队一件件等」;但它能成立,全靠一个前提——这几件活别抢同一份文件。
回想前面四十篇,咱们基本都在「一个会话」里折腾——开一个 Claude,给指令,它一步步干。这模式九成的活儿够用。但有两种时候你会嫌它慢。
一是任务天然就能拆开、互不依赖。 比如「改前端样式」「修后端一个 bug」「补一批单元测试」,三件事八竿子打不着,却只能排队:改完前端才轮到后端。明明能同时干,却被逼着串行。
二是任务大到一个会话扛不动。 比如「把整个代码库里某个旧 API 全换成新的」,涉及几十上百个文件,一个会话从头改到尾,上下文(context,可理解成它的「工作记忆」,详见第 19 篇)早塞满了,越往后越「忘事」。
类比:超市结账。 一条收银通道,十个人拎着购物车排长龙,第十个人得干等前面九个全结完——这就是串行。聪明的超市会多开几个收银口,十个人分到三四条队里同时结,总时间立刻砍下来。并行干活就是「多开收银口」:几件独立的活,分给几个 Claude 同时结账,而不是挤在一条队里。
但收银口能多开有个隐含前提:每条队是独立的,互不干扰。要是三个收银员共用同一个钱箱、同时往里塞钱找零,立刻乱套——这正是开头那个坑。所以并行的铁律就一条:
任务接触相同的文件吗?使用 worktrees 隔离工作。
落到你会遇到的真实场景,能并行的活儿长这样:
- 「这三个互不相干的模块,各修各的 bug」——分三个会话同时修,互不打扰
- 「把
utils/整个目录里没人用的死代码扫出来」——派个子代理去翻,主对话不被一堆文件灌满(详见第 23 篇) - 「同一份脚本,对 30 个文件各跑一遍同样的改动」——写成 headless 批量任务,机器自己跑完
💡 一句话总结:并行是为了让互相独立的活儿不用排队(像超市多开收银口),但它成立的铁律只有一条——别让它们抢同一份文件,否则越并行越乱。
02 官方四种并行方式:先认门,别一上来就挑花眼
Claude Code 的并行不止一招。官方专门有一页《并行运行代理》把它们摆在一起比,核心区别就一个问题:谁来协调这些活儿? 是 Claude 在一个对话里派活收活,是你甩出去回头再看,还是 Claude 当工头统筹一队。
先把四种方式一张表认清,这一节是地图,下面几节才是逐个深挖:
| 方式 | 它是什么 | 谁协调 | 什么时候用 |
|---|---|---|---|
| 子代理(Subagent) | 一个会话内派出去的工作者,在自己上下文里干完返回摘要 | Claude 在对话里派活收活 | 辅助任务会用一堆搜索结果 / 日志把主对话灌满,而你不会再翻这些过程 |
| 代理视图(Agent view) | 一块屏幕,调度并监控多个后台会话,claude agents 打开(研究预览) | 你甩出任务、回头检查 | 你有几个独立任务,想交出去、一眼扫状态、只在需要时介入 |
| 代理团队(Agent teams) | 多个会话协调干活,共享任务列表、互发消息,有个 leader 统筹(实验性,默认关) | Claude 当工头统筹一队 | 你想让 Claude 把项目拆成几块、分派、还让工人们保持同步(详见第 29 篇) |
| 动态工作流(Workflows) | 一段脚本,跑一大批子代理并交叉验证结果(研究预览) | 脚本而非 Claude 逐轮判断 | 活儿大到几个子代理协调不过来,或要结果互相验证:全库审计、500 个文件迁移 |
⚠️ 实验性标注:上表里代理视图(agent view)和动态工作流(workflows)是研究预览版、代理团队(agent teams)是实验性默认关闭——界面、快捷键、行为后续都可能变。照做前先
claude --version对一下版本。子代理则是稳定功能。
这表你不用背,记住一句就行:「谁协调」是分水岭——Claude 在对话里顺手派 → 子代理;你撒手甩后台 → 代理视图;Claude 当工头带队 → 代理团队;脚本死板地批量跑 → 动态工作流。
还有两个东西它们本身不是「并行方式」,而是给并行打配合的工具,这一篇重点讲前一个:
- Worktrees:给每个会话一份单独的 git 副本,让并行会话永远不会改到同一份文件。这是开头那个坑的正解,第 03 节专讲。
/batch:一个 skill,让 Claude 把一个大改动拆成 5 到 30 个 worktree 隔离的子代理,每个开一个 PR。它是「子代理 + worktree」的打包用法,不是单独一种协调风格。
子代理(第 23 篇)和代理团队(第 29 篇)前面都专门讲透了,这一篇不重复——本篇聚焦那块还没碰过的:worktree 隔离、后台多会话、headless 批量。
💡 一句话总结:并行有四种正经方式,「谁协调」是区分关键;worktree 和
/batch是给并行打配合的工具,不算单独方式;本篇专攻前面没讲过的 worktree、后台会话、headless 三块。
03 用 worktree 隔离:给每个会话一份「自己的副本」
这一节是开头那个坑的正解,也是整篇最该吃透的一块。
先说那个坑到底坑在哪:两个会话 cd 进同一个目录,等于俩人在同一张图纸上同时涂改,后写的盖住先写的,天经地义会乱。git worktree(工作树,git 的一项原生能力)就是来根治这个的。
类比:把同一张图纸复印几份,几个人各改各的副本。 设计图只有一张原稿,三个人要同时在上面标注,挤在一张纸上必然涂乱。正确做法是复印三份——每人拿一份副本随便改,改完再合并。git worktree 干的就是这事:它从同一个仓库历史里,给你拉出几个独立的工作目录,各有各的文件和分支,但共享同一套提交历史和远程。一个会话在它的副本里怎么改,都碰不到另一个会话的副本。
官方把这个值钱的点讲得很清楚:
在自己的 worktree 中运行每个 Claude Code 会话意味着一个会话中的编辑永远不会触及另一个会话中的文件,因此您可以让 Claude 在一个终端中构建功能,同时在第二个终端中修复错误。
一行命令开一个隔离会话
最省事的用法:启动时加 --worktree(或简写 -w),后面跟个名字。Claude 会自动创建一个隔离的 worktree 并在里头开工。默认这个 worktree 放在你仓库根目录下的 .claude/worktrees/<名字>/,分支名叫 worktree-<名字>:
claude --worktree feature-auth
想再开第二个独立会话?另一个终端、换个名字,跑同样的命令:
claude --worktree bugfix-123
这下两个会话各在自己的副本里,一个搭功能、一个修 bug,谁也碰不到谁的文件——开头那个「互相覆盖」的惨剧从根上没了。名字懒得起?省略它,Claude 自动生成一个像 bright-running-fox 这样的:
claude --worktree
会话里也能临时让它进 worktree——直接说一句「在 worktree 中工作」,它会用 EnterWorktree 工具给你建一个。
第一次在某个目录用
--worktree之前,得先在该目录里跑一次普通的claude,接受那个工作区信任对话框。没接受过信任,--worktree会直接报错让你先去跑一次claude——连-p模式也一样。
三个新手必踩的坑点
坑点一:.claude/worktrees/ 要进 .gitignore。 不然这些 worktree 的内容会在你主目录里显示成一堆「未跟踪文件」,看着碜得慌。官方专门提醒了这条。
坑点二:worktree 是干净的新副本,你的 .env 不在里面。 worktree 是个全新检出,主仓库里那些没被 git 跟踪的文件(像 .env、.env.local)默认不会跟过去——结果新会话一跑就缺环境变量。解法是在项目根放一个 .worktreeinclude 文件,列出要自动复制进每个 worktree 的本地文件,语法和 .gitignore 一样:
.env
.env.local
config/secrets.json
这个坑我亲自栽过:兴冲冲 -w 开了个会话准备改后端,结果 Claude 跑起来一直报连不上数据库,我对着报错排查了半天,甚至怀疑是数据库挂了——最后才反应过来,.env 压根没复制进 worktree,连接串它根本读不到。后来在每个项目根都顺手放上 .worktreeinclude,就再没犯过这毛病。
坑点三:退出时记得「保留还是删除」。 官方的清理规则很实在:
- 没改任何东西(无未提交改动、无未跟踪文件、无新提交):worktree 和它的分支会自动删除;但如果会话事先命了名(
--name),Claude 会弹提示让你决定保留还是删除。 - 改了东西:Claude 会问你「保留还是删除」——保留就留着目录和分支,以后能回来接着干;删除就连同未提交的改动一起丢掉。
- 非交互(
-p)跑出来的 worktree 不自动清理,因为没有退出提示,得自己git worktree remove删。
不想让 Claude 自动建,也能手动来
要完全掌控 worktree 放哪、用哪个分支,直接用 git 自己建也行(git 工作流第 43 篇会专门讲):
# 在新分支上建一个 worktree
git worktree add ../project-feature-a -b feature-a
# 进去启动 Claude
cd ../project-feature-a && claude
# 列出所有 worktree
git worktree list
# 干完删掉
git worktree remove ../project-feature-a
官方提醒一句很容易忘的:每个新 worktree 都是独立检出,记得在里头重新装依赖、配虚拟环境——别指望它继承主目录装好的 node_modules。
💡 一句话总结:worktree 给每个会话一份独立的代码副本(像复印图纸各改各的),
claude --worktree <名字>一行开一个隔离会话;记牢三坑——.claude/worktrees/进.gitignore、.env靠.worktreeinclude复制、退出时选「保留 / 删除」。
04 多会话并行:后台甩任务 + 一块总控台盯着
worktree 解决了「文件不打架」,但还有个问题:开了三五个会话,难道得开三五个终端来回切、一个个盯? 太累了。这就轮到「代理视图(agent view)」上场。
类比:机场塔台的航班动态板。 塔台不会派一个人盯一架飞机——一块大屏上,所有航班的状态一目了然:哪架在滑行、哪架等指令、哪架已落地。调度员平时扫一眼总览,只在某架要他拍板时才接管对讲。claude agents 给你的就是这么块塔台屏:所有后台会话排成行,状态一眼扫清,谁需要你才介入。
⚠️ 研究预览:agent view 是官方标注的研究预览功能,需要较新版本的 Claude Code,界面和快捷键后续可能变。先
claude --version对一下版本。
把任务甩到后台
后台会话的精髓是:它不绑在你的终端上——你关掉这块屏、关掉 shell、甚至另开一个交互会话,它照样在跑。有几种甩法。
第一种,从 shell 直接甩,加 --bg:
claude --bg "调查一下 SettingsChangeDetector 这个不稳定的测试为啥老挂"
甩出去后,Claude 会打印这个会话的短 ID 和管理它的命令,大概长这样:
backgrounded · 7c5dcf5d
claude agents list sessions
claude attach 7c5dcf5d open in this terminal
claude logs 7c5dcf5d show recent output
claude stop 7c5dcf5d stop this session
第二种,从正在聊的会话里甩:敲 /bg(/background 的简写),把当前对话挪到后台。
用 claude agents 这块塔台屏管它们
打开总控台:
claude agents
它会占满整个终端,把所有后台会话按状态分组列出来——「需要输入」「正在工作」「已完成」各归一拨。每行开头一个图标,颜色和动画告诉你这个会话啥状态:
| 状态 | 图标 | 含义 |
|---|---|---|
| 工作中 | 动画闪动 | 正在跑工具或生成回复 |
| 需要输入 | 黄色 | 在等你回答或批权限 |
| 已完成 | 绿色 | 任务成功干完 |
| 失败 | 红色 | 出错结束了 |
塔台屏的核心操作就三个,新手记住这仨足够:
Space(窥视):选中一行按空格,弹出小面板看它最近的输出、或它正卡在哪个问题上——多数时候不用进完整对话,瞄一眼就够。- 回复:在窥视面板里直接打字回它,按
Enter发出去,不用离开总控台。 Enter/→(附加):想钻进某个会话好好聊,按回车「附加」进去,它就变成一个完整的交互会话;在空输入框按←又退回总控台。
这里有个藏得很深但极关键的细节,正好把上一节的 worktree 串起来:每个后台会话在改文件前,Claude 会自动把它挪进 .claude/worktrees/ 下的隔离 worktree。也就是说——你用代理视图并行甩任务,文件隔离是自动帮你做好的,不用像第 03 节那样手动 -w。官方文档确认:代理视图在分派每个会话时,会自动为它创建独立的 worktree。
举个常见的并行组合:同时甩出三个后台会话——一个修 flaky 测试、一个审一个 PR、一个补文档。你该干嘛干嘛,每隔一阵 claude agents 扫一眼——谁变绿了去验收,谁标黄了去拍板。比开三个终端来回切省心太多了。
⚠️ 一个会消耗你额度的事实:后台会话和交互会话一样吃你的订阅用量。并行跑十个,额度消耗速度大约是跑一个的十倍。别看后台跑得欢就无脑开一堆。
💡 一句话总结:
--bg把任务甩到后台、/bg把当前会话甩后台,claude agents给你一块塔台屏(像机场航班板)——Space窥视、直接回复、Enter附加;后台会话的文件隔离是自动用 worktree 做好的,但并行越多越费额度。
05 Headless 批量:写进脚本里,让它无人值守地跑
前面两套是「你坐在终端前盯着」。但有一类活儿你压根不想盯——同一个套路,对一批东西各跑一遍;或者把 Claude 塞进 CI、塞进脚本,让它像个命令行工具一样被自动调用。这就是无头模式(headless,即不开交互界面、跑完就退出的运行方式)。
类比:把指令写成纸条投进自助机,跑完吐结果。 你不会守着自动售货机看它出货——投币、按键、东西掉出来,全程不用你盯。headless 就是这种「无人值守」:你把提示和参数一次性写清,塞给 claude -p,它跑完把结果吐出来,你拿去用就行。
核心就一个标志:-p(或 --print)。加上它,claude 就非交互地跑一次然后退出:
claude -p "找出 auth.py 里的 bug 并修掉" --allowedTools "Read,Edit,Bash"
这里 --allowedTools 是预先批准它能用哪些工具——因为没人在旁边点「同意」,你得提前告诉它「这几样工具随便用,别停下来问」(权限模式详见第 20、35 篇)。
三个让它真正好用的配套
配套一:管道喂数据。 headless 会读标准输入(stdin),所以你能像用任何命令行工具一样,把数据用管道喂进去。比如把构建报错丢给它解释,结果写进文件:
cat build-error.txt | claude -p "简明扼要说清这个构建错误的根因" > output.txt
排查构建挂掉时,就这么一行甩过去——比复制报错粘进会话快多了。
配套二:--bare 让启动更快。 默认 claude -p 会加载和交互会话一样的全套上下文(hooks、skills、plugins、MCP、CLAUDE.md 全读一遍),脚本里跑就嫌慢、还可能被队友 ~/.claude 里的配置干扰。加 --bare 跳过这些自动发现,启动快、结果还在每台机器上一致:
claude --bare -p "总结这个文件" --allowedTools "Read"
官方明确说了:
--bare是脚本和 SDK 调用的推荐模式,将在未来版本中成为-p的默认值。
配套三:--output-format json 拿结构化结果。 脚本要解析 Claude 的输出,纯文本不好处理。加 --output-format json,它会返回带元数据的结构化 JSON(结果、会话 ID,还有 total_cost_usd 这次花了多少钱),配 jq 一提取就能用:
claude -p "总结这个项目" --output-format json | jq -r '.result'
把 headless 拼成「批量」
单条 -p 还不算批量。真正的批量是拿 shell 循环把它套起来——对一批文件各跑一遍同样的活。比如给某个目录下每个 .py 文件都生成一句话说明:
for f in src/*.py; do
claude --bare -p "用一句话说明 $f 是干什么的" --allowedTools "Read"
done
这就是「无人值守批量」的雏形:循环、-p、--bare,三件套。当然,如果这批活儿大到几十上百个文件、还想互相验证结果,那就该上第 02 节提的动态工作流或 /batch 了——它们本质就是把这种批量正经工程化。
⚠️ 一个要留意的计费变化:官方文档注明,从 2026 年 6 月 15 日起,订阅套餐下的 Agent SDK 和
claude -p用量会从一份独立的月度 Agent SDK 额度里扣,跟你的交互用量分开算。脚本批量跑之前,心里有个数(计费细节见第 06 篇)。
💡 一句话总结:headless 用
claude -p非交互跑一次就退出(像投自助机不用盯),配--allowedTools预批工具、--bare加速、--output-format json拿结构化结果;拿 shellfor循环套起来就是「批量」雏形。
06 最关键的一节:什么时候别并行
讲了三套并行手段,但这一节比前面都重要——因为太多人一学会并行就上头,啥都想拆,结果越并行越乱、越并行越贵。
先把判断线立起来。值得并行,得同时满足两条:任务互相独立(A 不依赖 B 的结果)、不抢同一份文件(或者用 worktree 隔开了)。少一条,并行就是给自己挖坑。
并排看一眼,什么该并行、什么老实串行:
| 场景 | 该不该并行 | 为什么 |
|---|---|---|
| 三个互不相干的模块各修各的 bug | ✅ 并行 | 独立、不抢文件,典型该并行 |
| 同一套改动批量跑 30 个文件 | ✅ 并行(headless / /batch) | 互不依赖,机器代跑最省事 |
| 「先重构 A,再基于新 A 改 B」 | ❌ 串行 | B 依赖 A 的结果,并行只会拿到旧 A |
两个会话都要改 package.json | ❌ 串行(或务必 worktree 隔离) | 抢同一份文件,正是开头那个坑 |
| 一个小改动,五分钟能干完 | ❌ 串行 | 拆开的协调成本比省下的时间还多 |
| 任务之间要频繁互通中间结果 | ⚠️ 看情况 | 沟通成本高,不如一个会话顺着干 |
下面三条土规矩,是踩出来的经验,送给你。
第一,有先后依赖的活儿,死活别并行。 「重构完核心模块,再让其他模块适配新接口」这种,后一步就得等前一步——硬并行,后面那个会照着旧版本改,跑完发现全得返工。这么干一次,就白白浪费两个会话的额度。
第二,小活儿别拆。 五分钟能改完的东西,你光是「想清楚怎么拆、开几个会话、回头怎么合并」就不止五分钟。拆活儿本身有成本,小活儿拆了纯亏。
第三,并行越多越烧额度。 第 04 节那条得再强调一遍:并行十个会话,额度大约按十倍速度烧。一个稳妥的习惯是——手动并行控制在三五个以内,真要大批量(几十上百)就交给 /batch 或动态工作流去工程化,而不是手动开一屏会话。
说白了,并行是把双刃剑:对的场景上它,效率翻几倍;错的场景上它,比串行还慢还贵还乱。判断「该不该并行」,永远比「怎么并行」更值钱。
💡 一句话总结:值得并行的铁律是 「独立 + 不抢文件」,少一条就别拆;有先后依赖的活儿、五分钟的小活儿别并行;并行越多越烧额度,控制在三五个以内,大批量交给
/batch。
07 动手:亲手跑一遍 worktree 隔离 + 后台甩任务
光看不练假把式。下面这套全程基于一个 git 仓库,没仓库的先随便建一个练手。命令真实可跑,每步都给了预期输出,你照着走一遍,这几套手段就有肌肉记忆了。
用到 git 仓库;后台会话部分需要较新版本的 Claude Code(agent view 是研究预览),先
claude --version看一眼。下面命令不依赖魔法上网。
第一步:进一个 git 项目,先接受信任对话框
cd 你的某个git项目
claude
进去后随便问一句(比如「这个项目是干嘛的」)再退出。这一步是为了接受工作区信任——没接受过,下一步 --worktree 会直接报错。
第二步:用 --worktree 开一个隔离会话
claude --worktree test-parallel
预期:Claude 在 .claude/worktrees/test-parallel/ 下建好一个隔离 worktree 并在里头启动。你在这个会话里改任何文件,都只动这份副本,主目录纹丝不动。退出时如果改过东西,它会问你「保留还是删除」——练手就选删除。
第三步:确认 worktree 真建出来了(另开一个终端,回到主项目目录)
git worktree list
预期:列表里除了主检出,多出一行指向 .../.claude/worktrees/test-parallel,带自己的分支。看到这行 = 隔离副本确实建好了。
第四步:把一个任务甩到后台
claude --bg "列出这个项目所有 markdown 文件的标题"
预期:终端打印一行 backgrounded · <短ID>,后面跟着 claude attach / claude logs / claude stop 几条管理命令。看到这串 = 任务已甩进后台在跑,你的终端立刻就能干别的。
第五步:打开塔台屏盯它
claude agents
预期:整个终端被代理视图占满,刚甩的那个会话作为一行出现,旁边标着状态(工作中 / 已完成)。选中它按 Space 窥视输出,按 Esc 关面板,再按 Esc 退出代理视图。看到这块分组列表 = 你已经能用一块屏管多个后台会话了。
第六步:清理
# 停掉刚才那个后台会话(短ID 换成第四步打印的)
claude stop <短ID>
# 删掉练手的 worktree(在主项目目录)
git worktree remove .claude/worktrees/test-parallel
预期:claude stop 打印停止确认;git worktree remove 之后再跑一次 git worktree list,那行 test-parallel 已经没了。清干净 = 一条完整链路走通。
跑通这六步,你就把「开隔离会话 → 确认副本 → 甩后台 → 塔台盯 → 清理」这条并行主链亲手走了一遍。以后真要并行干活,本质都是这套,无非换任务、加几个会话。
💡 一句话总结:动手链路就六步——
claude(接受信任)→--worktree开隔离会话 →git worktree list确认 →--bg甩后台 →claude agents盯 →stop+git worktree remove清理;走通一遍比记十条命令都管用。
08 小结
这一篇把「让几个 Claude 同时开工」这件事,从「为什么并行」一路讲到「什么时候别并行」,中间塞了三套能上手的手段。
把核心要点串起来回顾:
| 你想干的事 | 用什么 | 关键点 |
|---|---|---|
| 搞清并行解决啥 | 「独立 + 不抢文件」两前提 | 像超市多开收银口,但每条队得独立 |
| 认清并行有哪几种 | 四种方式一张表 | 「谁协调」是分水岭;agent view / workflows 是研究预览,teams 实验性 |
| 让会话不互相覆盖文件 | --worktree / git worktree | 给每个会话一份独立副本,记牢 .gitignore、.worktreeinclude、清理三坑 |
| 后台甩任务、一屏盯进度 | --bg + claude agents | 后台会话不绑终端,文件隔离自动用 worktree;Space 窥视、Enter 附加 |
| 把任务写进脚本批量跑 | claude -p(headless) | 配 --allowedTools 预批、--bare 加速、--output-format json 拿结构化结果 |
| 判断该不该并行 | 「独立 + 不抢文件」铁律 | 有依赖、小活儿别拆;并行越多越烧额度,控制在三五个内 |
你现在应该能: 看明白并行到底解决什么、铁律是「独立且不抢文件」;分清官方四种并行方式该挑哪个;用 --worktree 给会话开隔离副本,再不重蹈开头那个「互相覆盖」的覆辙;用 --bg 和 claude agents 把任务甩后台、一屏盯着;用 claude -p 把活儿写进脚本批量跑;最重要的是——拿到一个任务,先冷静判断「这玩意儿值不值得并行」,而不是一上头就拆。
回头看开头那个「俩终端同改一个目录」的蠢事,根子就是不懂隔离、也没想清依赖。现在你手里有 worktree 这把隔离的钥匙、也有那条判断线,能比一头扎进去的人少走一大圈弯路。
下一篇 42「环境变量」——这一篇里你已经撞见好几个环境变量了:--bare 背后那个 CLAUDE_CODE_SIMPLE、关掉后台任务的 CLAUDE_CODE_DISABLE_BACKGROUND_TASKS、改配置目录的 CLAUDE_CONFIG_DIR……它们像一排藏在背后的「拨动开关」,不显眼,却能悄悄改掉 Claude Code 的行为。下一篇就把这排开关一个个翻出来,告诉你哪个管什么、哪个值得你动。想想看:同样一条命令,在你机器上和在 CI 里跑出来的行为可能不一样——差别往往就藏在这几个环境变量里。
42 · 环境变量:藏在背后那排「总开关」
都说环境变量是「高阶玩家才碰的东西」,说句实话——这话害了不少人。
太多人连模型、配代理、调超时,全靠每次开会话手动 /model 点一遍、手动改一遍,改完下次开新会话又得重来。问起为啥不一次配死,答案多半是「环境变量听着好硬核,怕搞坏」。
可你回头看看前面四十一篇——第 04 篇配 API key、第 05 篇接国产模型、第 19 篇管上下文、第 21 篇关遥测……这些事的底层,几乎全是同一套机制在兜底:环境变量。 你早就在用了,只是没人把它们摊开摆在一起讲。
这么说吧:环境变量不是「高阶才碰」,而是 「一次拨好、终身受益」的那排总开关。怕它,纯粹是因为没人告诉你哪几个开关常用、拨错了顶多什么后果。今天就把这层窗户纸捅破。
看完这一篇,你会拿到:
- 一句话讲明白环境变量在 Claude Code 里到底管什么、为什么值得花十分钟搞懂
- 三种设置方式(shell 临时 / shell 配置文件持久 /
settings.json的env字段)分别什么时候用,一张表说清 settings.json那四类文件各管多大范围、哪个进 git 哪个不进——直接接上第 31 篇- 一份「最该认识的环境变量」清单:连接、超时、隐私、配置目录,带默认值和踩坑提示
- 当同一件事既能用环境变量又能用设置字段时,到底谁说了算(优先级规则)
- 一个能照着跑、给了预期输出的实战:亲手设一个变量并验证它真的生效了
01 先搞懂:环境变量在 Claude Code 里到底管什么
先给结论:环境变量是 Claude Code 启动时读的一组「键值对开关」,用来定它怎么连模型、怎么认证、超时多久、要不要上报数据这些底层行为。
你前面用的那些功能——/model 换模型、claude mcp add 接服务、/config 调设置——大多是「会话里临时拨一下」。但有些行为,你希望每次启动都按你的来,不用每回手动设:比如「我永远走自建代理的地址」「我所有请求超时都给我放宽到 20 分钟」「我这台机器绝不上报任何遥测」。这些「定下来就别变」的底层规矩,就是环境变量管的。
官方一句话给它定了性:
环境变量可以控制 Claude Code 的行为,例如模型选择、身份验证、请求路由和功能切换。
类比:咖啡机上的预设按钮。 一台带预设的咖啡机,你可以每次现调——水量多少、浓度几档、要不要加奶,按一杯调一次;也可以把常喝的那杯存成「我的预设」,以后一键出杯,机器自己记着参数。 环境变量就是后者:它把那些你「每次都想这么来」的设置固化下来,Claude Code 一启动就照着读,省得你回回手动拨。
落到真实场景,你大概率会在这几种时候想起它:
- 「我接了 DeepSeek,不想每次都手动指模型」——把模型和地址写进环境变量(第 05 篇那套,底层就是它)
- 「公司网络慢,默认 10 分钟超时老不够」——一个变量把超时放宽
- 「这台是公司机器,合规要求一律不上报遥测」——一个变量直接关掉(第 21 篇提过)
- 「我有工作和个人两个账号,想分开互不干扰」——一个变量切换配置目录
看出来没?这些全是「设一次,长期生效」的需求。 环境变量就是为这类需求生的。
💡 一句话总结:环境变量是 Claude Code 启动时读的一组「键值对总开关」,管连接、认证、超时、隐私这些底层行为;它的价值在于把「每次都想这么来」的设置一次固化,不用回回手动拨。
02 在哪设:三种方式,从「就这一次」到「永远生效」
知道了它管什么,接下来最实在的问题——到底在哪儿设? 答案是三个地方,差别就一条线:这次设的,影响多久、影响谁。
官方把这条线讲得很干脆:
在 shell 中设置的变量仅在该终端会话期间有效,而在设置文件中的变量在每次运行
claude时都适用。
我把三种方式按「生效范围从窄到宽」排开,你对着选:
方式一:shell 里临时设(就管这一个终端)
在启动 claude 之前,在终端里 export 一下。只对当前这个终端窗口有效,关掉就没了。
macOS / Linux / WSL:
export API_TIMEOUT_MS="1200000"
claude
Windows PowerShell:
$env:API_TIMEOUT_MS = "1200000"
claude
这种适合 「我就想这一次试试」——临时放宽个超时、临时换个地址,跑完关掉终端,啥也没留下。
方式二:写进 shell 配置文件(这台机器每次都生效)
如果你想每开一个终端都自动带上,把那行 export 加进你的 shell 配置文件。Mac 上默认是 ~/.zshrc,很多 Linux 是 ~/.bashrc:
# 加到 ~/.zshrc 末尾
export API_TIMEOUT_MS="1200000"
存盘后开新终端(或 source ~/.zshrc)就生效。这是「我这台机器上,所有项目、所有终端都这么来」的做法。
Windows 上要持久化,用
setx API_TIMEOUT_MS "1200000"(CMD)或[Environment]::SetEnvironmentVariable("API_TIMEOUT_MS", "1200000", "User")(PowerShell),然后开一个新终端才生效。
方式三:写进 settings.json 的 env 字段(跟着配置走,跟启动方式无关)
第三种,也是最常用的——写进 settings.json 里的 env 键。官方说得很清楚它的好处:
Claude Code 在启动时直接从文件读取它们,因此无论如何启动
claude,它们都会生效。
{
"env": {
"API_TIMEOUT_MS": "1200000",
"BASH_DEFAULT_TIMEOUT_MS": "300000"
}
}
这个文件路径和写法,第 31 篇讲
settings.json时已经铺过底了。这里你只要记住:env是它专门留给环境变量的那个口子,把变量写这儿,跟你怎么敲claude无关,它都读得到。
三种方式并排一看就清楚该怎么选:
| 设置方式 | 生效范围 | 关掉终端还在吗 | 最适合 |
|---|---|---|---|
shell 临时 export | 仅当前终端 | ❌ 没了 | 「就想这一次试试」 |
写进 ~/.zshrc 等 | 这台机器所有终端 | ✅ 在 | 「我个人机器全局这么来」 |
写进 settings.json 的 env | 跟着该配置文件作用范围走 | ✅ 在 | 「跟项目/团队绑定,谁启动都生效」 |
一个顺手的习惯:临时验证一个变量管不管用,用 shell export 试;确认要长期用,就挪进 settings.json 的 env。 为啥偏爱 settings.json 而不是 ~/.zshrc?因为下一节那张「文件分级」表——settings.json 能让你精确控制「这个变量是只给我、还是全团队、还是只这个项目」,~/.zshrc 做不到这种区分。
💡 一句话总结:三种设置方式按生效范围排开——shell 临时
export(就这一次)、写进~/.zshrc(本机全局)、写进settings.json的env(跟配置走、跟启动方式无关);临时试探用第一种,长期生效推荐第三种。
03 settings.json 的四类文件:谁能管到、哪个进 git
上一节说 settings.json 的 env 是我最推荐的口子,但这里有个新手必踩的坑:settings.json 不止一个文件,它有四类,写进不同的文件,这个变量管的「人」完全不一样。
这事第 31 篇专门拆过,这里就环境变量的角度再钉一遍——因为放错文件的后果很真实:你以为只给自己设的代理地址,一不小心提交进了 git,全团队都被你带跑偏了。
类比:公司报销标准贴公告栏 vs 你自己记在便签。 财务把「打车 50 封顶」打印出来贴在公告栏,全公司都得照办,这是公开规矩;你自己嫌麻烦,在工位便签上写「这个月我自费的咖啡别报」,这是只管你自己的私人备注。环境变量写进哪个文件,就是在选「贴公告栏」还是「记便签」。
官方给的这张表,直接告诉你每类文件「管到谁」:
| 文件 | 适用于 |
|---|---|
~/.claude/settings.json | 你,在每个项目中 |
.claude/settings.json | 在项目中工作的每个人,检入源代码控制 |
.claude/settings.local.json | 你,仅在此项目中,未检入 |
| 托管设置 | 你组织中的每个人,由管理员部署 |
翻成大白话,四句话记住:
~/.claude/settings.json——在你主目录下,「我自己,所有项目都这么来」。你个人偏好放这儿。.claude/settings.json(项目根)——「这个项目里所有人都这么来」,而且它进 git,队友拉下来就带上。团队统一的规矩放这儿。.claude/settings.local.json(项目根)——「只有我,只在这个项目」,而且它不进 git(.local后缀默认被忽略)。带私人凭据、只属于你的临时设置放这儿。- 托管设置——管理员给全组织统一下发的,你一般改不了,也轮不到你设。
这里有个不大不小的跟头很容易栽。接自建网关时,图省事把 ANTHROPIC_BASE_URL 连同一个带个人 token 的地址写进项目根的 .claude/settings.json,然后顺手 git commit——推之前要是没扫一眼 diff,就麻烦了:那玩意儿一旦推上去,等于把私有地址(还可能带凭据)公开给了所有能看到这个仓库的人。 所以有条铁律记死:凡是带「个人专属」性质的变量(私有地址、个人配置目录这种),一律进 .local 那个不上 git 的文件;只有「全队都该一样」的,才往 .claude/settings.json 里放。
| 这个变量的性质 | 该写进哪个文件 |
|---|---|
| 我个人偏好,所有项目通用 | ~/.claude/settings.json(主目录) |
| 全队统一,要随项目共享 | .claude/settings.json(进 git) |
| 我私人的、带凭据的、只这个项目 | .claude/settings.local.json(❌ 不进 git) |
💡 一句话总结:
settings.json分四类文件,写进哪个决定这变量管「谁」——主目录管自己全局、项目根settings.json进 git 管全队、.local不进 git 只管自己;带个人凭据的变量,死活别往进 git 的文件里放。
04 最该认识的那几个变量:连接、超时、隐私、目录
官方那张环境变量表,说实话,长得吓人——上百个,从 AWS Bedrock 到 OpenTelemetry 导出器,绝大多数你这辈子都用不上。所以这一节我不堆清单,只挑小白真实会碰到的那十来个,按用途分四组,每个给你说清「干啥的、默认多少、什么时候动它」。
一组:连接与认证(怎么连上模型)
这组是前面第 04、05 篇的底层。三个核心:
ANTHROPIC_API_KEY # 你的 API 密钥
ANTHROPIC_BASE_URL # 把请求改道到代理或网关
ANTHROPIC_MODEL # 默认用哪个模型
-
ANTHROPIC_API_KEY——你的 API 密钥。这里有个特别容易踩的点,官方写得明明白白:一旦设了这个 key,即使你已经登录了订阅(Pro / Max / Team / Enterprise),也会改用这个 key。想换回订阅,得unset ANTHROPIC_API_KEY把它清掉。注意:交互模式下,Claude Code 会弹一次确认提示,让你批准或拒绝用这个 key,选择记住后续自动沿用;非交互模式(-p)则直接使用,不弹确认。 这个坑很容易踩——明明开了 Max 订阅,账单却走了 API 计费,查半天才发现是~/.zshrc里残留了一行export ANTHROPIC_API_KEY(第 04 篇详谈了订阅 vs API key 怎么选)。 -
ANTHROPIC_BASE_URL——把 API 请求改道到你的代理或网关。接国产模型、走自建中转,核心就是它(第 05 篇那套配置,主角就是这个变量)。 -
ANTHROPIC_MODEL——指定默认模型。注意它的优先级:--model标志和会话里的/model命令会盖过它(下一节细讲)。
二组:超时(嫌它太快放弃就调这个)
网络慢、或者走代理绕远路时,最常调的就是超时。两个最常用:
| 变量 | 管什么 | 默认值 |
|---|---|---|
API_TIMEOUT_MS | 单次 API 请求的超时 | 600000(10 分钟) |
BASH_DEFAULT_TIMEOUT_MS | 长跑 bash 命令的默认超时 | 120000(2 分钟) |
-
API_TIMEOUT_MS——API 请求多久算超时。官方提示:网络慢或走代理时把它调大。但别瞎填——它有个上限2147483647,超过这个数会让底层计时器溢出,请求直接秒失败(手抖多打个 0 是常见情形,结果每次请求瞬间报错,排查半天才发现是溢出)。 -
BASH_DEFAULT_TIMEOUT_MS——Claude 跑那种长命令(比如装依赖、跑构建)默认给多久。默认 2 分钟,跑大型构建不够时调它。
三组:隐私与遥测(合规/强隐私场景)
第 21 篇讲安全时点过的几个,这组管「往外发不发数据」:
DISABLE_TELEMETRY=1 # 关掉遥测上报
DO_NOT_TRACK=1 # 同上,跨工具通用的约定
DISABLE_TELEMETRY——设成1退出遥测。官方明确说遥测数据不含你的代码、文件路径或 bash 命令;但合规要求严的环境,设上它图个干净。DO_NOT_TRACK——设成1,等同于DISABLE_TELEMETRY。这是个被很多开发者 CLI 共同遵守的跨工具约定,你设过一次,好些工具都认。
还有个一键全关的——
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1,官方说它等同于同时设了DISABLE_AUTOUPDATER、DISABLE_FEEDBACK_COMMAND、DISABLE_ERROR_REPORTING和DISABLE_TELEMETRY。强隐私 / 隔离环境一个变量全关掉,省事。
四组:多账号与上下文(进阶但好用)
两个高频、强烈推荐你认识的:
CLAUDE_CONFIG_DIR——覆盖配置目录(默认~/.claude)。所有设置、凭证、会话历史、插件都存这底下。它最大的用处是并行跑多个账号——官方给的例子就很实用:
# 给工作账号开个独立配置目录,互不干扰
alias claude-work='CLAUDE_CONFIG_DIR=~/.claude-work claude'
工作号和个人号就可以这么分:平时 claude 走个人配置,敲 claude-work 走另一套完全隔离的设置和登录态,两边的历史、凭证、MCP 配置井水不犯河水。
DISABLE_AUTO_COMPACT——设成1关掉「接近上下文上限时的自动压缩」(第 19 篇讲过 auto-compact 这个机制)。手动/compact仍然能用。想完全自己掌控什么时候压缩,才设它——多数人保持默认即可。
⚠️ 一句重要提醒:官方说得很死——Claude Code 只在「启动时」读环境变量。所以你改完任何变量(无论改 shell 还是改
settings.json),都得退出claude重开,新值才生效。改完没反应,十有八九是没重启。
💡 一句话总结:真正常碰的就四组——连接认证(
ANTHROPIC_API_KEY/BASE_URL/MODEL)、超时(API_TIMEOUT_MS默认 10 分钟)、隐私(DISABLE_TELEMETRY/DO_NOT_TRACK)、多账号(CLAUDE_CONFIG_DIR);改完务必重启claude才生效。
05 优先级:同一件事好几个地方都能设,到底谁说了算
学到这儿你会冒出一个很自然的疑问:模型既能用 ANTHROPIC_MODEL 设、又能用 /model 命令选、还能在 settings.json 里写 model 字段——三个都设了,听谁的?
这就是「优先级(precedence)」要回答的事。不搞清它,你会遇到「我明明设了啊怎么没用」的灵异现象。
先记住官方给的第一条总纲——环境变量 > 设置字段:
当相同的行为同时具有环境变量和设置字段时,环境变量优先。例如,
ANTHROPIC_MODEL覆盖model设置。当环境变量未设置时,设置字段适用。
类比:老板当面那句话,压过员工手册。 员工手册(settings.json 的字段)白纸黑字写着「报销打车 50 封顶」;可老板今天当面跟你说「这趟远,你打车实报实销」(环境变量)——这一趟你当然听老板当面那句的。环境变量就是那句「当面交代」,比手册里写死的字段更优先。等老板没特别交代时(环境变量没设),才回去按手册(设置字段)办。
但这里有个反直觉的拐点,新手最容易栽:不是所有东西环境变量都压得住。 模型这件事,官方专门点了名:
--model和/model覆盖ANTHROPIC_MODEL。
也就是说,模型这条链是这样的:
/model 命令 / --model 标志 ← 最优先(你当场的选择)
↓ 盖过
ANTHROPIC_MODEL 环境变量 ← 其次
↓ 盖过
settings.json 的 model 字段 ← 兜底
为啥模型这儿反过来了?其实很合理——你在会话里手动 /model 切一下,是「我现在就想用这个」的明确当场意图,它当然该压过你之前设死的那个环境变量。 这跟「老板当面那句压过手册」是同一个逻辑:越「当场、越明确」的指令,优先级越高。
| 配置方式 | 相对优先级 | 一句话 |
|---|---|---|
/model 命令 / --model 标志 | 最高 | 你会话里/启动时当场的明确选择 |
ANTHROPIC_MODEL 环境变量 | 中 | 你预先设死的默认 |
settings.json 的 model 字段 | 兜底 | 都没设时才用 |
注意:这个「命令/标志盖过环境变量」是模型这类配置的规矩,不是放之四海皆准。官方原话提醒不同功能交互方式不一样——比如
CLAUDE_CODE_EFFORT_LEVEL反而会覆盖/effort命令。所以拿不准某个具体变量时,回官方那张变量表查它那一行的说明,别想当然。
这条很容易栽一次:在 settings.json 里写死了 ANTHROPIC_MODEL,结果某次会话里随手 /model 切了个别的,切完就忘了——下半场一直在用临时切的那个,还纳闷怎么跟配置的不一样。其实道理很直白:/model 当场选的,本来就该压过预设的环境变量。这不是 bug,是设计。
💡 一句话总结:总纲是环境变量 > 设置字段(老板当面话压过员工手册);但模型这类有例外——
/model/--model这种「当场明确指令」反过来压过ANTHROPIC_MODEL;规律是「越当场越明确,优先级越高」,拿不准就查官方那行说明。
06 动手:设一个变量,亲手验证它真的生效了
光看不练,环境变量这东西永远隔层纱。下面带你走一遍最小闭环:设一个变量 → 进会话 → 确认它真生效了。全程不依赖你任何已有的复杂配置,几分钟搞定。
我们拿 BASH_DEFAULT_TIMEOUT_MS(bash 命令默认超时)来练——选它是因为它安全、可观察、改错了也不影响连接。
第一步:先看默认状态(在终端,启动 claude 之前)
什么都别设,直接开一个会话:
claude
进去后,让它跑一句话,问它当前的 bash 超时:
我现在的 bash 命令默认超时是多少毫秒?读一下你环境里的 BASH_DEFAULT_TIMEOUT_MS,没设的话就说默认值
预期:它会告诉你这个变量没显式设置,走默认 120000(2 分钟)。记住这个基线值,等会儿对照。然后退出会话(敲 /exit 或 Ctrl+C 两下)。
第二步:用 shell 临时设一个值,再开会话
回到终端,临时 export 一个不一样的值(设成 5 分钟),紧接着开会话:
export BASH_DEFAULT_TIMEOUT_MS="300000"
claude
Windows PowerShell 用:
$env:BASH_DEFAULT_TIMEOUT_MS = "300000"然后claude。
进去后,问同样的问题:
我现在的 bash 命令默认超时是多少毫秒?
预期:这次它该读到 300000(5 分钟),而不是默认的 120000。看到值从 120000 变成了 300000 = 你的临时设置真的被读进去了。 这就验证了「方式一:shell 临时设」确实管用。
第三步:验证「关掉终端就没了」
退出会话,完全关掉这个终端窗口,重新开一个新的,直接 claude(这次什么都不 export),再问一遍同样的问题。
预期:又变回 120000(默认值)。因为 export 只对那个已经关掉的终端有效——这就亲眼印证了第 02 节那条「shell 临时设,关掉终端就没了」。
第四步(可选):写进 settings.json,让它持久
如果你想让这个值长期生效、跟启动方式无关,把它写进 settings.json。最稳妥是写进只属于你、不上 git 的那个文件:
{
"env": {
"BASH_DEFAULT_TIMEOUT_MS": "300000"
}
}
写进
.claude/settings.local.json(当前项目根、不进 git),或~/.claude/settings.json(你的主目录、所有项目通用),按你想要的范围选——参考第 03 节那张表。
存盘后,新开终端、直接 claude(不 export),再问一遍——这次该稳定读到 300000 了,而且无论你以后怎么启动 claude,它都在。这就是「方式三:写进 settings.json」相比 shell 临时设的好处:一次写好,不用回回 export。
跑完这四步,你就把环境变量「设 → 验证生效 → 验证范围 → 持久化」整条链路亲手走了一遍。以后设任何变量,本质都是这套:先临时试管不管用,确认了再挪进 settings.json 固化。
💡 一句话总结:验证一个变量生不生效,最稳的办法就是「问 Claude 它读到的值」;先 shell 临时
export试探(关终端就没)、确认管用再写进settings.json持久化——亲手走一遍这条链路,环境变量就再也不玄了。
07 小结
这一篇我们钻到水面下,把控制 Claude Code 底层行为的那排「总开关」——环境变量——认全、拨明白了。
归纳一下,整篇讲的核心就五件事:它管什么、在哪设、写进哪个文件、常用的那几个长啥样、多处都设了听谁的。一张表串起来:
| 你要搞清的事 | 答案 | 关键点 |
|---|---|---|
| 环境变量管啥 | 连接、认证、超时、隐私这些底层行为 | 启动时读的键值对开关,「设一次长期生效」 |
| 在哪设 | shell 临时 / ~/.zshrc / settings.json 的 env | 按生效范围选,长期用推荐 settings.json |
| 写进哪个 settings 文件 | 主目录 / 项目根(进 git) / .local(不进 git) | 带凭据的别进 git |
| 最常用哪几个 | ANTHROPIC_*、API_TIMEOUT_MS、DISABLE_TELEMETRY、CLAUDE_CONFIG_DIR | 各有默认值,改完重启才生效 |
| 多处都设了听谁的 | 环境变量 > 设置字段;但 /model 压过 ANTHROPIC_MODEL | 越当场越明确,优先级越高 |
你现在应该能: 看懂环境变量在 Claude Code 里到底管什么、知道三种设置方式各自的生效范围、清楚 settings.json 四类文件谁进 git 谁不进、认识连接/超时/隐私/多账号这几组最常用的变量、并且想明白当同一件事多处都能设时该听谁的。更重要的是——你亲手设了一个变量、验证了它真生效、还看到了「关掉终端就没」和「写进文件就持久」的区别。 这层窗户纸一旦捅破,环境变量就从「高阶玄学」变成了你随手能拨的开关。
回到开头那句话:环境变量从来不是「高阶才碰」,而是「一次拨好、终身受益」。 你前面四十一篇里那些「每次都得手动设一遍」的别扭,现在多半都能用一个变量一劳永逸地解决了。
下一篇 43「Git 工作流」——环境变量帮你把 Claude Code 的底层行为安顿明白了,接下来该让它真正融进你每天的开发节奏。说到开发,绕不开的就是 Git:让 Claude 帮你写提交信息、理清 diff、开 PR、处理冲突……它在 Git 这块到底能帮到哪一步、又有哪些坑得你自己盯着?下一篇好好聊聊。想想看:你愿意让 AI 替你 git commit,但 git push 到生产分支这一下,你敢撒手吗?
16 小时 Claude Code