关于 graph
graph 是一项将任务、规格或 Issue 集转为依赖工作图的技能,并通过子 Agent 并行实现独立节点。它使用隔离的 git worktree、波次屏障和检查点协调执行。
主要功能
- 01将任务拆分为依赖节点
- 02校验 DAG 并识别范围冲突
- 03将工作分层为并行波次
- 04在隔离的 git worktree 中运行子 Agent
- 05保存检查点并生成 HTML 跟踪页
适用场景
- 01并行处理 PRD 或 Issue 集中的独立任务
- 02按任务依赖协调分阶段实现
- 03从已保存的波次检查点恢复执行
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ smallnest/ goal-workflow --skill graph安装后在 Claude Code 中输入/graph确认已加载。
附带文件scripts/render_graph_html.py
详细介绍
graph — 将任务/PRD 转换为并行执行图
将任务(或 PRD/SPEC/问题集)转换为一个有向无环图,将其分层为超步(波次),并使用子 Agent 并发实现每个波次中的独立节点。每个节点都在自己的 Git worktree 中运行完整的 /goal → /review-it → /ship-it 流程,因此并行节点绝不会相互覆盖对方的工作树。波次之间会通过汇入屏障合并结果,并重新规划下一波。
这是 /loop-it 的并行版本。/loop-it 严格按顺序执行(一个 worktree,一次处理一个问题)。/graph 则会在每个波次中同时分发所有独立节点。
心智模型(借鉴自 LangGraph/图工程)
| 概念 | 此处含义 |
|---|---|
| 节点 | 一个可实现的工作单元(一个问题/子任务) |
| 边 | 依赖关系:B depends on A → 边 A → B |
| 超步/波次 | 依赖项均已满足的一组节点——并发运行 |
| 分出 | 为当前波次中的每个节点分派一个子 Agent |
| 汇入(屏障) | 启动下一波之前,等待当前波次中的所有节点完成 |
| 状态通道 | .graph_state——共享检查点,在波次之间重写(恢复来源) |
| 实时跟踪器 | graph.html——Claude 风格的浅色主题仪表板,在每个检查点根据 .graph_state 重新渲染 |
| 动态重新规划 | 波次结束后,如果出现新的工作/依赖关系,则修订图 |
核心原则: 同一波次中的独立节点没有共享状态,也不存在顺序依赖,因此可以真正并行运行。依赖关系决定了唯一的执行顺序。其他工作均同时运行。
概览
Input (task / PRD / SPEC / issues)
│
▼
1. Decompose into nodes ─────────► nodes = {id, title, deps, criteria, scope}
│
▼
2. Build DAG + validate ─────────► detect cycles, orphan deps
│
▼
3. Topological layering ─────────► waves = [[n1,n2,n3], [n4,n5], [n6]]
│
▼
4. Render graph + confirm with user
│
▼ (write .graph_state + graph.html — open graph.html to watch live)
┌──────────── per wave (superstep) ────────────┐
│ │
│ FAN-OUT: 1 subagent per node (parallel) │
│ each subagent, in its own git worktree: │
│ /goal (inline implement) → /review-it │
│ → /ship-it │
│ │
│ FAN-IN barrier: wait for ALL nodes │
│ integrate, update .graph_state │
│ re-render graph.html │
│ re-plan next wave if graph changed │
│ │
└───────────────────────────────────────────────┘
│
▼
All waves done → final summary
第 1 步:定位并分解输入
接受以下任意输入:自由格式的任务描述、PRD/SPEC 文件,或现有问题集(GitHub/本地 .md)。
- PRD/SPEC → 复用
/to-issues的分解规则(每个 User Story 对应一个节点;拆分大型项,合并琐碎项)。 - 现有问题 → 每个问题对应一个节点;从问题正文中解析依赖关系(
Depends on: #3、Dependencies: #3, #5)。 - 自由格式任务 → 自行拆分为可独立交付的最小单元。
每个节点都必须包含:
Node #N
title: short imperative title
deps: [list of node ids] or []
criteria: acceptance criteria (checklist) — how the subagent knows it's done
type: backend | frontend | fullstack | ui | infra | docs
scope_hint: which files/dirs this node is expected to touch (for conflict analysis)
scope_hint 很重要:没有依赖边但文件范围重叠的两个节点,并非真正独立——参见第 3 步。
第 2 步:构建 DAG 并验证
根据 deps 构建边,然后进行验证:
| 检查 | 失败时的操作 |
|---|---|
循环(A → B → A) | 输出 ⚠️ 循环依赖: #A ↔ #B。按节点 ID 顺序打破循环,警告用户,并要求用户确认或修正。 |
悬空依赖(#7 depends on #99,不存在该节点) | 输出警告,并删除虚假边。 |
| 范围冲突(两个无依赖节点编辑相同文件) | 添加一条软边,按较低 ID 优先串行执行,或标记给用户。绝不能让两个并行 worktree 争用相同文件。 |
热点文件例外: 几乎每个节点都必须修改的共享接线文件(例如 router.go、main.go、mod.rs、DI 容器或 __init__ 重新导出文件)不算范围冲突——若将其视为冲突,整个图就会被串行化成一条链。对于此类文件,假设仅追加的修改可以顺利合并,并优先采用以下方式之一:(a) 指定一个节点负责接线,让其他节点提供注册钩子;或 (b) 在最后一个波次中追加一个小型的“接好所有部分”节点。范围冲突规则仅适用于多个节点修改同一文件中的相同逻辑(例如两个处理器重写同一个函数)。
步骤 3:拓扑分层为多个波次
使用 Kahn 算法计算波次:
- 波次 0 = 所有
deps == []且彼此之间没有作用域冲突的节点。 - 移除波次 0 的节点;波次 1 = 依赖项现已全部满足的节点。
- 重复上述步骤,直到所有节点都已分配。
- 在一个波次内,如果两个节点编辑了同一文件中的同一段逻辑(根据步骤 2 中热文件的例外情况判定为真实冲突),则将 ID 较大的节点推迟到下一波。仅仅重叠于接线文件不会触发此规则。
**ID 约定(始终一致):**ID 较小者优先——环依赖按 ID 从小到大打破(步骤 2),作用域冲突按 ID 从小到大串行处理(ID 较大的节点推迟到下一波)。
输出分层计划:
📊 Graph: 6 nodes, 3 waves
Wave 0 (parallel ×3): #1 db schema #2 config loader #3 logging util
Wave 1 (parallel ×2): #4 API handler (deps #1) #5 CLI flags (deps #2)
Wave 2 (parallel ×1): #6 integration (deps #4,#5)
Max parallelism: 3 subagents in Wave 0.
同时为用户生成 Mermaid 图:
```mermaid
graph LR
n1[#1 db schema] --> n4[#4 API handler]
n2[#2 config loader] --> n5[#5 CLI flags]
n3[#3 logging util]
n4 --> n6[#6 integration]
n5 --> n6
```
**在派发任何子 Agent 之前,等待用户确认。**允许用户调整节点、依赖项或最大并行度上限。
步骤 4:执行前检查
在第一波开始前(与 /loop-it 的理念相同):
git rev-parse --is-inside-work-tree # in a repo?
git status --porcelain # clean tree? (dirty → stash/abort)
git branch --show-current # on main/master?
git ls-remote --heads origin # remote reachable?
gh auth status # if shipping to GitHub
任何硬性失败 → 输出错误并停止。与用户确认最大并发上限(默认并行运行 3–4 个子 Agent;更多可能导致触及速率限制并增加审查噪声)。
然后初始化状态通道和实时跟踪器(仅执行一次,在计划确认后、首次扇出前立即执行):
# 1. Write the initial checkpoint (all nodes pending, current_wave 0).
cat > .graph_state <<'JSON'
{ "version": 1, "task": "...", "repo": "owner/repo",
"waves": [[1,2,3],[4,5],[6]], "current_wave": 0,
"nodes": { "1": {"title":"...","deps":[],"status":"pending","wave":0}, ... } }
JSON
# 2. Keep it out of git.
grep -qxF '.graph_state' .gitignore || printf '.graph_state\ngraph.html\n' >> .gitignore
# 3. Render the Claude-style light-theme dashboard.
python3 skills/graph/scripts/render_graph_html.py .graph_state graph.html
告知用户:在浏览器中打开 graph.html — 它每 5 秒自动刷新,因此可以实时跟踪执行情况(波次、节点状态、进度条,以及按状态着色的 Mermaid DAG)。每个检查点都要重新运行渲染命令(见步骤 5b)以推送更新。
步骤 5:逐波执行(扇出 → 扇入)
按顺序逐个处理每个波次:
5a. 扇出 — 每个节点派发一个子 Agent,并行执行
在单条回复中派发该波次的所有节点(在一条消息中发起多个 Agent/子 Agent 调用即可并发执行)。每个子 Agent 都在自己的 git worktree 中工作,避免并行编辑文件时发生冲突:
# The orchestrator creates a worktree per node BEFORE dispatching:
git worktree add -b feat/node-{N}-{slug} ../.graph-worktrees/node-{N} main
每个子 Agent 都会收到一份自包含提示词(不会继承编排器的上下文):
You are implementing ONE node of a task graph, working in an ISOLATED git worktree.
Worktree: ../.graph-worktrees/node-{N} (already created on branch feat/node-{N}-{slug})
Node #{N}: {title}
Type: {type}
Scope: {scope_hint} — stay within these files; do not touch other nodes' scope
Acceptance criteria (all must pass):
- [ ] {criterion 1}
- [ ] {criterion 2}
Context (deps already merged into main, pull first):
{summaries of dependency nodes' outputs, or the referenced PRD/SPEC excerpt}
Your pipeline (run all three, in order):
1. IMPLEMENT (inline /goal): read the node + any referenced PRD/SPEC, read adjacent
code, implement to satisfy EVERY acceptance criterion, run build + tests + lint
(e.g. go build ./... && go vet ./... && go test ./...). Iterate until all green.
2. REVIEW (/review-it): run code review on your changes, apply accepted findings,
re-run focused tests, repeat until review is clean (max 2 rounds).
3. SHIP (/ship-it): commit (message references the node/issue), push branch,
create PR, merge, close the issue.
Constraints:
- Work ONLY inside your worktree. Do NOT edit files outside {scope_hint}.
- Do NOT try to call `goal` via the Skill tool (it's a UI command, not a skill) —
"implement" means you write the code yourself. /review-it and /ship-it ARE skills.
- If you cannot satisfy a criterion, STOP and report what's blocking — don't fake it.
Return: node id, PASS/FAIL, PR/commit refs, files changed, and — if you discovered new required work or a dependency the graph didn't capture — a `NEW_WORK:` line describing it (title + which nodes it blocks). Emit `NEW_WORK: none` if there's nothing.
为什么使用 worktree,而不仅是分支:
/goal会修改工作树。两个子 Agent 在同一个 checkout 中编辑会相互破坏。每个节点使用一个 worktree,可为其提供独立文件系统 checkout 和独立分支——这才真正实现了安全的并行波次。
5b. 扇入 — 屏障、集成、重新规划
等待该波次中的每个子 Agent 返回(BSP 屏障——本波提交前,下一波不能开始)。然后:
- 阅读每个子 Agent 的摘要。将节点标记为
shipped或failed。 git checkout main && git pull— 依赖项的输出现已合并到 main,供下一波使用。- 移除已完成的 worktree:
git worktree remove ../.graph-worktrees/node-{N}(失败的 worktree 保留以供调查)。 - 将检查点写入
.graph_state,然后重新渲染跟踪器:python3 skills/graph/scripts/render_graph_html.py .graph_state graph.html(已打开的graph.html会在下次自动刷新时加载更新)。 - 动态重新规划(类似 LangGraph 的条件边):检查每个子 Agent 的
NEW_WORK:行。如果有任何一行不是none,则添加新节点/边,并在开始下一波前对剩余节点重新分层。向用户展示变更。 - 如果本波有任何节点失败,则将依赖于它的所有节点标记为
blocked并跳过(其输入尚未就绪)。
继续处理下一波。
状态文件:.graph_state(+ 实时跟踪器 graph.html)
.graph_state 位于仓库根目录,必须写入 .gitignore。它是唯一可信来源:每个波次结束后都要保存检查点,这样发生崩溃时才能从波次边界恢复;并从中重新生成 graph.html,以便浏览器仪表板保持实时更新。graph.html 是一个派生视图——切勿手动编辑;应从 .graph_state 重新生成。
{
"version": 1,
"updated_at": "2026-07-21T10:30:00Z",
"task": "Add user auth",
"repo": "owner/repo",
"waves": [[1, 2, 3], [4, 5], [6]],
"current_wave": 1,
"nodes": {
"1": { "title": "db schema", "deps": [], "status": "shipped", "branch": "feat/node-1-db-schema", "pr": 43, "wave": 0 },
"2": { "title": "config loader", "deps": [], "status": "shipped", "wave": 0 },
"3": { "title": "logging util", "deps": [], "status": "failed", "wave": 0, "error": "test TestLog failed", "attempts": 2 },
"4": { "title": "API handler", "deps": [1], "status": "in_progress", "wave": 1 },
"6": { "title": "integration", "deps": [4, 5], "status": "blocked", "wave": 2, "reason": "depends on #3 (failed)" }
}
}
状态值:pending | in_progress | shipped | failed | blocked | skipped。每个节点都包含 title + deps,这样 graph.html 就能直接根据检查点绘制 DAG 和卡片。
随时可以渲染跟踪器:
python3 skills/graph/scripts/render_graph_html.py .graph_state graph.html
恢复时:读取 .graph_state,跳过 shipped,询问如何处理 failed(重试/跳过),重新推导剩余波次,并重新渲染 graph.html。
安全防护
- 必须隔离工作树——绝不能在同一检出目录中运行两个并行的
/goal会话。 - 必须设置汇入屏障——在第 N 波的所有节点都返回并合并之前,绝不能启动第 N+1 波。
- 作用范围冲突时应串行执行——无依赖的节点若会修改相同文件,必须安排在不同波次。
- 切勿在
/ship-it前跳过/review-it。 - 限制并发数——默认 3–4 个;更多并发容易触发速率限制并造成合并冲突。
- **绝不能强制推送到 main。**每个节点都通过自己的分支/PR 发布。
- 失败的节点会阻塞其依赖节点——不要在输入条件未满足时发布。
- 限制每个节点的最大重试次数——复用
/loop-it的错误分类,别无限循环。 - 首次扇出前确认计划。
常见错误
| 错误 | 修正方法 |
|---|---|
| 在不同响应中派发子 Agent | 在一个响应中发起多个调用 = 并行。分开调用 = 串行。 |
| 未使用工作树 → 并行编辑会破坏工作树 | 每个节点使用一个 git worktree。 |
| 两个“独立”节点编辑同一个文件 | 添加软边;将它们安排在不同波次。 |
| 所有节点尚未合并就启动下一波 | 强制执行汇入屏障。 |
| 过度拆分为 20 个琐碎节点 | 合并小单元;节点应是有意义且可发布的单元。 |
| 忽略失败节点的依赖节点 | 将它们标记为 blocked,并跳过。 |
与其他技能的关系
/prd → /prd-to-spec → /to-issues ─┬─► /loop-it (sequential: one node at a time)
└─► /graph (parallel: whole wave at once)
│
each node: inline /goal → /review-it → /ship-it (in its own worktree)
/to-issues——复用分解规则来构建节点。/loop-it——串行执行的对应技能;节点大量共享文件或需要串行保障时使用。/graph——本技能;DAG 中存在真正的并行性(独立子系统)时使用。/review-it、/ship-it——每个节点的子 Agent 都会调用的实际技能。