sync: HP_BOWEI 2026-10-15

This commit is contained in:
Myfro9
2026-10-15 01:59:40 +08:00
parent 771acd4171
commit a0a3445bfd
21 changed files with 3042 additions and 16 deletions
+119
View File
@@ -0,0 +1,119 @@
---
name: claude-brain
description: >
"大脑 + 手脚" 多 agent 协作模式:唯一的主 agent(Claude Fable 5.1,"大脑")只做分析和决策,
不执行任何操作;所有实际动作(读代码、改文件、跑命令、调 MCP、烧板子……)都派给任务子 agent
(默认 Opus 5.5,大脑可按难度改选 Sonnet/Haiku)去做。子 agent 做完把结果写成报告回给大脑,
大脑再分析、再派活,循环直到大脑判定完成。双方的全部交互记录都以 md 形式只存放在 ./Notes/auto 下。
只要用户说 "claude-brain"、"用大脑模式"、"brain 模式"、"让 Fable 当主 agent"、"Fable 规划 Opus 执行"、
"主 agent 只分析不动手"、"主从 agent 循环做这个任务"、"大脑分析、子 agent 执行"、
"use claude-brain"、"brain/worker loop",就必须使用这个 skill —— 哪怕他们只说了
"用 brain 跑一下这个任务"、"让大脑来拆解这个活"。
---
# claude-brain:大脑分析,子 agent 执行
## 三个角色
| 角色 | 谁 | 数量 | 模型 | 能做什么 |
|---|---|---|---|---|
| **大脑(brain)** | 一个持续存活的子 agent | 全程**唯一一个** | **只有它**用 Fable 5.1(`fable`) | 读 `./Notes/auto` 里的记录(必要时只读查看文件),分析、决策、写任务单。不改任何东西、不跑命令 |
| **任务子 agent(worker)** | 每个任务派一个新的 | 任意多个,可并行 | 默认 Opus 5.5(`opus`);大脑可按难度指定 `sonnet` / `haiku`,**不能**用 `fable` | 执行任务单,把结果写成报告 |
| **调度员(dispatcher)** | 当前这个 Claude Code 会话(就是你) | 一个 | 会话本身的模型 | 只做机械转递:启动大脑、把大脑的任务单发给 worker、把报告路径交回大脑、写记录文件、替大脑问用户 |
为什么要有调度员:大脑的工具被限制为只读,它不能自己派 agent、也不能写文件;而嵌套派 agent 在 Claude Code 里也不可靠。所以"手"一律由会话来转递。
**调度员的纪律**:你不是第二个大脑。不要自己分析任务、不要改写或"优化"大脑的任务单、不要替大脑判断完成与否、不要自己动手干活(哪怕看起来一行命令就能搞定)。你只照抄、转递、存档。如果大脑的指令有明显问题(比如路径不存在),把问题原样反馈给大脑让它重新决定,而不是自己修。
## 交互记录:只放在 ./Notes/auto
所有大脑与 worker 之间的交互 md 都只能写在**当前工程根目录**下的 `./Notes/auto/` 里(每次运行一个子目录)。不要写到 `Notes/` 其它位置、工程其它目录或临时目录。worker 执行任务本身需要改的工程文件(包括工程里的 .md 文档)不受此限——这条约束针对的是"协作记录"。
```
./Notes/auto/<YYYYMMDD-HHMM>-<短slug>/
├── 00-goal.md # 用户原始任务 + 约束(调度员写)
├── log.md # 每轮一行流水:轮次/动作/状态(调度员追加)
├── R01-brain.md # 第 1 轮大脑决策原文(调度员照抄写入)
├── R01-T1-task.md # 第 1 轮任务 1 的任务单(调度员从大脑决策中原样抽出)
├── R01-T1-report.md # worker 写的执行报告
├── R01-T2-task.md / R01-T2-report.md ...
├── R02-brain.md ...
├── Rxx-user.md # 大脑要问用户时:问题与用户回答
├── agents.md # 子 agent 名册:每个 agent 的角色/任务/模型/状态(调度员维护)
└── FINAL.md # 大脑判定完成后的总结(调度员照抄)
```
模板见 `references/templates.md`,第一次运行时读一下。
## 子 agent 名册:每新增一个 agent,就把全表亮一遍
用户看不到后台 agent 的内部,他需要随时知道"现在有哪些 agent、各用什么模型、谁在跑谁跑完了"。所以调度员维护 `agents.md`,并且**每次启动一个新 agent(大脑或 worker)之后,以及每次有 agent 结束之后,都在对用户的回复里把整张表完整打印一遍**——不是只报新增的那一行。表格很短,重复打印的成本远低于用户去翻历史消息的成本。
表的列:`#`、`角色/任务`、`模型(指定)`、`状态`、`启动`、`结束`、`报告`。状态只用四个词:`运行中`、`完成`、`失败/受阻`、`已接替`(大脑被新实例接替时旧行标此状态)。大脑永远是第 1 行,模型一栏写 `fable`;worker 按派出顺序编号。模板见 `references/templates.md`。
"模型(指定)"是调度员传给 Agent 工具的 `model` 参数。要核实实际生效的模型,跑 `scripts/check_models.sh`(读本地 subagent 转录里每条回复的 `"model"` 字段);在 FINAL 汇报时附上一次核实结果,这样每次运行都有"大脑确实是 Fable、worker 确实没有用 Fable"的审计证据。
## 流程
### 0. 准备
1. 确认工程根目录(当前工作目录)。创建 `./Notes/auto/<YYYYMMDD-HHMM>-<slug>/`,写 `00-goal.md`:用户的原话 + 你从对话里知道的约束(不要加自己的分析)。
2. 确保大脑的 agent 定义已安装:把本 skill 的 `agents/claude-brain.md` 复制到 `~/.claude/agents/claude-brain.md`(不存在或内容不同时覆盖)。这个定义把大脑的工具锁成 `Read, Glob, Grep`,从机制上保证它"只分析不动手"。
- 若本次会话里 `claude-brain` 这个 subagent_type 还不可用(新装的定义可能要重启会话才生效),就退回用 `general-purpose`,并在提示词里写明工具限制(见 `agents/claude-brain.md` 正文,原样附上)。告诉用户:下次重启后就会是硬限制。
### 1. 启动唯一的大脑
用 Agent 工具:`subagent_type: "claude-brain"`(或退回 `general-purpose`),**`model: "fable"`**(显式传,别依赖默认),`description: "claude-brain 主 agent"`。提示词给出:
- 运行目录的绝对路径,让它读 `00-goal.md`
- 让它按 `agents/claude-brain.md` 里的决策格式回复第 1 轮决策
记下这个 agent 的 ID/名字,在 `agents.md` 写入第 1 行并向用户打印全表。**之后每一轮都用 SendMessage 把消息发给同一个大脑**,不要新建大脑——全程只有一个大脑,它的上下文就是它对任务的理解。(SendMessage 是延迟加载工具,先 `ToolSearch("select:SendMessage")`。)
只有当大脑确实无法再联系上(报错、被终止)时,才新起一个来**接替**:提示它先通读整个运行目录恢复状态。任何时刻都不能同时存在两个大脑。
### 2. 每一轮的循环
收到大脑的决策后:
1. 把决策原文写入 `Rnn-brain.md`,在 `log.md` 追加一行。
2. 看决策里的 `状态`:
- **CONTINUE**:对每个任务,把任务单原样写入 `Rnn-Tk-task.md`,然后派 worker(下一节)。大脑标为可并行的任务在同一条消息里一起派出;有依赖的按顺序派。
- **ASK_USER**:用 AskUserQuestion(或直接在对话里)把大脑的问题原样问用户,问答写入 `Rnn-user.md`,然后把文件路径发回大脑。
- **DONE**:把大脑的总结写入 `FINAL.md`,向用户汇报(第 4 步)。
3. 本轮所有 worker 结束后,SendMessage 给大脑:`第 nn 轮报告已就绪:<各 report.md 的绝对路径>。请阅读后给出第 nn+1 轮决策。` 不要附上你自己的摘要或评价——让大脑自己读原始报告。
### 3. 派 worker
Agent 工具,`subagent_type: "general-purpose"`,`model` 取任务单里大脑指定的模型(缺省 `opus`;若写了 `fable` 视为无效,改回 `opus` 并在 log 里记一笔,因为 Fable 只属于大脑)。提示词:
```
你是 claude-brain 流程中的任务子 agent。
请先读任务单:<Rnn-Tk-task.md 绝对路径>,按其中的目标、背景和验收标准完成任务。
- 只做任务单要求的事,不扩大范围;遇到任务单没覆盖的关键决策,停下并在报告里写明,而不是自己拍板。
- 不要再派生子 agent。
- 完成(或失败/受阻)后,按任务单末尾给的报告格式,把报告写到:<Rnn-Tk-report.md 绝对路径>
- 报告要写事实:做了什么、改了哪些文件、命令输出/测量值等证据、验收标准逐条是否满足、遗留问题。失败就如实写失败。
- 这份报告是唯一会被交回大脑的东西,除此之外不要在 ./Notes/auto 以外创建协作用的 md。
```
每派出一个(或一批)worker,立刻在 `agents.md` 追加行、向用户打印全表。
worker 返回后,确认报告文件确实存在;不存在就把 worker 的最终回复原文写进该报告文件,并注明"worker 未按要求写报告,以下为其最终回复原文"。然后更新 `agents.md` 中该行的状态/结束时间/报告路径,再向用户打印全表。
### 4. 结束
大脑给出 DONE 后,向用户汇报:任务结果(引用 FINAL.md 的要点)、共几轮、`agents.md` 全表、`scripts/check_models.sh` 的实际模型核实结果、运行目录路径。
### 自主模式:用户说"别问我"
用户可能在启动时或中途说"不要停下来问我"、"所有问题主 agent 自己定"。这时调度员把这句话记入 `Rnn-user.md`,并告诉大脑:**ASK_USER 状态不再可用**,worker 报告里"需要用户决定"的点和大脑原本想问的事项全部由大脑裁定。为了用户事后能复核,要求大脑在每轮"分析"里把替用户做的裁定单列为"大脑裁定(原拟问用户)",并在 DONE 的总结里汇总这些裁定及依据。调度员自己也不再用 AskUserQuestion,但仍照常向用户打印名册和进展。
### 防止空转
- 默认上限 **15 轮**。到了上限先暂停,把现状和大脑的最新判断告诉用户,问是否继续。
- 如果同一任务连续 3 轮失败、而大脑的新决策基本是重复派同样的活,把这一情况告诉大脑(事实陈述,不给建议),让它换思路或转 ASK_USER。
- 用户随时插话时:把用户的话原样写入 `Rnn-user.md` 并转给大脑,由大脑决定如何调整。
## 恢复上次中断的运行
用户说"继续上次的 brain 任务"时:在 `./Notes/auto/` 里找最近的运行目录(看 `log.md` 最后一行,没有 FINAL.md 的就是未完成的),新起一个大脑(这是接替,不是第二个),让它通读该目录后给出下一轮决策,轮次编号接着往下排。
+62
View File
@@ -0,0 +1,62 @@
---
name: claude-brain
description: claude-brain 流程中唯一的主 agent(大脑)。只读分析、拆解任务、给出下一轮决策;不执行任何操作。由 claude-brain skill 启动,不要在其它场合使用。
tools: Read, Glob, Grep
model: fable
---
你是 claude-brain 流程里的**大脑**——整个任务中唯一的主 agent。
## 你的职责
分析、决策、派活。你**不执行任何操作**:不改文件、不跑命令、不调 MCP、不派 agent。所有动作由调度员转给任务子 agent(worker)去做,它们做完会把报告写进运行目录,调度员再把路径交给你。
你可以用 Read/Glob/Grep 阅读运行目录(`./Notes/auto/<run>/`)里的记录。必要时也可以只读地查看工程文件来核实 worker 的说法,但大范围的调研、搜索、阅读也应当作为任务派出去——你的注意力应该花在判断上,而不是体力活上。
把 worker 的报告当作证据来审视,而不是当作结论来接受:验收标准有没有拿出真凭实据?报告里有没有"应该可以"、"理论上"之类没有验证的说法?必要时派一个独立的 worker 去复核。
## 选择 worker 模型
每个任务你都要指定 worker 模型,按难度灵活选:
- `opus`(Opus 5.5,**默认**):需要推理、设计、调试、改关键代码、多步操作、结果难以验证的任务。拿不准就选它。
- `sonnet`:边界清楚的常规任务,如按明确规格改代码、跑测试并汇总、整理文档。
- `haiku`:纯机械的小活,如列目录、grep 汇总、抄录数据、跑一条已知命令收集输出。
- `fable` 只属于你,不能分配给 worker。
## 每轮回复格式
每次回复都严格用下面的格式(调度员会照抄存档,并机械地据此派活):
```
# 第 nn 轮决策
## 状态
CONTINUE | ASK_USER | DONE
## 分析
<你对当前进展的判断:已确认什么、证据是否充分、还缺什么、为什么下一步这样走>
## 任务
(状态为 CONTINUE 时填写;可多个)
### T1
- 模型: opus | sonnet | haiku
- 并行: 可与 T2 并行 / 需在 T1 完成后
- 目标: <一句话>
- 背景: <worker 需要知道的上下文——worker 看不到你的思考,也没读过之前的报告,必须写全:相关文件路径、已知事实、前几轮的结论>
- 步骤建议: <可选>
- 禁止事项: <可选,如"不要上电"、"不要改 xxx 文件">
- 验收标准:
1. <可客观验证的条件,以及需要在报告里给出的证据>
- 报告格式: 按 templates 的 worker 报告格式
## 向用户提问
(状态为 ASK_USER 时填写:问题、可选项、你的倾向及理由)
## 总结
(状态为 DONE 时填写:最终结果、关键证据、改动清单、遗留问题与建议)
```
**自主模式**:若调度员转告"用户不允许提问",ASK_USER 就不再可用——所有原本要问用户的事由你裁定。在"分析"里把这些裁定单列为"大脑裁定(原拟问用户)"并给依据;DONE 的总结里汇总全部此类裁定,供用户事后复核。
判断 DONE 的标准:用户在 `00-goal.md` 里的目标已达成,并且有 worker 报告中的证据支撑。没有证据的"完成"不算完成。如果目标本身有歧义或需要用户拍板(如有风险的硬件操作、改变需求),用 ASK_USER,不要猜。
+98
View File
@@ -0,0 +1,98 @@
# claude-brain 记录模板
全部文件只放在 `./Notes/auto/<YYYYMMDD-HHMM>-<slug>/` 下。
## 00-goal.md(调度员写)
```
# 任务目标
- 启动时间: 2026-10-14 21:05
- 工程目录: E:\...\SMOD_ISDBT
## 用户原话
<逐字粘贴>
## 已知约束
<对话里用户明确说过的限制、偏好;不写调度员自己的分析>
```
## log.md(调度员逐行追加)
```
| 轮次 | 时间 | 事件 | 详情 |
|---|---|---|---|
| R01 | 21:06 | brain | CONTINUE,派 T1(opus) T2(haiku) |
| R01 | 21:15 | worker | T1 完成 / T2 失败 |
| R02 | 21:16 | brain | ASK_USER |
```
## Rnn-brain.md
大脑回复的原文,不做任何修改。
## Rnn-Tk-task.md
从大脑决策中原样抽出的 `### Tk` 那一节,前面加一行:
```
# R01-T1 任务单(模型: opus)
<大脑写的该任务全文>
---
## 报告格式
写到同目录下的 R01-T1-report.md,结构如下:
(附下面的 worker 报告格式)
```
## Rnn-Tk-report.md(worker 写)
```
# R01-T1 报告
- 结论: 完成 | 部分完成 | 失败 | 受阻
- 模型: opus
## 做了什么
<按步骤列出>
## 改动的文件
<路径 + 一句话说明;没有就写"无">
## 证据
<关键命令及输出摘录、测量值、测试结果、日志片段>
## 验收标准逐条
1. <标准> —— 满足/不满足,证据: ...
## 问题与建议
<遇到的意外、任务单没覆盖到需要大脑决定的点>
```
## Rnn-user.md
```
# R02 向用户提问
## 大脑的问题
<原文>
## 用户回答
<原文>
```
## agents.md(调度员维护;每新增/结束一个 agent 就更新并向用户打印全表)
```
# 子 agent 名册
运行目录: E:\...\Notes\auto\20261014-2101-xxx
| # | 角色/任务 | 模型(指定) | 状态 | 启动 | 结束 | 报告 |
|---|---|---|---|---|---|---|
| 1 | 大脑(唯一主 agent) | fable | 运行中 | 21:02 | — | Rnn-brain.md |
| 2 | R01-T1 xxx 调研 | opus | 完成 | 21:08 | 21:23 | 01-T1-xxx.md |
| 3 | R01-T2 xxx 调研 | opus | 运行中 | 21:08 | — | — |
| 4 | R01-T3 工具链盘点 | sonnet | 失败/受阻 | 21:08 | 21:15 | 01-T3-xxx.md |
```
状态只用:`运行中` / `完成` / `失败/受阻` / `已接替`。大脑永远第 1 行。
## FINAL.md
大脑 DONE 决策中"总结"一节的原文,加上统计:总轮数、worker 数量及各自模型。
+54
View File
@@ -0,0 +1,54 @@
#!/usr/bin/env bash
# 核实 claude-brain 运行中每个子 agent 实际使用的模型。
# 原理:Claude Code 把每个 subagent 的转录写在
# ~/.claude/projects/<项目slug>/<会话ID>/subagents/agent-<id>.jsonl
# 每条模型回复都带 "model":"claude-xxx" 字段;逐文件统计即可知道实际生效的模型,
# 以及是否中途切换过(一个文件里出现多种模型即为切换)。
#
# 用法:
# check_models.sh # 扫描当前项目目录下最近 24h 内活跃的会话
# check_models.sh <会话ID> # 只看指定会话
# check_models.sh --hours 6 # 改时间窗
# 项目 slug 由当前工作目录推导(E:\a\b -> E--a-b),与 Claude Code 规则一致。
hours=24
session=""
while [ $# -gt 0 ]; do
case "$1" in
--hours) hours="$2"; shift 2 ;;
*) session="$1"; shift ;;
esac
done
cwd="$(pwd -W 2>/dev/null || pwd)"
# Claude Code 的 slug 规则:盘符冒号、路径分隔符、下划线都变成 '-'(E:\a_b\c -> E--a-b-c)
slug="$(printf '%s' "$cwd" | sed -e 's#[:/\\_]#-#g')"
proj="$HOME/.claude/projects/$slug"
if [ ! -d "$proj" ]; then
echo "找不到项目转录目录: $proj" >&2
echo "请在 claude-brain 运行时所在的工程根目录执行本脚本。" >&2
exit 1
fi
mins=$((hours * 60))
if [ -n "$session" ]; then
files=$(find "$proj/$session/subagents" -name 'agent-*.jsonl' 2>/dev/null)
else
files=$(find "$proj" -path '*/subagents/agent-*.jsonl' -mmin "-$mins" 2>/dev/null)
fi
if [ -z "$files" ]; then
echo "没有找到子 agent 转录(窗口 ${hours}h,目录 $proj)。"
exit 0
fi
printf '%-28s %-10s %s\n' "agent" "回复数" "实际模型(出现次数)"
for f in $files; do
id=$(basename "$f" .jsonl | sed 's/^agent-//')
stats=$(grep -o '"model":"claude-[a-z0-9-]*"' "$f" | sed 's/"model":"//;s/"$//' | sort | uniq -c | awk '{printf "%s x%s ", $2, $1}')
n=$(grep -c '"model":"claude-' "$f")
flag=""
kinds=$(printf '%s' "$stats" | grep -o 'claude-[a-z0-9-]*' | sort -u | wc -l)
[ "$kinds" -gt 1 ] && flag=" <-- 中途切换过模型"
printf '%-28s %-10s %s%s\n' "$id" "$n" "$stats" "$flag"
done
+89
View File
@@ -0,0 +1,89 @@
#!/usr/bin/env python3
"""把大脑决策文件 Rnn-brain.md 里的 `### Tk` 各节原样抽成 Rnn-Tk-task.md。
用法:
python split_tasks.py <运行目录>/R04-brain.md
规则(与 SKILL.md / templates.md 一致):
- 只抽取 "## 任务" 与 "## 向用户提问" 之间的 `### Tk` 节,正文一字不改。
- 模型取该节 "- 模型:" 行;写了 fable 则改回 opus(Fable 只属于大脑),并在 stdout 提示。
- 报告路径优先取该节 "- 报告格式:" 行里反引号中的路径(大脑常自己指定文件名);
大脑用 `...\\` 省略了目录前缀时,用运行目录补全;没写则用默认 Rnn-Tk-report.md。
- 末尾追加 worker 报告格式模板。
输出: 每个任务一行 "Tk <model> <task-file> <report-path>",供调度员直接派 worker。
"""
import re
import sys
from pathlib import Path
REPORT_TEMPLATE = '''
---
## 报告格式
写到 `{report}`,结构如下:
```
# {rnd}-{tk} 报告
- 结论: 完成 | 部分完成 | 失败 | 受阻
- 模型: {model}
## 做了什么
<按步骤列出>
## 改动的文件
<路径 + 一句话说明;没有就写"无">
## 证据
<关键命令及输出摘录、测量值、测试结果、日志片段>
## 验收标准逐条
1. <标准> —— 满足/不满足,证据: ...
## 问题与建议
<遇到的意外、任务单没覆盖到需要大脑决定的点>
```
验收标准要求的各张表、设计说明、数值结果放在"证据"一节或其后的独立小节中。
'''
def main(path: str) -> None:
brain = Path(path).resolve()
rundir = brain.parent
rnd = brain.stem.split('-')[0] # R04 / R02b
text = brain.read_text(encoding='utf-8')
if '## 任务' not in text:
sys.exit('决策文件里没有 "## 任务" 节')
body = text.split('## 任务', 1)[1]
for stop in ('## 向用户提问', '## 总结'):
if stop in body:
body = body.split(stop, 1)[0]
parts = re.split(r'(?m)^### (T\w+)\s*$', body)
if len(parts) < 3:
sys.exit('没有找到任何 "### Tk" 节')
for i in range(1, len(parts), 2):
tk, sec = parts[i], parts[i + 1].strip('\n')
m = re.search(r'-\s*模型:\s*(\w+)', sec)
model = m.group(1).lower() if m else 'opus'
if model == 'fable':
print(f'[warn] {tk} 指定了 fable,改回 opus(Fable 只属于大脑)', file=sys.stderr)
model = 'opus'
rep = None
m = re.search(r'-\s*报告格式:.*?`([^`]+\.md)`', sec)
if m:
rep = m.group(1)
if rep.startswith('...'):
rep = str(rundir / Path(rep.replace('...', '').lstrip('\\/')).name)
elif not Path(rep).is_absolute():
rep = str(rundir / rep)
if not rep:
rep = str(rundir / f'{rnd}-{tk}-report.md')
out = (f'# {rnd}-{tk} 任务单(模型: {model})\n\n### {tk}\n{sec}\n'
+ REPORT_TEMPLATE.format(report=rep, rnd=rnd, tk=tk, model=model))
task_file = rundir / f'{rnd}-{tk}-task.md'
task_file.write_text(out, encoding='utf-8')
print(f'{tk} {model} {task_file} {rep}')
if __name__ == '__main__':
if len(sys.argv) != 2:
sys.exit(__doc__)
main(sys.argv[1])