Control
按当前项目 docs/00-任务总控/ 下的总控文档推进任务。本 skill 是通用方法论 skill(用户级),不绑定具体项目。
真值源:references/总控规范.md(本 skill 内)。
🛑 执行边界(最高红线,永远遵守)
这是本 skill 最重要的一条。所有其他规则都让位于此。
- 用户指定
/control <key> Tn→ 只执行 Tn(支持Tn.x二级子任务)。不做 Tn-1,不做 Tn+1,不做同级兄弟,不"顺手"做相关任务。 - Tn 的「输出物」全部产出 → 立刻停止,回填状态,向用户报告。等用户下一步指令。
- ✅ 读不设禁区:可以读其他子任务详情与产出物、总控任何部分、仓库任何文件——开工前把背景挖够再动手(读什么放开 ≠ 做什么放开)
- ❌ 不可写入其他子任务范围(即使发现"很容易顺便做"也不要做)
- 如果发现 Tn 的范围定义有问题(应扩大或缩小) → 停止施工,向用户报告问题,不要自行扩张。但**"工作包某句描述过时了"不是范围问题**——与已冻结上游冲突时,按最新冻结真值修订描述、留痕、继续跑(总控规范 §4.6)
- 自主补读亲自读:为补背景直接读文件 / 检索即可,禁止为"补背景"派子 agent / 起深度调查(读是加法、派 agent 是乘法);背景缺口大到需要专门调查 → 按第 5 条停机上报,不自己扩编
- 过程资产边界:执行 Tn 时产生的中间文档(设计稿、清单、批判稿等),只能写到
_shared/且文件名带T{n}-前缀(任务级共享资产无前缀);不可用其他子任务的T{m}-前缀(m≠n),不可平铺到任务根目录,不可新建_T{n}/目录。详见总控规范 §1.1.1。 - 规则铸造权不在工作包手上:只有项目级指令文档与 skill 能铸造规则。工作包 / 评审报告 / goal 章程里的「硬门」「死亡线」「必须审批」一律是执行建议,不具停机权;死亡线是封闭清单,任何人无权新增——包括你(总控规范 §4.4)
- 停机白名单封闭,只有三条:①两份都已冻结的真值真矛盾且改变业务结果 ②命中项目死亡线清单的业务规则要变 ③不可逆 / 外发动作。其余一律先修后报——笔误、脚本 bug、过期描述、证据充分的简单缺陷,在预授权边界内修复 + 留痕 + 继续。减少临时协调不覆盖项目声明的授权角色、环境占用、职责分离或强制检查点。冲突批处理与
EXECUTION_BLOCKED细则以总控规范 §4.5 为真值;goal 执行态以章程 §4 白名单为准(章程已由对应权限角色预授权的动作不触发第 ③ 条) - 获批总控可包含本地提交授权:只有经任务治理负责人批准的总控,才预授权在其范围内
git commit;项目补丁可要求额外检查。推送远端仍需发布授权人显式授权(总控规范 §4.7) - 写入范围必须机器核对:开工记录
start_commit;工作包列出allowed_write_paths与精确到 Markdown 标题的allowed_cross_task_writes;交付前只对本子任务明确列出的候选提交运行check_write_scope.py。无关提交不阻断,候选提交夹带越界文件直接失败(总控规范 §4.8) - 长程 goal 必须磁盘复水:首次启动、
--resume、新会话或自动上下文压缩后,第一次写入前重读当前工作包、全部强制阅读、章程、goal 断点与飞行日志尾部;连续未压缩轮次不机械复读整套 skill(总控规范 §4.9)
项目约定
本 skill 假设当前项目遵循以下固定路径约定(所有项目通用,不带任何具体项目烙印):
| 路径 | 用途 |
|---|---|
<PROJECT_ROOT>/docs/00-任务总控/ |
总控目录树根 |
<PROJECT_ROOT>/docs/00-任务总控/README.md |
活跃任务索引 |
<PROJECT_ROOT>/docs/00-任务总控/归档/ |
已完成任务归档树 |
<PROJECT_ROOT>/docs/00-任务总控/归档/README.md |
归档总索引 |
<PROJECT_ROOT>/docs/00-任务总控/归档/V{x}/README.md |
版本归档索引 |
<PROJECT_ROOT>/docs/00-任务总控/{YYYY-MM-DD}-{任务名}/ |
任务子目录(日期前缀防多 worktree 编号撞车) |
<PROJECT_ROOT>/docs/00-任务总控/{YYYY-MM-DD}-{任务名}/README.md |
任务主总控(拆分 / 单文件统一) |
<PROJECT_ROOT>/docs/00-任务总控/{YYYY-MM-DD}-{任务名}/T{n}-{子任务名}.md |
拆分模式的一级子任务工作包 |
<PROJECT_ROOT>/docs/00-任务总控/{YYYY-MM-DD}-{任务名}/T{n}/T{n}.md |
被拆过的父任务说明(保留背景/范围,原 T{n}-*.md 迁移到此) |
<PROJECT_ROOT>/docs/00-任务总控/{YYYY-MM-DD}-{任务名}/T{n}/T{n}.{m}-{子任务名}.md |
二级子任务工作包(split 后产生) |
<PROJECT_ROOT>/.claude/local/active-control |
per-worktree 激活配置(gitignored) |
<PROJECT_ROOT>/.gitignore |
必须包含 .claude/local/ |
项目根解析:脚本通过 find_project_root() 自动定位 —— 优先 CLAUDE_PROJECT_DIR 环境变量,回退 git rev-parse --show-toplevel。仓库外执行报错。
新项目首次使用:跑一次 scripts/bootstrap_project.py 自动建好骨架。详见下面「触发模式 / /control init」。
🔒 /control status 输出契约(硬规则)
这是为了消除"AI 看到脚本输出后自由排版"的问题。所有 status 类查询的最终呈现以脚本输出为准。
触发条件(任一):
/control list/control status/control <key> status- 用户用同义说法询问任务列表 / 进度 / 现在做到哪儿了 / 给我一个总控任务表
已知失效模式(必读):工具调用的 stdout 在部分客户端界面上会被直接渲染出来,AI 因此容易产生"用户已经看到了,我只需要追加一句结论"的错误判断,转而只输出一行总结(如"下一步可执行 Tn")而跳过表格本身。这个判断是错的——第 2 步要求的是 AI 自己的最终文字回复里包含完整表格,不是"工具输出已展示"就算数。跨模型/跨客户端都会犯这个错,必须靠下面的显式自检堵住,不能靠"应该记得"。
执行步骤:
- 调用
render_control_status.py(带或不带关键词,按触发模式) - 逐字复述脚本 stdout 输出到自己的最终文字回复正文中(不是"已经调用过工具就算展示过"),包含但不限于:
- 块头(
# 总控状态/# 活跃总控) - 派生总体状态行
- 任务统计行
- 顶部附注行(如有)
- 完整子任务总表(所有列:编号 / 子任务 / 状态 / 依赖 / 预期输出)
- 块头(
- 禁止:重排版、合并行、省略列、改列名、调整列顺序、给数据加省略号、把表格转成 bullet list、跨多任务时只输出部分
- 允许:表格之后追加最多一段简短"下一步建议",格式必须从下列固定模板选一条:
- 「下一步可执行:
Tn(依赖已满足)」—— 存在可执行子任务 - 「全部完成,可调用
archive_control.py --apply归档」—— 派生状态 = 已完成 - 「存在阻塞:
Tn,请对应授权角色裁决」—— 派生状态 = 阻塞 - 「未启动,请任务调度负责人决定从哪个子任务开始」—— 派生状态 = 未启动
- 「下一步可执行:
- 用户没有问下一步时,第 4 步可以省略;不主动追加其他解读
- 发送前自检(发送前必做,不可跳过):在写下最终回复的最后一刻,反问自己——"如果去掉我调用的工具,只看我这段文字本身,用户能不能看到完整子任务总表?" 答案是"不能"(比如正文只有"下一步可执行:Tn"这类总结句,表格本身没有出现在文字里)→ 视为本次回复不合格,必须重写,把步骤 2 的完整表格文本真正写入正文后再发送。
错误处理:脚本报错(找不到总控 / 多候选 / 缺列)→ 把脚本的错误原文展示给用户,再询问应该怎么处理;不要"修复式 freestyle"。
触发模式
| 模式 | 作用 |
|---|---|
/control init |
新项目首次使用:建 docs/00-任务总控/ 骨架、追加 .gitignore(幂等) |
/control list |
列出所有活跃总控(最少上下文) |
/control status |
只读查看当前总控状态表 |
/control <关键词> |
进入指定总控,列出可执行子任务,等用户选 |
/control <关键词> Tn |
执行指定子任务(严格边界,支持 Tn.x 二级子任务) |
/control <关键词> status |
查看指定总控状态 |
/control <关键词> split Tn |
把一级父任务 Tn 拆为二级子任务 Tn.1 ~ Tn.N(用户必须先和 AI 对齐边界) |
/control blocked |
列出所有阻塞子任务 |
/control switch |
列出所有活跃总控,交互式让用户选一个写入激活指针 |
/control use <关键词> |
直接按关键词设置激活总控(已知目标时用,比 switch 快) |
/control use --clear |
清除激活配置 |
/control use --show |
显示当前激活配置 |
关键词省略时的目标选择优先级:
- 显式
<关键词>(用户传了就用这个) .claude/local/active-control文件指向的任务(多激活时显式指定)- 唯一兜底:只有 1 个未归档总控时直接选中
- 否则报错列候选,要求加关键词或运行
/control use <key>
多候选时停止并让用户选择。
强制阅读(按粒度递增)
核心原则:触发的命令越具体,读的文件越精准。不要预先读所有文件。
| 触发模式 | 必读文件 | 默认不读(非禁区) |
|---|---|---|
/control init |
无(直接调脚本) | — |
/control list |
<PROJECT_ROOT>/docs/00-任务总控/README.md |
references/总控规范 / 各总控正文 |
/control <key> 或 /control <key> status |
上 + 目标主总控 README.md 的「任务背景」「子任务总表」 | 子任务详情段、其他子任务、references |
/control <key> Tn 或 /control <key> Tn.x |
上 + 该子任务详情 + 它列出的「强制阅读」文件 | 其他子任务详情、references |
/control <key> split Tn |
上 + Tn 父任务详情(用于和用户对齐拆分边界) | 其他子任务详情 |
| 创建新总控 | references/总控规范.md + task-control-doc skill |
— |
| 归档任务 | references/总控规范.md §2.3 + 归档目录索引 |
— |
CLAUDE.md 由会话级注入,不需要再读。
「默认不读」管的是成本,不是禁区:status / list 类只读查询别把全库读一遍。但一旦进入 Tn 执行,执行者可以且应该按需补读——「背景导航」(如有)、其他子任务详情、相关正式文档、代码现状,把背景挖够再动手(见执行流程 §3 与执行边界第 3、6 条)。旧版把「不读」当禁令,是为弱模型防上下文污染设计的;强模型时代背景不足导致误判的代价远大于多读几个文件。
自动化脚本
| 脚本 | 对应触发模式 |
|---|---|
scripts/bootstrap_project.py |
/control init |
scripts/render_control_status.py --list |
/control list |
scripts/render_control_status.py [关键词] |
/control [关键词] status |
scripts/next_subtask.py [关键词] |
/control [关键词](含完整会话启动提示词) |
scripts/next_subtask.py [关键词] --show Tn |
/control [关键词] Tn —— dump 子任务详情段(支持 Tn.x) |
scripts/split_subtask.py <关键词> Tn --subtasks "Tn.1=名1,..." [--apply] |
/control [关键词] split Tn —— 拆分(默认 dry-run) |
scripts/check_write_scope.py ... |
对本子任务候选提交做写入范围与跨任务 Markdown 段检查 |
scripts/list_blocked.py |
/control blocked |
scripts/render_control_status.py --list → 用户选择 → scripts/set_active.py <精确名> |
/control switch |
scripts/set_active.py <关键词> / --clear / --show |
/control use ... |
scripts/archive_control.py <关键词> --version V1 [--apply] |
归档(默认 dry-run) |
SKILL_DIR=~/.claude/skills/control/scripts
# 新项目首次初始化(幂等)
python3 $SKILL_DIR/bootstrap_project.py
# 最少上下文:只列活跃总控
python3 $SKILL_DIR/render_control_status.py --list
# 列指定总控的子任务概览
python3 $SKILL_DIR/render_control_status.py <关键词>
# 推荐下一个可执行子任务(输出含完整会话启动提示词,可复制即用)
python3 $SKILL_DIR/next_subtask.py <关键词>
# Dump 指定子任务详情段全文(用户已知做哪个,直接看完整工作包)
python3 $SKILL_DIR/next_subtask.py <关键词> --show T3
# 阻塞盘点
python3 $SKILL_DIR/list_blocked.py
# 交互式切换激活总控(/control switch)
# 步骤:① 列出所有活跃总控 ② 向用户展示编号列表 ③ 用户选择 ④ 写入指针
python3 $SKILL_DIR/render_control_status.py --list # ① 获取候选列表
# → AI 把列表以编号形式呈现给用户,等待选择
# → 用户选定后执行:
python3 $SKILL_DIR/set_active.py <用户选中的精确目录名> # ④ 写入指针
# 直接按关键词设置激活总控(/control use,已知目标时用)
python3 $SKILL_DIR/set_active.py <关键词>
python3 $SKILL_DIR/set_active.py --show
python3 $SKILL_DIR/set_active.py --clear
# 归档(默认 dry-run)
python3 $SKILL_DIR/archive_control.py <关键词> --version V1 --apply
# 拆分父任务(默认 dry-run,--apply 才写盘)
python3 $SKILL_DIR/split_subtask.py <关键词> Tn \
--subtasks "Tn.1=表设计,Tn.2=接口契约,Tn.3=Migration" \
--reason "Tn 工作量超出预期" --apply
# 子任务交付前:仅检查明确属于本子任务的候选提交
python3 $SKILL_DIR/check_write_scope.py --repo . \
--start-commit <开工SHA> --candidate <候选SHA> \
--allow 'src/目标/**' \
--allow-cross 'docs/00-任务总控/.../README.md::子任务总表'
执行流程
0. /control switch — 交互式切换激活指针
- 运行
render_control_status.py --list获取所有活跃总控 - 若无活跃总控 → 提示先创建,停止
- 若只有一个 → 直接写入,告知用户(无需选择)
- 若有多个 → 以编号列表形式展示给用户(
1. xxx 2. yyy),等待用户回复编号或关键词 - 用户选定后运行
set_active.py <精确目录名>写入.claude/local/active-control - 输出确认:「已将激活总控切换为:xxx」
不读任何总控文档正文,只需
--list输出即可完成全流程。
1. 进入
- 解析触发模式 → 确定需要的最小上下文(见上面的「强制阅读」表)
- 用脚本获取索引信息(
render_control_status.py或next_subtask.py) - 多候选时停止 → 列出候选,让用户选择
- 不要自己解析总控文档——脚本已经处理了
- worktree 不绑定任务——任意 worktree 都可以切换激活总控。多激活时通过
.claude/local/active-control文件确定默认目标,配置不存在且唯一总控时自动兜底
2. 子任务选择
用户没指定 Tn 时的优先级(已固化在 next_subtask.py):
- 状态为
进行中的子任务(恢复未完成工作) - 第一个
待完成且依赖均已已完成的子任务
不跳过未解决的依赖。全部阻塞 → 报告原因并停止。
3. 执行(严格边界)
开始前:
- 子任务状态改为
进行中 - 读取工作包「写入范围」,在第一次写入前把当前提交记为
start_commit;目标路径若较模板发生变化,先修工作包范围再施工,禁止执行后补白名单 - 重新从磁盘读取该子任务详情和「强制阅读」文件——不依赖聊天历史
- 若为 goal 首次启动、恢复、新会话或自动压缩后的续跑,同时读取章程、
T{n}-goal断点.json与飞行日志尾部;先复水再产生任何写入 - 主动补读背景:「背景导航」(如有)、其他子任务详情、相关正式文档、代码现状——把背景挖够再动手,不要仅凭工作包内容硬猜
- 自主补读亲自读(直接读文件 / 检索),不为补背景派子 agent / 起深度调查;背景缺口大到需要专门调查 → 停机向用户报告(工作包没写清,见执行边界第 5、6 条)
- 由用户在新会话开头自行选择模型(不在总控里预定义)
执行中:
- 改动严格限于「要做的事情」描述的范围
- 每个本子任务提交保持单一职责,不夹带无关文件;仓库中的其他提交/工作树变化不自动归给本任务,也不因其存在停机
- 遵守「不做什么」字段(如有)
- 子任务详情有「会话启动提示词」时按它走
- 遵守项目本地的真值优先级与同步规则(项目自身的 CLAUDE.md / AGENTS.md)
完成后:
- 先提交本子任务变更,再把这些精确候选提交逐个传给
check_write_scope.py;越界时回退本子任务内容或补做真实上游范围裁决,禁止事后扩白名单让检查变绿 - 立刻停止,不要继续做下一个子任务
- 回填总控(见下面的「回填」段)
- 向用户报告完成情况,等下一步指令
4. 回填
子任务完成后更新:
- 子任务总表「状态」 →
已完成 - 子任务详情「当前状态」 →
已完成 - 子任务详情「输出物」 → 实际产出文件列表
- 子任务详情「风险与注意事项」 → 新发现的残余风险(如有)
- 总控的「进展记录」追加一行:
- YYYY-MM-DD:[子任务编号] 完成,[简要摘要]
阻塞时设为 阻塞,写明:阻塞什么、为何阻塞、最佳下一步。
5. 派给外部 agent 时
主流路径:用户在新会话执行子任务时,直接复制子任务详情末尾的「会话启动提示词」(或 next_subtask.py 输出末尾生成好的版本)。
如需主线程内 spawn agent(少数场景),prompt 必须注入边界声明(见 references/总控规范.md §4.3):禁止接管任务调度、只做指定编号子任务。
5.5 /control <key> split Tn —— 中途拆分父任务
触发场景:用户在执行过程中发现某个一级任务 Tn 太大、单一会话做不完,需要原地拆为 Tn.1 ~ Tn.N 二级子任务继续推进。
核心约束:
- 只允许两级层次。
Tn.x不能再拆,深层拆要么开新总控、要么改设计 - AI 不可自行决定拆分粒度 —— 必须先与用户对齐:拆几个、各自做什么、依赖顺序
- 用户对齐后才调脚本生成骨架,脚本写完只是占位,子任务详情仍由用户/AI 后续填写
执行流程:
- 用户敲
/control <key> split Tn,或用自然语言"把 T3 拆一下" - AI 读取 Tn 父任务详情(用
next_subtask.py --show Tn),向用户呈现当前状态 - AI 询问用户:要拆为几个子任务、每个子任务负责什么、命名建议是什么
- 用户答复后,AI 重复一次拆分计划让用户确认("拆 T3 为:T3.1=表设计、T3.2=接口契约、T3.3=Migration,理由:T3 工作量超出预期 —— 确认吗?")
- 用户确认后调脚本(默认 dry-run,预览改动):
python3 $SKILL_DIR/split_subtask.py <key> Tn \ --subtasks "Tn.1=...,Tn.2=...,..." \ --reason "..." - dry-run 输出无异常 → 加
--apply真正写盘 - AI 简要报告改动:父任务状态自动派生、子任务骨架已生成、提示用户后续要补全各子任务详情
- 不要顺手开始执行任何子任务 —— 拆分完毕,等用户决定下一步
拆分后的数据语义:
- 父任务 Tn 在总表状态列写
派生,渲染时由脚本聚合子任务实际状态显示 - 原来对 Tn 的依赖(如 T(n+1) 依赖 Tn)保持不变,语义自动变为"所有 Tn.* 完成"
- 父任务不会再被
next_subtask.py推荐执行;只有叶子节点可执行 - 归档校验只看叶子状态;派生父跳过
拒绝场景(脚本会自动报错):
- 拆已完成 / 已取消的任务
- 拆子任务(Tn.x 不可再拆)
- 拆已经被拆过的父任务(不允许"追加",要追加请手动改总表)
- 子任务清单少于 2 个 / 编号不从 .1 起 / 编号不连续
6. 收尾与归档
任务整体完成时(不是子任务完成时) → 用户确认后调脚本:
python3 ~/.claude/skills/control/scripts/archive_control.py <关键词> --version V1 --apply
脚本自动同步索引并迁移目录到 归档/V{x}/。归档前会校验所有子任务必须为 已完成 或 已取消。
如该任务有专属 worktree,归档完后手动 git worktree remove。
任务被明确删除/放弃 → 见 references/总控规范.md §2.4(手动操作,不进归档)。
回复用户
摘要应包含:
- 目标总控文档 + 子任务编号
- worktree 状态(如适用)
- 改了什么 / 没改什么(突出边界遵守)
- 残余风险(如有)
- 建议下一步(不要主动接着做)