loop-graph-cli
给 AI 编码 agent(opencode / claude code / kilo code / qwen / codebuddy / qoder)安装
Loop Engineering(循环工程) + Graph Engineering(图工程) 闭环能力的 CLI 工具。
它解决什么问题
AI 编码 agent 单次执行容易跑偏、不收敛、无法自我验证。本工具给 agent 装上一套两层循环闭环:
- 外层(脚本管终止边界):
MAX_ITER / BUDGET_S 硬熔断保证有界,STALL_LIMIT + 可选 VERIFY_CMD 叠加客观信号降低空转/虚报
- 内层(编排者管决策):orchestrator 用 Task 工具委派 executor / reviewer / fixer 三角色协作,跑 执行→审查→修复→再审 的完整闭环
两档可选:
- 档位 A: Loop Engineering — 单节点自环(
/loop-task),适合绝大多数顺序任务
- 档位 B: Graph Engineering — 多节点图(
/graph-task),用 nodes/edges/state 声明拓扑,需要更细粒度路由时启用
外层 while (loop-task.sh | graph-run.sh) 内层闭环 (orchestrator 进程内)
┌──────────────────────────┐ ┌─────────────────────────────────┐
│ iter < MAX_ITER? │ │ 读状态 → 拆步骤 │
│ spawn orchestrator ────┼─────────────│→ Task(executor) 执行 │
│ 查硬约束: │ │ Task(reviewer) 验证+审查 │
│ goal_met & approved? │ │ fail? Task(fixer) → 再审 │
│ → DONE │ │ 写状态 → 判 DONE 退出 │
│ stalled/budget/iter? │ └─────────────────────────────────┘
│ → ABORT │
└──────────────────────────┘
图模式额外(graph-run.sh + graph-orchestrator):
- 读 state.graph 拓扑,从 entry 出发按边路由
- 每节点由 statectl graph-next 算下一节点(共享收敛点)
- 触达 __done__ 写终态;触达 __abort__ 转人工
安装
npm install -g loop-graph-cli
使用
1. 给项目装 loop 能力
在你的项目根目录(已用 opencode/claude/kilo 的项目)里:
loop-graph install --to opencode
loop-graph install --to claude
loop-graph install --to kilo
loop-graph install --to opencode --dry-run
loop-graph install --to opencode --force
安装后会在项目里生成 .opencode/(或 .claude/ / .kilo/ / .qwen/ / .codebuddy/ / .qoder/):
.opencode/
├── statectl.sh # 状态读写工具(jq)+ graph-next 子命令
├── loop-task.sh # Loop Engineering 外层(硬约束 + spawn 编排者)
├── graph-run.sh # Graph Engineering 外层(硬约束 + spawn 图编排者)
├── loop-review.sh # 复盘命令
├── state-schema.json # 状态 schema(v1 + v2 联合)
├── STATE_CONTRACT.md # 状态契约(含图拓扑/节点状态归属)
├── agents/
│ ├── orchestrator.md # 编排者(决策层,Loop Engineering)
│ ├── graph-orchestrator.md # 图编排者(决策层,Graph Engineering 档位 B)
│ ├── executor.md # 执行者
│ ├── reviewer.md # 审查者(验证+语义)
│ └── fixer.md # 修复者
└── commands/
├── loop-task.md # /loop-task 斜杠命令入口
├── graph-task.md # /graph-task 斜杠命令入口(档位 B)
└── loop-review.md # /loop-review 复盘命令
frontmatter 由安装器按平台生成:payload/templates/ 下的 agent/command 模板只含正文,不带 frontmatter。
安装时 src/install.ts 根据目标平台的 frontmatterStyle 生成对应格式(缩进由代码保证,避免占位符拼 YAML 错位):
| opencode / kilo | mode: subagent + temperature + steps + permission(orchestrator/graph-orchestrator 自动带 task 权限块) | loop-task / graph-task 带 agent: <对应编排者> + subtask: false |
| claude / qwen / codebuddy / qoder | name + description + tools(工具集由角色决定:orchestrator/graph-orchestrator 含 Task,executor/fixer 含 Edit/Write,reviewer 只读) | 仅 description(agent/subtask 为 opencode 专用) |
新增平台只需在 PLATFORMS 里声明合适的 frontmatterStyle。
Loop vs Graph:怎么选
两种模式都给 agent 装"外层硬约束循环 + 内层三角色协作闭环",区别在内层怎么组织工作流:
| 工作流形态 | 单节点自环,编排者自由拆步骤 | 显式图拓扑,按 nodes/edges 的边路由 |
| 入口 | /loop-task → loop-task.sh | /graph-task → graph-run.sh |
| 编排者 | orchestrator | graph-orchestrator |
| 默认流程 | 编排者自主决定三角色顺序与次数 | 写死:exec→review→(approved→完成 / changes_requested→fix→再审 / blocked→中止) |
一句话:拿不准就用 Loop;只有当你想要"固定的、可审计的多阶段流水线"时才用 Graph。
2. 在 agent 工具里启动闭环
2a. Loop Engineering(单节点循环,档位 A)
/loop-task 修复登录页 500 错误 登录成功且 E2E 测试通过
也可在命令行直接跑(调试 / CI / 无 agent 场景):
bash .opencode/loop-task.sh "修复登录页 500 错误" "登录成功且 E2E 测试通过"
格式都是 ...loop-task "任务描述" "达成标准"(达成标准可省略,由 reviewer 判定)。
"单节点"的含义:状态文件里没有显式步骤图,编排者根据上下文自由编排三角色的调用顺序与次数,外层脚本只管硬约束(别跑超时、别空转)。编排者会自动:
- 读任务目标,拆解步骤
- Task 委派 executor 执行
- Task 委派 reviewer 验证(跑测试/编译)+ 语义审查
- 未过则 Task 委派 fixer 修复,再复审
- goal_met & approved → DONE
2b. Graph Engineering(多节点图,档位 B)
/graph-task 修复登录页 500 错误 登录成功且 E2E 测试通过
默认图(不带 --graph 时跑的流程,等价于一条标准 exec→review→fix 流水线):
exec-1 ──► review-1 ──approved──► __done__(完成)
│
├──changes_requested──► fix-1 ──► review-1(再审)
│
└──blocked──► __abort__(转人工)
适用场景:你想要"固定流程、不让编排者自由发挥"时,直接用默认图即可;想要不同流程再注入自定义图。
图编排者会:
- 读
state.graph 图拓扑
- 从
entry 出发,逐节点串行执行(不并行——档位 B 锁定决策)
- 用
statectl graph-next <node_id> <result> 计算下一节点(由边条件 when 驱动)
- 触达虚拟终点
__done__ 时写终态,触达 __abort__ 时转人工
注入自定义图(可选):
cat > /tmp/my-graph.json <<'EOF'
{
"entry": "plan",
"nodes": [
{"id": "plan", "role": "executor"},
{"id": "build", "role": "executor"},
{"id": "test", "role": "reviewer"}
],
"edges": [
{"from": "plan", "to": "build"},
{"from": "build", "to": "test"},
{"from": "test", "to": "__done__", "when": "approved"},
{"from": "test", "to": "build", "when": "changes_requested"}
]
}
EOF
/graph-task 重构登录模块 单元测试覆盖率 > 80% 并 E2E 通过 --graph /tmp/my-graph.json
图定义规则(graph-run.sh 启动时校验,不合法则报错退出):
- 顶层必须含
entry / nodes / edges 三字段,缺任一或 JSON 非法即退出。
- 节点
role 只能是 executor / reviewer / fixer 三选一(不创造新角色)。
- 虚拟终点
__done__(完成) / __abort__(转人工)只能作边的 to 值。
- 边
when 缺省 = 无条件顺序边;设了则匹配节点的 result 决定路由(常见取值 approved / changes_requested / blocked)。
3. 复盘
/loop-review # 复盘全部任务
/loop-review <状态文件> # 复盘指定任务
自检(MOCK)
不接真实 agent,用内置 mock 编排者验证安装/控制流能否收敛(本项目的 npm test 也是这么跑的):
MOCK=1 bash .opencode/loop-task.sh "测试任务" "标准"
MOCK=1 bash .opencode/graph-run.sh "测试任务" "标准"
约束与闸门(可配置)
| 最大迭代轮数 | 20 | MAX_ITER | 硬信号:防无限循环 |
| 总预算(秒) | 3600 | BUDGET_S | 硬信号:防超时 |
| 停滞熔断阈值 | 3 | STALL_LIMIT | 连续 N 轮无进展且工作区无改动则终止 |
| 客观校验命令 | (无) | VERIFY_CMD | 配置后每轮脚本亲自跑,退出码 0 才认可 DONE |
| VCS 类型 | auto | LOOP_VCS | `auto |
覆盖示例:
MAX_ITER=5 BUDGET_S=120 bash .opencode/loop-task.sh "任务" "标准"
VERIFY_CMD='npm test' bash .opencode/loop-task.sh "修复登录" "登录流程绿灯"
LOOP_VCS=tfvc bash .opencode/loop-task.sh "任务" "标准"
VERIFY_CMD='npm test' bash .opencode/graph-run.sh "修复登录" "登录流程绿灯"
依赖
- 目标项目侧:
jq(JSON 处理)
- Git Bash: 下载 jq.exe 放入 PATH
- macOS:
brew install jq
- Linux:
apt install jq / yum install jq
- agent 工具: opencode / claude code / kilo code 任一(需支持 markdown subagent + Task 委派)
支持的平台
| OpenCode | .opencode/ | task | ✅ |
| Claude Code | .claude/ | Task | ✅ |
| Kilo Code | .kilo/ | task | ✅ |
| Qwen Code | .qwen/ | 隐式子代理(自动路由) | ✅ |
| CodeBuddy | .codebuddy/ | 隐式子代理(自动路由) | ✅ |
| Qoder | .qoder/ | Agent | ✅ |
Trae / ZCode 采用配置驱动(非 markdown subagent),暂不支持。
架构设计
为什么是两层循环
- 纯脚本驱动(每轮调一个子 agent):硬约束强,但子 agent 之间不共享上下文,且只 opencode 支持外部 CLI 调子 agent
- 纯 prompt 编排(循环全在 prompt 里):覆盖广但硬约束靠 LLM 自觉,易跑飞
- 本工具(两层):外层脚本管硬约束,内层编排者管多 agent 协作——两者兼得
关于"硬约束"的准确边界(别误解):
- 真正硬的只有
MAX_ITER 与 BUDGET_S(确定性,保证有界性)。
progress_delta/goal_met/review 都是 agent 自报的软信号,脚本只转述不验真——防“无限跑/超时”,不天然防“跑偏”。
- 可用
VERIFY_CMD 加客观闸门(脚本亲自跑、退出码 0 才认可 DONE),停滞判定也叠加了“工作区是否真改动”(mtime,不依赖 VCS)。
- “共享上下文”仅在单轮编排者进程内;跨轮靠状态文件的
history 字段接续。
- 安全:executor/fixer 的 bash 受命令白名单约束(opencode/kilo 在
permission.bash 逐条 allow + 兜底 *: deny,失败方向安全;完整列表见 src/install.ts 的 SAFE_BASH)。白名单刻意不含通用解释器裸调用(node/python — 因 -e/-c 能执行任意代码架空白名单,需跑脚本请走 tsx/pytest/npx 等带文件入口的工具)。注意:这是防意外损坏的护栏,不是防恶意 Agent 的沙箱——要防 prompt-injection 触发的破坏性操作,请在隔离主机/容器中运行,不要在开发者工作机上裸跑。开跑前按 VCS(git/tfvc/none)提示回滚点。
- 详见 STATE_CONTRACT.md 的“信号硬度”一节。
为什么用 Node CLI + 纯 sh payload
- Node CLI(安装器):npm 发布要求,仅安装时跑一次(渲染占位符 + 复制 payload)
- 纯 sh payload(装到目标项目):agent 调用统一
bash xxx.sh,对 Node 透明,目标项目不依赖 Node
详见 STATE_CONTRACT.md。
开发
npm install
npm run build
npm run typecheck
npm run dev -- --list
目录结构
loop-graph-cli/
├── src/ # Node CLI 安装器
│ ├── cli.ts # 入口
│ ├── platforms.ts # 6 家平台配置(opencode/claude/kilo/qwen/codebuddy/qoder)
│ └── install.ts # 渲染 + 复制 payload
├── payload/ # 装到目标项目的资产(纯 sh + jq)
│ ├── statectl.sh # 状态读写 + graph-next
│ ├── loop-task.sh # Loop Engineering 外层
│ ├── graph-run.sh # Graph Engineering 外层(档位 B)
│ ├── loop-review.sh # 复盘命令
│ ├── state-schema.json # 状态 schema(v1 + v2 联合)
│ ├── STATE_CONTRACT.md # 状态契约
│ └── templates/ # agent/command 模板(带 {{占位符}})
│ ├── agents/
│ │ ├── orchestrator.md
│ │ ├── graph-orchestrator.md # 档位 B
│ │ ├── executor.md
│ │ ├── reviewer.md
│ │ └── fixer.md
│ └── commands/
│ ├── loop-task.md
│ ├── graph-task.md # 档位 B
│ └── loop-review.md
└── tests/ # 测试(selfcheck.sh)
License
MIT