— 03 / 第三章
循环 · 计划、动手、验收.
这一章不讲循环,带你跑一次:一个真实的报错,从 /plan 拿到方案、改计划、放它动手、审 diff、验收通过。中途把权限模式六档和 allow / deny / ask 规则的写法讲透 —— 那是决定它「哪些事不用问你」的旋钮,也是全书后面所有放手的前提。跑完你手里有一份能复用的计划请求模板和一份权限配置。
— I
第一步:让它先交方案,不许动一个字.
/plan、或启动时 claude --permission-mode plan。1注 1Claude Code Docs · Permission modes —— 计划模式:让 Claude 调研、提方案,但不动源码 —— 读文件、跑探索命令、写出计划,批准前编辑一律被挡;Shift+Tab、/plan 或 claude --permission-mode plan 进入,Ctrl+G 把计划丢进外部编辑器改。六档模式配置值:default(界面标 Manual,manual 是可接受的别名)、acceptEdits、plan、auto、dontAsk、bypassPermissions。Shift+Tab 默认只在 default → acceptEdits → plan 之间循环,auto 与 bypassPermissions 按条件加入,dontAsk 从不出现在循环里。状态栏原样显示:⏸ plan mode on / ⏵⏵ accept edits on / ⏵⏵ auto mode on / ⏵⏵ don't ask on / ⏵⏵ bypass permissions on。acceptEdits 额外自动放行 mkdir、touch、rm、rmdir、mv、cp、sed(限工作目录或 additionalDirectories 内)。auto 由一个独立分类器模型审查每个动作,进入时丢弃授予任意代码执行的宽 allow 规则、退出时恢复;连续 3 次或累计 20 次拦截后回落到弹窗,阈值不可配。dontAsk 自动拒绝一切本会弹窗的调用,只放行 allow 规则命中项、只读 Bash 与 PreToolUse hook 批准的调用。bypassPermissions 不能会话中途进入,须启动时启用;即便在该模式下,显式 ask 规则、组织设为 ask 的 connector 工具、标记 requiresUserInteraction 的 MCP 工具,以及 root / home 目录删除仍会弹窗。auto 模式的可用性取决于套餐、组织策略、模型与供应商。截至 2026-08-05。
这份被你改过、批过的计划,不只是开工许可 —— 它是第 10 章验收时的基线:活交回来,diff 就对着它逐条核。所以计划请求本身值得写好:说清目标,更要说清验收标准和禁区。
提示词计划请求模板 · 目标 + 验收 + 禁区
/plan 我要做:<一句话目标>。 先读 <相关目录或文件>,把打算怎么做写成计划,包括:要改哪些文件、为什么。 验收标准:<能检验的标准,做完要能通过>。 禁区:<不许动的目录 / 不许引的依赖 / 不许做的重构>。 拿不准的地方列成问题问我,别自己猜。
/plan 我要做:修掉 POST /api/orders 在并发下偶发的 500。 先读 src/api/orders/ 和 src/db/,把打算怎么做写成计划,包括:要改哪些文件、为什么。 验收标准:npm test -- src/api/orders 全绿,并新增一条并发重现用例,该用例在修复前必须失败。 禁区:不动数据库 schema,不新引依赖,不重构 src/db/pool.ts 的连接池实现。 拿不准的地方列成问题问我,别自己猜。
Ctrl+G 能把它整份丢进你的外部编辑器1注 1Claude Code Docs · Permission modes —— 计划模式:让 Claude 调研、提方案,但不动源码 —— 读文件、跑探索命令、写出计划,批准前编辑一律被挡;Shift+Tab、/plan 或 claude --permission-mode plan 进入,Ctrl+G 把计划丢进外部编辑器改。六档模式配置值:default(界面标 Manual,manual 是可接受的别名)、acceptEdits、plan、auto、dontAsk、bypassPermissions。Shift+Tab 默认只在 default → acceptEdits → plan 之间循环,auto 与 bypassPermissions 按条件加入,dontAsk 从不出现在循环里。状态栏原样显示:⏸ plan mode on / ⏵⏵ accept edits on / ⏵⏵ auto mode on / ⏵⏵ don't ask on / ⏵⏵ bypass permissions on。acceptEdits 额外自动放行 mkdir、touch、rm、rmdir、mv、cp、sed(限工作目录或 additionalDirectories 内)。auto 由一个独立分类器模型审查每个动作,进入时丢弃授予任意代码执行的宽 allow 规则、退出时恢复;连续 3 次或累计 20 次拦截后回落到弹窗,阈值不可配。dontAsk 自动拒绝一切本会弹窗的调用,只放行 allow 规则命中项、只读 Bash 与 PreToolUse hook 批准的调用。bypassPermissions 不能会话中途进入,须启动时启用;即便在该模式下,显式 ask 规则、组织设为 ask 的 connector 工具、标记 requiresUserInteraction 的 MCP 工具,以及 root / home 目录删除仍会弹窗。auto 模式的可用性取决于套餐、组织策略、模型与供应商。截至 2026-08-05。 —— 删掉过度设计的那段、补上它漏掉的边界情况,再让它照改好的版本动手。这一下是整条线上性价比最高的动作:改一行计划,比改十行代码便宜。
计划也有成本,别处处开。官方的判断尺很好用:方案不确定、改动跨多个文件、代码不熟 —— 值得计划;一句话能说清那个 diff 的活,直接干。4注 4Claude Code Docs · Best practices —— 推荐工作流:探索、计划、实现、提交四步;计划在方案不确定、改动跨多文件、代码不熟时最值,「如果一句话能说清那个 diff,跳过计划」。跑偏时尽早纠:Esc 打断、同一问题纠正两次仍不对就 /clear 带着教训重开。截至 2026-08-05。改个错字还要走审批,是把仪式当成了纪律。
— II
第二步:六档模式,定它的自由度.
| 配置值 | 不问就能做 | 适合 |
|---|---|---|
default | 只读操作(界面里叫 Manual) | 敏感代码、刚上手 |
acceptEdits | 文件编辑,外加 mkdir / touch / rm / rmdir / mv / cp / sed | 你事后看 diff 的日常活 |
plan | 只读操作 | 动手前的调研 |
auto | 几乎全部,独立分类器在每个动作前把关 | 方向可信的长任务 |
dontAsk | 只有预批准项;其余一律自动拒绝 | 锁死的 CI 与脚本(第 9 章) |
bypassPermissions | 几乎一切,且不能会话中途进入 | 只在隔离容器 / VM 里用 |
acceptEdits:文件随它改,你看最终 diff —— 逐个批编辑的第十次点击之后,你其实已经不在审了。要走得更远用 auto:不是全放行,而是有一个独立的分类器模型在每个动作前把关;它还有两个自我保护的设计 —— 进入 auto 时会主动丢弃那些授予任意代码执行的宽 allow 规则(退出再恢复),以及连续 3 次或累计 20 次拦截后回落到弹窗,阈值不可配。1注 1Claude Code Docs · Permission modes —— 计划模式:让 Claude 调研、提方案,但不动源码 —— 读文件、跑探索命令、写出计划,批准前编辑一律被挡;Shift+Tab、/plan 或 claude --permission-mode plan 进入,Ctrl+G 把计划丢进外部编辑器改。六档模式配置值:default(界面标 Manual,manual 是可接受的别名)、acceptEdits、plan、auto、dontAsk、bypassPermissions。Shift+Tab 默认只在 default → acceptEdits → plan 之间循环,auto 与 bypassPermissions 按条件加入,dontAsk 从不出现在循环里。状态栏原样显示:⏸ plan mode on / ⏵⏵ accept edits on / ⏵⏵ auto mode on / ⏵⏵ don't ask on / ⏵⏵ bypass permissions on。acceptEdits 额外自动放行 mkdir、touch、rm、rmdir、mv、cp、sed(限工作目录或 additionalDirectories 内)。auto 由一个独立分类器模型审查每个动作,进入时丢弃授予任意代码执行的宽 allow 规则、退出时恢复;连续 3 次或累计 20 次拦截后回落到弹窗,阈值不可配。dontAsk 自动拒绝一切本会弹窗的调用,只放行 allow 规则命中项、只读 Bash 与 PreToolUse hook 批准的调用。bypassPermissions 不能会话中途进入,须启动时启用;即便在该模式下,显式 ask 规则、组织设为 ask 的 connector 工具、标记 requiresUserInteraction 的 MCP 工具,以及 root / home 目录删除仍会弹窗。auto 模式的可用性取决于套餐、组织策略、模型与供应商。截至 2026-08-05。
— III
第三步:把「不用问我」写成规则.
permissions 块里,三种裁决:allow(不问)、ask(必问)、deny(不许)。
求值顺序是这套规则唯一必须背下来的东西,官方原话:按 deny、ask、allow 的顺序求值,该顺序里第一个命中决定结果,规则的具体程度不改变顺序。2注 2Claude Code Docs · Configure permissions —— 规则求值顺序原话:「Rules are evaluated in order: deny, then ask, then allow. The first match in that order determines the outcome, and rule specificity doesn't change the order.」宽 deny 不能带白名单例外。格式为 Tool 或 Tool(specifier);deny 里写裸工具名会把该工具整个从 Claude 的上下文里移除(EndConversation 除外),Bash(*) 等同于裸 Bash。通配符:`*` 匹配任意字符序列(含空格),`Bash(ls *)` 匹配 ls -la 但不匹配 lsof,`Bash(ls*)` 两者都匹配,:* 后缀是等价的尾部通配写法。识别的命令分隔符为 && || ; | |& & 与换行,规则必须逐个子命令独立命中;批准一条复合命令最多保存 5 条规则。匹配前会剥掉一组固定包装:timeout、time、nice、nohup、stdbuf,加上内建 command、builtin 与 zsh 的 noglob;该列表内建不可配。开发环境运行器 direnv exec、devbox run、mise exec、npx、docker exec 不在剥离之列 —— 原文示例:Bash(devbox run *) 会匹配 run 之后的任何东西,包括 devbox run rm -rf .。watch、setsid、ionice、flock 等 exec 包装以及带 -exec / -delete 的 find 永远弹窗,前缀规则盖不住。deny 与 ask(不含 allow)可用 Tool(param:value) 匹配顶层标量入参,如 Agent(model:opus)、Agent(isolation:worktree)、Bash(run_in_background:true),每条规则一个参数,模型省略的参数永不命中;主内容字段不能这样匹配 —— Bash / PowerShell 的 command、Read / Edit / Write 的 file_path、Grep / Glob 的 path、NotebookEdit 的 notebook_path。截至 2026-08-05。推论很重要:一条宽 deny 不能带白名单例外 —— Bash(aws *) 拦死之后,再写多细的 Bash(aws s3 ls) allow 都没用。2注 2Claude Code Docs · Configure permissions —— 规则求值顺序原话:「Rules are evaluated in order: deny, then ask, then allow. The first match in that order determines the outcome, and rule specificity doesn't change the order.」宽 deny 不能带白名单例外。格式为 Tool 或 Tool(specifier);deny 里写裸工具名会把该工具整个从 Claude 的上下文里移除(EndConversation 除外),Bash(*) 等同于裸 Bash。通配符:`*` 匹配任意字符序列(含空格),`Bash(ls *)` 匹配 ls -la 但不匹配 lsof,`Bash(ls*)` 两者都匹配,:* 后缀是等价的尾部通配写法。识别的命令分隔符为 && || ; | |& & 与换行,规则必须逐个子命令独立命中;批准一条复合命令最多保存 5 条规则。匹配前会剥掉一组固定包装:timeout、time、nice、nohup、stdbuf,加上内建 command、builtin 与 zsh 的 noglob;该列表内建不可配。开发环境运行器 direnv exec、devbox run、mise exec、npx、docker exec 不在剥离之列 —— 原文示例:Bash(devbox run *) 会匹配 run 之后的任何东西,包括 devbox run rm -rf .。watch、setsid、ionice、flock 等 exec 包装以及带 -exec / -delete 的 find 永远弹窗,前缀规则盖不住。deny 与 ask(不含 allow)可用 Tool(param:value) 匹配顶层标量入参,如 Agent(model:opus)、Agent(isolation:worktree)、Bash(run_in_background:true),每条规则一个参数,模型省略的参数永不命中;主内容字段不能这样匹配 —— Bash / PowerShell 的 command、Read / Edit / Write 的 file_path、Grep / Glob 的 path、NotebookEdit 的 notebook_path。截至 2026-08-05。
{
"$schema": "https://json.schemastore.org/claude-code-settings.json",
"permissions": {
"defaultMode": "acceptEdits",
"allow": [
"Bash(npm run lint)",
"Bash(npm test *)",
"Bash(git status)",
"Bash(git diff *)",
"Bash(git log *)"
],
"ask": [
"Bash(git push *)",
"Bash(gh pr merge *)"
],
"deny": [
"Read(./.env)",
"Read(./.env.*)",
"Read(./secrets/**)",
"Bash(rm -rf /*)",
"Bash(curl * | sh)"
]
}
}一份可抄的起手权限配置:放行日常、拦死危险、可疑的必问
- 星号前那个空格是有意义的
Bash(ls *)匹配ls -la,但不匹配lsof;Bash(ls*)两个都匹配。2注 2Claude Code Docs · Configure permissions —— 规则求值顺序原话:「Rules are evaluated in order: deny, then ask, then allow. The first match in that order determines the outcome, and rule specificity doesn't change the order.」宽 deny 不能带白名单例外。格式为 Tool 或 Tool(specifier);deny 里写裸工具名会把该工具整个从 Claude 的上下文里移除(EndConversation 除外),Bash(*) 等同于裸 Bash。通配符:`*` 匹配任意字符序列(含空格),`Bash(ls *)` 匹配 ls -la 但不匹配 lsof,`Bash(ls*)` 两者都匹配,:* 后缀是等价的尾部通配写法。识别的命令分隔符为 && || ; | |& & 与换行,规则必须逐个子命令独立命中;批准一条复合命令最多保存 5 条规则。匹配前会剥掉一组固定包装:timeout、time、nice、nohup、stdbuf,加上内建 command、builtin 与 zsh 的 noglob;该列表内建不可配。开发环境运行器 direnv exec、devbox run、mise exec、npx、docker exec 不在剥离之列 —— 原文示例:Bash(devbox run *) 会匹配 run 之后的任何东西,包括 devbox run rm -rf .。watch、setsid、ionice、flock 等 exec 包装以及带 -exec / -delete 的 find 永远弹窗,前缀规则盖不住。deny 与 ask(不含 allow)可用 Tool(param:value) 匹配顶层标量入参,如 Agent(model:opus)、Agent(isolation:worktree)、Bash(run_in_background:true),每条规则一个参数,模型省略的参数永不命中;主内容字段不能这样匹配 —— Bash / PowerShell 的 command、Read / Edit / Write 的 file_path、Grep / Glob 的 path、NotebookEdit 的 notebook_path。截至 2026-08-05。少打一个空格,你就把一个完全不同的命令放行了。- 复合命令逐段过筛
- 识别的分隔符是
&&、||、;、|、|&、&和换行,规则必须对每个子命令独立命中;批准一条复合命令时最多保存 5 条规则。2注 2Claude Code Docs · Configure permissions —— 规则求值顺序原话:「Rules are evaluated in order: deny, then ask, then allow. The first match in that order determines the outcome, and rule specificity doesn't change the order.」宽 deny 不能带白名单例外。格式为 Tool 或 Tool(specifier);deny 里写裸工具名会把该工具整个从 Claude 的上下文里移除(EndConversation 除外),Bash(*) 等同于裸 Bash。通配符:`*` 匹配任意字符序列(含空格),`Bash(ls *)` 匹配 ls -la 但不匹配 lsof,`Bash(ls*)` 两者都匹配,:* 后缀是等价的尾部通配写法。识别的命令分隔符为 && || ; | |& & 与换行,规则必须逐个子命令独立命中;批准一条复合命令最多保存 5 条规则。匹配前会剥掉一组固定包装:timeout、time、nice、nohup、stdbuf,加上内建 command、builtin 与 zsh 的 noglob;该列表内建不可配。开发环境运行器 direnv exec、devbox run、mise exec、npx、docker exec 不在剥离之列 —— 原文示例:Bash(devbox run *) 会匹配 run 之后的任何东西,包括 devbox run rm -rf .。watch、setsid、ionice、flock 等 exec 包装以及带 -exec / -delete 的 find 永远弹窗,前缀规则盖不住。deny 与 ask(不含 allow)可用 Tool(param:value) 匹配顶层标量入参,如 Agent(model:opus)、Agent(isolation:worktree)、Bash(run_in_background:true),每条规则一个参数,模型省略的参数永不命中;主内容字段不能这样匹配 —— Bash / PowerShell 的 command、Read / Edit / Write 的 file_path、Grep / Glob 的 path、NotebookEdit 的 notebook_path。截至 2026-08-05。 - 包装器会被剥掉,运行器不会
- 匹配前会剥掉
timeout、time、nice、nohup、stdbuf等固定包装 —— 所以Bash(npm test *)也盖得住timeout 30 npm test。但npx、docker exec、devbox run这类不在剥离之列,文档给的原例够吓人:Bash(devbox run *)会匹配 run 之后的任何东西,包括devbox run rm -rf .。2注 2Claude Code Docs · Configure permissions —— 规则求值顺序原话:「Rules are evaluated in order: deny, then ask, then allow. The first match in that order determines the outcome, and rule specificity doesn't change the order.」宽 deny 不能带白名单例外。格式为 Tool 或 Tool(specifier);deny 里写裸工具名会把该工具整个从 Claude 的上下文里移除(EndConversation 除外),Bash(*) 等同于裸 Bash。通配符:`*` 匹配任意字符序列(含空格),`Bash(ls *)` 匹配 ls -la 但不匹配 lsof,`Bash(ls*)` 两者都匹配,:* 后缀是等价的尾部通配写法。识别的命令分隔符为 && || ; | |& & 与换行,规则必须逐个子命令独立命中;批准一条复合命令最多保存 5 条规则。匹配前会剥掉一组固定包装:timeout、time、nice、nohup、stdbuf,加上内建 command、builtin 与 zsh 的 noglob;该列表内建不可配。开发环境运行器 direnv exec、devbox run、mise exec、npx、docker exec 不在剥离之列 —— 原文示例:Bash(devbox run *) 会匹配 run 之后的任何东西,包括 devbox run rm -rf .。watch、setsid、ionice、flock 等 exec 包装以及带 -exec / -delete 的 find 永远弹窗,前缀规则盖不住。deny 与 ask(不含 allow)可用 Tool(param:value) 匹配顶层标量入参,如 Agent(model:opus)、Agent(isolation:worktree)、Bash(run_in_background:true),每条规则一个参数,模型省略的参数永不命中;主内容字段不能这样匹配 —— Bash / PowerShell 的 command、Read / Edit / Write 的 file_path、Grep / Glob 的 path、NotebookEdit 的 notebook_path。截至 2026-08-05。 - deny 和 ask 能盯参数,allow 不能
- 用
Tool(param:value)匹配顶层标量入参,例如Agent(isolation:worktree)、Bash(run_in_background:true);一条规则只管一个参数,模型没传的参数永不命中。主内容字段盯不了 —— Bash 的 command、Read / Edit / Write 的 file_path、Grep / Glob 的 path。2注 2Claude Code Docs · Configure permissions —— 规则求值顺序原话:「Rules are evaluated in order: deny, then ask, then allow. The first match in that order determines the outcome, and rule specificity doesn't change the order.」宽 deny 不能带白名单例外。格式为 Tool 或 Tool(specifier);deny 里写裸工具名会把该工具整个从 Claude 的上下文里移除(EndConversation 除外),Bash(*) 等同于裸 Bash。通配符:`*` 匹配任意字符序列(含空格),`Bash(ls *)` 匹配 ls -la 但不匹配 lsof,`Bash(ls*)` 两者都匹配,:* 后缀是等价的尾部通配写法。识别的命令分隔符为 && || ; | |& & 与换行,规则必须逐个子命令独立命中;批准一条复合命令最多保存 5 条规则。匹配前会剥掉一组固定包装:timeout、time、nice、nohup、stdbuf,加上内建 command、builtin 与 zsh 的 noglob;该列表内建不可配。开发环境运行器 direnv exec、devbox run、mise exec、npx、docker exec 不在剥离之列 —— 原文示例:Bash(devbox run *) 会匹配 run 之后的任何东西,包括 devbox run rm -rf .。watch、setsid、ionice、flock 等 exec 包装以及带 -exec / -delete 的 find 永远弹窗,前缀规则盖不住。deny 与 ask(不含 allow)可用 Tool(param:value) 匹配顶层标量入参,如 Agent(model:opus)、Agent(isolation:worktree)、Bash(run_in_background:true),每条规则一个参数,模型省略的参数永不命中;主内容字段不能这样匹配 —— Bash / PowerShell 的 command、Read / Edit / Write 的 file_path、Grep / Glob 的 path、NotebookEdit 的 notebook_path。截至 2026-08-05。
— IV
第四步:验收,以及那条退路.
/rewind,或者输入框为空时连按两次 Esc,打开倒带菜单:只恢复对话、只恢复代码、或两者一起回到任一节点。3注 3Claude Code Docs · Checkpointing —— /rewind,或在输入框为空时连按两次 Esc,打开倒带菜单;输入框有字时双击 Esc 只清空文本(文本入历史,按 Up 可召回)。checkpoint 随对话保存,续开会话后仍可 /rewind。边界写得明白:只追踪本次会话内经 Claude 文件编辑工具做的改动 —— 你在编辑器里的手改、其他并发会话的改动通常不在内;倒带跳过软链接与硬链接路径,并给出提示。所选 checkpoint 没有可回滚的文件改动时,菜单只给恢复对话与摘要选项。截至 2026-08-05。(输入框里有字时,双击 Esc 只是清空文本 —— 文本会进历史,按 Up 能召回。3注 3Claude Code Docs · Checkpointing —— /rewind,或在输入框为空时连按两次 Esc,打开倒带菜单;输入框有字时双击 Esc 只清空文本(文本入历史,按 Up 可召回)。checkpoint 随对话保存,续开会话后仍可 /rewind。边界写得明白:只追踪本次会话内经 Claude 文件编辑工具做的改动 —— 你在编辑器里的手改、其他并发会话的改动通常不在内;倒带跳过软链接与硬链接路径,并给出提示。所选 checkpoint 没有可回滚的文件改动时,菜单只给恢复对话与摘要选项。截至 2026-08-05。)checkpoint 随对话保存,续开会话后照样能倒。3注 3Claude Code Docs · Checkpointing —— /rewind,或在输入框为空时连按两次 Esc,打开倒带菜单;输入框有字时双击 Esc 只清空文本(文本入历史,按 Up 可召回)。checkpoint 随对话保存,续开会话后仍可 /rewind。边界写得明白:只追踪本次会话内经 Claude 文件编辑工具做的改动 —— 你在编辑器里的手改、其他并发会话的改动通常不在内;倒带跳过软链接与硬链接路径,并给出提示。所选 checkpoint 没有可回滚的文件改动时,菜单只给恢复对话与摘要选项。截至 2026-08-05。
倒回之外还有两个更轻的纠偏动作:Esc 随时打断、补一句再继续;同一个问题纠正两次还不对,说明上下文里已经堆满失败尝试 —— /clear 清场,把学到的教训写进新的第一句,几乎总比在旧会话里继续拉扯更快。4注 4Claude Code Docs · Best practices —— 推荐工作流:探索、计划、实现、提交四步;计划在方案不确定、改动跨多文件、代码不熟时最值,「如果一句话能说清那个 diff,跳过计划」。跑偏时尽早纠:Esc 打断、同一问题纠正两次仍不对就 /clear 带着教训重开。截至 2026-08-05。
— V
循环连起来,就是最小的派活单元.
没有循环的一小时
一句接一句地聊,它边想边改。三十分钟后 diff 大得没法看,你说不清它在哪一步拐错的,也没有任何一条能复跑的检查能告诉你「现在算好了没有」。唯一的验收信号是你自己的眼睛。
有循环的一小时
一份你改过的计划当基线,一套写进仓库的规则决定它什么时候不用问你,一条测试命令替你回答「好了没有」,一个验证过的 /rewind 兜底。你做了两次判断,其余时间它在跑。
- 用上面的模板对一件真活请求了计划,并且按 Ctrl+G 亲手删改了至少一条。
- 数出了这一轮它问你的次数,并把其中至少两条写进了 settings 的 allow(或 deny)。
- 收活时对着计划逐条核过 diff,并且拿到了一份真实的检查输出,而不是一句「搞定了」。
- 故意 /rewind 了一次,确认这条退路真的存在 —— 并且知道它盖不住 Bash 删的文件。
先批方案,再收结果, 中间的键盘留给它.
Approve the plan, collect the result — leave the keys in between to it.
Aklman Library
— 讨论
讨论.
评论区初始化中…