- name
- workflow-graph
- description
- 把有多个执行者(人、模型、脚本)参与的工作流设计成能运行的图:循环、节点、交接物、回边、闸门、三个指标,附术语表和交付模板。设计或改造开发流程、agent 编排、审查流程时加载;用户拿来一张编排图或工作流 prompt 要套到自己的流程上时也用。只改单个任务、不动流程结构时不用。
# workflow-graph
本 skill 是通用做法,不针对某个项目。它说明怎样把一条反复要做、有多个执行者(人、模型、脚本)参与的工作流,画成一张能运行的图,以及图运行时谁做什么。只读本 skill 就能设计、运行和调整这样的图,不需要别的文件。
全文用同一个例子:**处理 bug 报告**——有人报了 bug,要确认、修好、审查、合并、发布。
## 1. 术语
| 术语 | 定义 | 例子 |
|---|---|---|
| 工作流(workflow) | 为一个目标反复执行的一串工作 | 处理 bug 报告 |
| 执行者(executor) | 做一件事的人、模型或脚本。写模型时连推理档位一起写 | 用户;强模型 high;便宜模型 medium;测试脚本 |
| 推理档位 | 模型每次回答前思考多深的设置,常见取值 low / medium / high。档位越高越慢、越贵,推理越充分 | — |
| 执行者状态 | 执行者此刻处在哪一种:**在干活**、**等下一条指令**、**等审批**(停在一个要人决定的问题上,例如工具权限确认、需求澄清、发布确认)、**已退出**。由执行者运行环境的事件得出(进程退出、钩子触发、输入框空着),不以执行者自己的宣称为准 | 修复模型跑完测试后停在空输入框 → 等下一条指令 |
| 控制者 | 此刻能向一个节点输入内容的那一个执行者 | 修复节点的控制者是主控;它等审批时,控制者是用户 |
| 主控(orchestrator) | 运行这张图的执行者:派活、接收交接物、判断闸门、走回边、记录、向用户汇报 | 一个主会话里的强模型 |
| 顾问(advisor) | 比主控更强的模型,能看到主控的全部记录。只在固定时点(第 3 节)给意见,不写代码、不做决定 | — |
| 作者、审查者 | 作者产出交接物,审查者检查它。同一份产出,作者和审查者不能是同一个执行者 | 修复的作者是编码模型,审查者是主控 |
| 记录(log) | 每发生一件事(开始、交付、提问、回答、卡住、过闸门、退回、移交、完成)就写一行事实,格式见第 6 节。只写观察到的事实;进度、状态这类展示用的结论在读的时候从事实算出来,不另外存一份 | 第 6 节的示例 |
| 循环(loop) | 一件窄活的重复结构,由四部分组成:**触发**(什么让它开始)、**动作**(只做这一件事)、**检查**(怎么知道做完了,必须能观察到:命令的结果、文件里的一行、某人的一句"可以"。判断"做完了"时,优先用运行环境发出的信号(进程退出、钩子事件、约定的文件出现),其次才是执行者自己写的完成标记;运行环境没有这类信号时,就用完成标记,同时设超时和空闲判定(规则 11),因为执行者可能忘了写;产出好坏要靠判断时,把标准写成逐条能答"是/否"的清单,交给另一个执行者逐条判断)、**停止**(最多重试几次,到了交给谁) | 修复:触发=收到任务说明;动作=改代码加测试;检查=新测试修复前失败、修复后通过;停止=3 次不过就交回主控 |
| 节点(node) | 图里的一个点:一个循环,加上它的目的、输入、输出、执行者和可用工具 | "修复"节点 |
| 交接物(artifact) | 一个节点交给下一个节点的东西,格式固定(文件、提交、表格),写明结论、证据、没验证的地方和做过的假设 | 修复报告:改了什么、测试结果、没验证的地方 |
| 交接(edge) | 两个节点之间的一条连线,带着一种交接物,每次交接都留记录 | 修复 → 审查,带修复报告 |
| 回边(back edge) | 检查不通过时,交接物退回**造成问题的那个节点**,附具体发现和复现方法 | 审查发现 bug → 退回修复节点,不是由审查者自己改 |
| 闸门(gate) | 交接通过前必须满足的条件。两种:**分数闸门**(可量化的条件加阈值,由主控或脚本判断)和**人工闸门**(等一个具体的人确认)。闸门批准的是交接物的一个具体版本(提交号、文件哈希),通过时记下这个版本;之后版本变了,闸门重新判断 | 合并前:测试全过、审查无阻塞问题,合并的就是审查过的那个提交 |
| 阈值(threshold) | 分数闸门的数字。来自自己过去的记录,不是凭感觉定,并写明依据 | "退回超过 3 轮就停",依据是过去几次超过 3 轮后改进很少 |
| 不可逆动作 | 对外的或撤不回的动作:发消息或邮件、对外发布、推送到别人共用的地方、付款、删除数据 | 发布新版本 |
| 移交(hand-off) | 循环到了停止条件,把问题连同已有的证据交给停止条件写明的那个执行者 | 修复 3 次不过 → 交给主控决定拆小或改说明 |
| 三个指标 | 判断这张图运转好坏要盯的三个数(第 5 节) | — |
## 2. 规则
这些规则在设计和运行时都适用。
1. **循环在节点里,图在节点之间。** 节点内部自己重试,直到检查通过或停止;节点之间只通过交接物往来。
2. **节点少、职责窄。** 每个节点只做一件事。只是转手、不改变内容的节点删掉。去掉一个节点后三个指标不变差,就去掉它。
3. **审查者不审自己的产出。** 主控自己写了东西(接手了任务、合并时改了代码),就交给另一个执行者审。
4. **能用代码判断的交给代码。** 测试过没过、格式对不对、文件在不在、数字有没有超阈值,由脚本判断;只有需要权衡的才交给模型。
5. **强模型只用在推理会改变结果的地方。** 判断标准:换成便宜模型后,产出的对错或质量会不会明显变差。会变差的(设计、拆任务、审查复杂状态、处理分歧、要权衡意图和语气的写作)用强模型;有明确对错标准、重复的活用便宜模型或脚本。拿不准时先用便宜模型,按三个指标看结果再换。
6. **不可逆动作前一定有人工闸门。** 能撤回的动作可以用分数闸门。
7. **假设写出来。** 每份交接物都写"做了哪些假设、哪些没验证",接收方据此决定要不要补查。
8. **失败要看得见。** 检查不过就走回边或移交,并说明原因;检查偶发失败时查出原因修掉,以第一次的结果为准,不靠重跑到通过;不跳过检查,也不悄悄换一种做法。
9. **每个决定都记一行。** 过闸门、退回、移交都写进记录,并带上依据的数字;记录的格式见第 6 节。
10. **一个节点同一时刻只有一个控制者。** 换控制者是交接:先让旧的停下,新的再接手。执行者等审批时,控制者是那个要做决定的人,这期间节点的输入只来自这个人;其他人和自动化看到节点输入框里有没发出的内容时,留给控制者处理。
11. **"空闲"要反复观察才算。** 在一段观察窗口内连续几次看到它停着、没有新输出,才判定它停下了,一次观察不算。窗口多长、看几次,和阈值一样从记录里定,没有记录时标"待校准"。超时只设给"看起来停了、但还没确认完成"的执行者;正在干活的、在等人决定的,不设时限。
## 3. 运行时:主控、回边和顾问
主控的循环:
```
收到触发 → 派给第一个节点
→ 收到交接物 → 判断闸门
通过 → 交给下一个节点
不通过 → 走回边,退回造成问题的节点(附发现和复现方法)
→ 某个节点到了停止条件 → 主控处理移交:
改任务说明 / 拆小 / 换执行者 / 自己接手(自己接手时,审查交给别的执行者,规则 3)
→ 定期观察外部事实(测试结果、审查意见、合并冲突)→ 判断是不是需要处理的反馈 → 是就走回边交给造成它的节点
→ 到了人工闸门 → 停下,给那个人一份能直接拍板的摘要(做了什么、为什么、证据在哪)
→ 最后一个节点完成 → 记录 → 汇报
```
顾问只在三个时点调用,日常步骤不调用:
| 时点 | 什么时候算 |
|---|---|
| 定计划之前 | 读完需要的材料之后、写任务说明或拆任务之前 |
| 同一个问题第二次出现 | 同一条审查发现第二次退回;同一个错误第二次出现;方案迟迟收不拢 |
| 宣布完成之前 | 过最后一道闸门之前(例如合并、汇报)。先把成果落盘(提交、写文件),再问 |
顾问的意见和主控查到的证据冲突时,主控带着证据再问一次,再决定。不在冲突时悄悄换方向。
## 4. 设计一张图
按顺序做六步。每步都有完成标准,达不到就不进入下一步。
### 第 1 步:盘点现状
把今天手工完成这条工作流的路径逐步写下来,标出哪些步骤重复、哪里有分支、哪里在等人。写出三样东西:目标、瓶颈、一个最应该改善的数字(附当前值)。
完成标准:路径上每一步都写了执行者;那个数字有当前值,或者写明从今天开始怎么记录。
### 第 2 步:找出循环
把每件重复的活写成一个循环:触发、动作、检查、停止。
停止次数和闸门阈值一样从自己的记录里定(第 5 步);还没有记录时,先写 3 次并标"待校准"。
完成标准:每个检查都能观察到(一条命令、一个文件、一个人的确认,或一份逐条判断的清单);每个停止条件都有次数(或"待校准"标记),并写明交给谁。
### 第 3 步:给循环配节点
每个循环成为一个节点,写明目的、输入、输出、执行者(模型和档位)和工具。按规则 4、5 选执行者。
完成标准:每个节点的输入都来自某条交接或某个触发;每个选了强模型的节点都写了理由。
### 第 4 步:画交接
每次交接画一条边,写明交接物和它的格式。每个可能不通过的检查都画回边,指向造成问题的节点。
完成标准:每个检查的失败都有回边;没有只转手的节点;每种交接物的格式都写明了。
### 第 5 步:设闸门
在每个不可逆动作前设人工闸门,在每个"产出要被别人接着用"的地方设分数闸门。阈值从自己的记录里定:翻过去的记录,选一个能拦住过去的坏结果、又放过好结果的数,把依据写下来。还没有记录时,先写一个临时值,标"待校准",记满一批后再定。
完成标准:每个不可逆动作都有人工闸门并写明是谁;每个分数闸门都有数字和依据(或"待校准"标记);每个闸门都写明它批准的是交接物的哪个版本。
### 第 6 步:分阶段上线
| 阶段 | 做什么 |
|---|---|
| 1 | 只跑一个循环,手工驱动,确认检查和停止条件真的有效 |
| 2 | 两个节点加一条交接,确认交接物够下一个节点直接开工 |
| 3 | 加上闸门 |
| 4 | 整张图跑起来,每个决定都按规则 9 记录 |
完成标准:每个阶段都在一个真实任务上跑通过一次,问题已改进设计。
## 5. 交付模板
设计完成时交出下面几张表。示例行用的是"处理 bug 报告"。
**循环表**
| 循环 | 触发 | 动作 | 检查 | 停止 |
|---|---|---|---|---|
| 修复 | 收到任务说明 | 改代码、加测试 | 新测试修复前失败、修复后通过;全部测试通过 | 3 次不过 → 交主控 |
**节点表**
| 节点 | 目的 | 输入 | 输出 | 执行者 | 工具 |
|---|---|---|---|---|---|
| 修复 | 让 bug 不再出现 | 任务说明 | 提交 + 修复报告 | 编码模型 high | 编辑器、测试 |
**交接表**(回边单独标出)
| 从 | 到 | 交接物 | 格式 | 回边? |
|---|---|---|---|---|
| 修复 | 审查 | 修复报告 | 改了什么、测试结果、假设、没验证的地方 | 否 |
| 审查 | 修复 | 审查发现 | 每条:严重程度、位置、复现方法 | 是 |
**闸门表**
| 闸门 | 位置 | 条件 | 批准的版本 | 阈值和依据 | 谁判断 |
|---|---|---|---|---|---|
| 合并 | 审查 → 合并 | 测试全过、审查无阻塞问题 | 审查时的提交号 | 全过;不允许"重跑通过" | 主控(脚本出结果) |
| 发布 | 合并 → 发布 | 用户确认 | 要发布的版本号 | 不可逆 | 用户 |
**三个指标**:选三个能说明图运转好坏的数,写明怎么算、在哪记。常用的三个:
| 指标 | 怎么算 | 说明什么 |
|---|---|---|
| 漏网问题 | 过了所有闸门之后才发现的严重问题个数 | 检查和闸门够不够严 |
| 退回轮数 | 每个任务被回边退回的次数 | 任务说明和执行者是否合适 |
| 周期 | 从触发到最后一道闸门的时长 | 图里有没有卡住的地方 |
**何时调整这张图**:某个指标连续变差;某个节点从不改变结果(规则 2);同一个停止条件反复触发。调整也按第 4 节的步骤走,并把原因记一行。
## 6. 记录的格式
记录是工作流根目录(这条工作流的所有执行者都能读写的那个共同目录,例如代码仓库的根目录)下的一个文件 `.workflow/log.jsonl`:每行一个 JSON 对象,表示一条事实,只追加,不修改、不删除。谁做了这件事谁写;执行者的运行环境没有可观察的信号、或者执行者不方便写时,由观察到它的执行者(通常是主控)代写,并在 `by` 里写真正做事的那个执行者。用什么写由工作流自己定(脚本、命令行工具、语言自带的 JSON 序列化),要求是每行都是一个合法的 JSON 对象。
**字段**
| 字段 | 必填 | 意思 |
|---|---|---|
| `time` | 是 | 事实发生的时间,ISO 8601,带时区,精确到秒或毫秒都可以,例如 `2026-10-03T10:42:00+08:00` |
| `task` | 是 | 任务编号:每个任务一个在这条工作流里不重复的名字,例如 `B7` |
| `event` | 是 | 下表的事件之一 |
| `node` | 是 | 事实发生在哪个节点,写节点名,例如 `修复` |
| `by` | 是 | 做这件事的执行者 |
| `to` | 视事件 | 交给谁或退回到哪个节点:`return` 写节点名,`question`、`handoff` 写执行者 |
| `round` | 视事件 | `return` 写这是第几次退回,从 1 开始 |
| `cap` | 视事件 | `return` 写退回上限,读的人不用另找配置 |
| `gate` | 视事件 | `gate` 写闸门名 |
| `result` | 视事件 | `gate` 必须写 `pass` 或 `fail`,别的值算无效行 |
| `version` | 否 | 相关交接物的版本:提交号、文件哈希、版本号 |
| `note` | 否 | 一句话说明,例如没过的原因、数字依据 |
**事件**
| 事件 | 什么时候写 | 读出的状态 |
|---|---|---|
| `start` | 任务进入一个节点(派活) | 在 `node` 进行中 |
| `done` | 节点的动作做完,交接物交出 | 在 `node` 已交付,等主控处理 |
| `question` | 执行者停下,等 `to` 决定 | 有提问,等 `to` |
| `answer` | 问题有了答复 | 回到提问之前的状态 |
| `blocked` | 执行者做不下去了 | 卡住 |
| `gate` | 判断完一道闸门 | `pass`:闸门通过,等下一条事实;`fail`:闸门没过,等主控 |
| `return` | 走回边,退回到 `to` 节点 | 在 `to` 修改中,第 `round` 轮(上限 `cap`)。重新派工时可以再写一条 `start`,不写也行 |
| `handoff` | 到了停止条件,移交给 `to` | 已移交给 `to` |
| `finish` | 任务走完最后一个节点 | 完成 |
**示例**(处理 bug 报告的一个任务)
```json
{"time":"2026-10-03T10:00:00+08:00","task":"B7","event":"start","node":"修复","by":"主控"}
{"time":"2026-10-03T10:20:00+08:00","task":"B7","event":"done","node":"修复","by":"编码模型","version":"a1b2c3d"}
{"time":"2026-10-03T10:30:00+08:00","task":"B7","event":"return","node":"审查","by":"主控","to":"修复","round":1,"cap":3,"note":"新测试在修复前也通过"}
{"time":"2026-10-03T10:50:00+08:00","task":"B7","event":"done","node":"修复","by":"编码模型","version":"d4e5f6a"}
{"time":"2026-10-03T11:00:00+08:00","task":"B7","event":"gate","node":"合并","by":"主控","gate":"合并","result":"pass","version":"d4e5f6a"}
{"time":"2026-10-03T11:01:00+08:00","task":"B7","event":"finish","node":"合并","by":"主控","version":"e7f8a9b"}
```
**怎样从记录读出一个任务的现状**
1. 只看这个任务的行,按 `time` 排序;`time` 相同的按在文件里的先后。
2. 最后一个 `question` 之后还没有 `answer`:现状是有提问。否则现状由最近一条既不是 `question` 也不是 `answer` 的事实决定,对照上面"读出的状态"一列(提问期间执行者交付了,回答之后就按交付算)。
3. 退回轮数取所有 `return` 里最大的 `round`(同一条事实写重了也不会多算);上限取最近一条带 `cap` 的 `return`。
4. 周期是第一条事实到 `finish` 的时长;还没有 `finish`,或 `finish` 之后又有事实(任务重新打开),算到现在。
5. 需要主控处理的状态:`done`、`question`、`blocked`、`gate` 的 `fail`、`handoff`。
不是合法 JSON、缺必填字段、事件不在上表里、`time` 读不出来的行算无效行:报出来(第几行、为什么),其余行照常用。不认识的字段忽略。
Claude Code 用户可以加载本 skill 目录里 `pane/` 的看板,实时看这份记录(`claude --plugin-dir <本 skill 目录>/pane`,输入 `/workflow-pane` 打开);其他 agent 直接按上面的步骤读文件即可。
GitHub에서 보기