Mingyu's Library主页
2026年8月24日

第 18 课:`/goal` —— 让 Claude 自己判断「干完了没有」

2026-08-24 · 主题:/goal 完成条件驱动的长任务自主推进 为什么是今天:第 3 课讲 subagent 分工、第 6 课讲复杂需求稳定交付、第 16 课讲 worktree 并行——都是「怎么把活派出去」。但派出去之后谁来判断活干完了?一直是同一个模型自说自话。/goal 把「干活的模型」和「判定完成的模型」拆成两个,这是长任务能不能真正无人值守的关键一环。 前置:/goal 需 Claude Code v2.1.234+(check-in 功能);idle check-in 需 v2.1.236+;--resume 选择器恢复 goal 需 v2.1.239+。 官方文档:https://code.claude.com/docs/en/goal


技巧 1(入门):写一个「评审员能读懂」的完成条件

/goal 后面跟条件,设完立刻开一轮,不用再发 prompt:

/goal all tests in test/auth pass and the lint step is clean

关键在于:评审员是一个小快模型(Claude API 默认 Haiku),它不跑命令、不读文件,只读会话里已经出现的内容做判断。所以条件必须是「Claude 自己的输出能证明」的东西。

一个能撑过几十轮的条件通常有三要素:

要素 说明 例子
一个可度量的终态 测试结果 / 构建退出码 / 文件数 / 队列清空 「test/auth 全部通过」
明确的验证方式 告诉 Claude 怎么证明 「npm test exits 0」「git status is clean」
不可动的约束 路上什么不许变 「不修改其他测试文件」

写全了大概长这样(条件上限 4000 字符):

/goal npm test exits 0 and npm run lint exits 0, proven by pasting the exit code of each; no file outside src/auth/ is modified; or stop after 20 turns

结尾那句 or stop after 20 turns 是兜底闸门——把轮数写进条件本身,Claude 每轮汇报进度,评审员从对话里判断这个子句是否触发。没有它,一个写得含糊的条件可能烧掉一整晚的 token。

查看状态直接敲 /goal(不带参数),会显示条件、已运行时长、已评审轮数、当前 token 花费、评审员最近一次的理由:

/goal

提前收手:

/goal clear

(stop / off / reset / none / cancel 都是 clear 的别名;/clear 开新会话也会顺带清掉 goal。)

📖 https://code.claude.com/docs/en/goal


技巧 2(进阶):/goal + auto mode 才等于「无人值守」

这是最常见的误解:/goal 不改变权限模式。

两者是互补的,要真正整晚不管,必须同时开:

# 会话里先切到 auto mode(或启动时指定),再设 goal
/goal migrate every call site in src/api/ to the v2 client, until `npm run build` exits 0 and `rg "v1Client" src/` returns nothing; or stop after 30 turns

另外三种「让会话自己往下跑」的机制,选型别搞混:

机制 下一轮由什么触发 什么时候停
/goal 上一轮结束,或后台任务把 goal 挂起时的 idle check-in 到期 评审员判定 met / impossible;或遇到需你修的错误;或 /goal clear
/loop 时间间隔到了 你停它,或 Claude 认为做完了
Stop hook 上一轮结束 你自己的脚本或 prompt 说了算

一句话选型:按条件收敛用 /goal,按节奏轮询用 /loop,要跨所有会话生效、要确定性脚本判定就写 Stop hook(/goal 本质就是一个会话级的 prompt-based Stop hook 包装)。

📖 https://code.claude.com/docs/en/goal · https://code.claude.com/docs/en/hooks-guide#prompt-based-hooks


技巧 3(进阶):后台任务会「冻住」评审,check-in 节奏可以自己调

一个坑:如果一轮结束时还有 subagent 或后台 shell 在跑,这一轮不评审,要等到下一个「结束时没有后台任务」的轮次。后台任务跑完了,Claude Code 会把结果当作新的一轮送给 Claude,你不用再敲字。

问题是长构建/长测试会让 goal 一直挂着。Claude Code 的应对是 check-in:

嫌 30 分钟太长(比如你的测试跑 5 分钟就该有结论)可以改:

# 首次 check-in 改成 8 分钟,后续按 8 → 16 → 32 分钟退避
export CLAUDE_CODE_GOAL_CHECKIN_MINUTES=8
claude
# 完全关掉 check-in
export CLAUDE_CODE_GOAL_CHECKIN_MINUTES=0

还有个安全阀值得知道:如果 Claude 连续几轮只回话不动工具(在跟评审员打嘴仗),Claude Code 会停下循环、打印警告、把控制权还给你,但 goal 仍然保留——你下一次发 prompt 后评审会自动恢复。看到这个警告,基本等于条件写得太主观,回去改条件。

📖 https://code.claude.com/docs/en/goal · https://code.claude.com/docs/en/env-vars


技巧 4(高阶):把 /goal 塞进 CI / 定时脚本

/goal 在非交互模式、桌面端和 Remote Control 里都能用。用 -p 设 goal,整个循环会在一次调用里跑到收敛:

claude -p "/goal CHANGELOG.md has an entry for every PR merged this week, proven by listing the PR numbers and the matching lines" \
  --output-format stream-json --verbose

两个必须注意的点:

  1. 一定加 --output-format stream-json --verbose。默认文本输出在整个循环结束前什么都不打印,一个跑了 20 轮的 goal 在 CI 日志里看起来就像挂死了。
  2. 中途要停按 Ctrl+C——非交互 goal 没有 /goal clear 可敲。

哪些失败会自动清空 goal(需要你介入修的那类),值得写进你的 runbook:

除此之外的失败(限流、服务过载等瞬时错误)goal 都会保留、继续跑。被清空时的警告以 Goal cleared after an unrecoverable error 开头、以 Run /goal again to continue 结尾——CI 里 grep 这两句就能区分「该重试」还是「该叫人」。

最后一个细节:恢复会话会把还活着的 goal 一起恢复(--continue、--resume <id|name>、会话选择器都支持;选择器路径需 v2.1.239+),但轮数、计时器、token 基线会重置。所以如果你靠 or stop after 20 turns 兜底,resume 之后这个预算是重新开始算的——长期跑的任务记得改成时间或产物口径的约束。

📖 https://code.claude.com/docs/en/goal · https://code.claude.com/docs/en/headless


一句话回顾

/goal = 一个会话级的 Stop hook,用小快模型在每轮结束后判定你的条件是否成立。条件要可度量、可从对话里证明、带兜底子句;要无人值守就配 auto mode;后台任务会推迟评审,靠 CLAUDE_CODE_GOAL_CHECKIN_MINUTES 调节奏;进 CI 记得 stream-json,并区分「会清空 goal 的四类错误」和「会自动继续的瞬时错误」。