主题
Plan Mode 与 Todo
两个不同阶段的东西,放在一页讲是因为它们经常连着用:
- Plan Mode 管"动手之前"——只读地探索代码,写出方案,等你批准
- Todo 管"动手之后"——把长任务拆成清单,逐项推进,你能看到进度
快速上手
复杂任务先规划:
text
/plan进去之后正常提需求。它会读代码、写出方案,然后停下来等你批。批了才开始改文件。
不进 Plan Mode 也行——遇到多步任务时它会自己调 enter_plan_mode。你可以直接说 "先给我方案,别动手",效果一样。
详细说明
Plan Mode 里它能做什么、不能做什么
代码级强制只读,不是靠提示词请求它"别改",而是权限层拦住写操作。
| 能 | 不能 |
|---|---|
| 读文件、grep、查符号、跑只读命令 | 改文件、写文件 |
| 把方案写进计划文件 | 跑有副作用的命令 |
计划文件是唯一例外——方案本身要落盘。放行是精确匹配当前计划文件路径, 不接受路径前缀匹配,所以不能借这个口子写到别处。
计划文件在 ~/.sid-code/plans/<项目名>/ 下,按 YYYYMMDD-HHmm + 主题命名。 好处是几天后想翻"上次那个方案"能找到。
三个状态
text
inactive → planning → awaiting_approvalawaiting_approval 是它调完 exit_plan_mode 之后的状态:方案已提交,球在你这。 你可以批准、可以拒绝并说明要改什么。拒绝会退回 planning,它带着你的反馈重写。
退出 Plan Mode 只能走状态机入口:exit_plan_mode 工具或斜杠命令。 Shift+Tab 的权限模式循环会跳过 plan 档——键盘只改一个模式字符串会造出 "假 plan 态"(每轮的约束提醒不触发),所以那条路被显式堵住了。在 plan 态按 Shift+Tab 会提示你用 exit_plan_mode 退出。
什么任务值得 Plan Mode
值得:
- 改动跨多个文件,或要动你不熟的模块
- 有多种做法,你想先看它选哪条、为什么
- 改错了代价高(数据迁移、权限逻辑、发布脚本)
不值得:
- 单文件小改、修 typo、加个日志——规划的开销比改本身还大
- 你已经明确知道要改哪一行
判断标准很简单:你会不会想在它动手前看一眼计划。会就用。
Todo:执行阶段的进度
批准之后进执行阶段,模型用 TodoWrite 维护一份清单。三个状态:
text
⬜ pending ⏳ in_progress ✅ completed任何时候看当前清单:
text
/todosTodo 不只是给你看的进度条,它是模型自己的工作记忆。长任务里模型容易"做到一半忘了 还有什么",清单让它每一步都能对照剩余项。这也是为什么执行阶段有了 Todo 之后, 模型不会再动不动想重新 enter_plan_mode——它有地方记进度了。
清单是全量替换的:每次更新都提交完整列表,不是增量打补丁。所以你看到的 永远是当前完整状态,不会出现半旧半新。
相关但不同的三个东西
容易和 Plan Mode 搞混,放一起说清楚:
| 命令 | 干什么 | 和 Plan Mode 的区别 |
|---|---|---|
/goal <完成条件> | 目标驱动:设定完成条件,达成前不停 | Plan 是"先批准再动手",goal 是"一直干到达标" |
/loop [间隔] <任务> | 按间隔重复跑同一个 prompt | 周期性任务,和规划无关,见定时与无人值守 |
下面展开讲 /goal——它有一套独立的评估机制,不只是"循环到满意"。
/goal:目标驱动持续执行
/goal 解决的是一类 Plan Mode 管不了的场景:你知道目标长什么样,但不想逐步盯着它怎么干。 设定一个完成条件,AI 自己干到达标为止,中间不需要你批准每一步。
典型用法:
text
/goal 把 src/legacy/ 下所有 callback 风格函数改成 async/await,测试全绿才算完成它和 Plan Mode 的根本区别:Plan Mode 是"先出方案等你批",/goal 是"直接干到达标"。 两者还可以配合——先 /plan 看方案,满意后退出 Plan Mode 再 /goal 执行。
子命令
/goal 的完整参数(src/command/commands/goal/goal.ts:42-56):
| 子命令 | 作用 |
|---|---|
/goal <完成条件> | 设定新目标(已有活跃目标会先确认替换) |
/goal status | 查看当前目标状态、轮次、预算、证据数、上次评估 |
/goal pause | 暂停目标 |
/goal resume | 恢复目标 |
/goal edit <新条件> | 编辑目标条件(会重置已收集的证据) |
/goal turns <n> | 调整最大轮次(1–1000) |
/goal budget <tokens> | 设置 Token 预算(支持 100k 这种写法) |
/goal clear 或 /goal cancel | 清除目标 |
它怎么判断"达标了"
这是 /goal 的核心设计,不是靠模型自己说"我做完了"。每轮对话结束时,一套独立的机制介入 (src/query/goal-gate.ts,在 end_turn 处理链的最末):
- 证据收集——自动从工具结果里提取证据(
src/goal/evidence-collector.ts)。 测试结果、构建结果、文件变更、命令输出都会进证据日志,不依赖模型配合,也不受/compact影响(证据是结构化的,压缩对话不会丢)。 - 预算检查——先查 Token 预算,超了直接停(省下后面评估的调用费用)。
- 轮次检查——再查轮次上限。
- 独立评估者——用一个独立的小模型(haiku 级别,512 token 输出、关闭思考) 基于证据日志判定目标是否达成(
src/goal/evaluator.ts)。 对话上下文只作补充,不是主判据——所以即使对话被压缩,评估也不受影响。 - 快速路径——测试全绿 / 构建成功 / 报告型任务已交付,直接判定满足,连 LLM 都不调 (
src/goal/evaluator.ts的tryFastPathEval)。
评估者返回结构化结果:{satisfied, reason, blockerKey, progress, impossible}。
双闸与自动停
| 闸 | 默认值 | 触发什么 |
|---|---|---|
| 最大轮次 | 150 轮(src/goal/config.ts:34,"给长任务留足空间") | 到了 → turns_limited |
| Token 预算 | 可配(/goal budget) | 到了 → budget_limited |
还有一个卡住检测:连续 3 轮撞上同一个 blocker(src/goal/blocked-detector.ts, 默认 threshold=3)→ 判 blocked。比如连续 3 轮都卡在"找不到某个依赖",它会停下来 而不是无限重试。
blocked 默认是软提醒,不是硬停止
blocked 和 impossible 默认降级为软提醒——告诉你"看起来卡住了",但不会强制终止, 你可以让它继续试或手动调整。想恢复"卡住即停"的旧行为,设环境变量 SID_ENABLE_GOAL_HARD_STOP=1(src/query/goal-gate.ts:319-321)。
目标不会忘
长任务里模型容易"做着做着忘了目标是什么"。/goal 每 4 轮自动把目标状态回注一次 (src/goal/reminder.ts,reminderInterval: 4),首轮必注入、/compact 后强制注入。
回注走的是 reminderParts 管道,不进 system prompt——所以不影响 Prompt Cache 命中率 (cache 按前缀命中,system prompt 没变就还在)。这也是 /goal 能长跑而不贵的原因之一。
状态栏会显示进度:◎ 目标 N/M 轮,接近上限(≥80%)转黄预警;暂停时显示 ⏸ 目标已暂停。
目标跨会话
目标状态会持久化到会话 metadata(src/app.ts:4048-4066)。用 --resume 恢复会话时, 非终态的目标会一起恢复,继续推进。/clear 会落一个 __CLEARED__ 哨兵防止"幽灵目标复活"。
/goal 与 Token Budget 续写互斥
/goal 和 --max-budget-usd 的"超预算续写"语义冲突——一个要停、一个要续。 同时用的话 /goal 优先(src/query/loop.ts:2144-2146)。要给 /goal 任务设成本上限, 用 /goal budget <tokens> 设 Token 预算,或用 quota.costLimit 做硬顶(见 成本与用量 的坑一)。
/goal、Plan Mode、/loop 三者怎么选
| 你要的 | 用哪个 | 为什么 |
|---|---|---|
| 先看方案再动手 | Plan Mode | 要你的批准才改文件 |
| 知道目标,干到达标为止 | /goal | 独立评估者判定,不需要逐步批准 |
| 按固定间隔重复同一件事 | /loop | 定时调度,不是"达标"驱动,见定时与无人值守 |
判断标准:你要不要在它动手前看一眼方案。要就用 Plan Mode;不要、只关心结果就用 /goal。
常见问题
在 Plan Mode 里它说要改文件,然后报权限错误。 预期行为。plan 模式下写操作被权限层拦住,这正是它的作用。它应该把改动写进方案 而不是直接改——如果它反复尝试写文件,说明它没意识到自己在 plan 态,直接提醒一句就行。
按了 Shift+Tab 想退出 Plan Mode,没反应。 见上,plan 不参与键盘循环。用 exit_plan_mode(让它提交方案)或者告诉它"退出计划模式"。
方案写得不对,我怎么让它重写。 在 awaiting_approval 时拒绝并说清哪里不对。别批准了再让它改——批准之后它就 开始动手了,改起来更麻烦。
批准了但它没按计划做。 计划与实际工具调用的对齐度(fidelity)内核有记录:计划步数、实际调用数、 偏离计划的调用数。/trace 能看到这些。发现偏离多的话,通常是计划写得太粗, 下次让它把步骤拆细。
计划文件堆了很多,能删吗。 能,~/.sid-code/plans/ 下的都是纯文本记录,删掉不影响任何运行时行为。
Plan Mode 里能用子代理探索吗。 能,子代理也受只读约束。这在大仓库里很值——探索读的那一堆文件不进主上下文, 见子代理。