238 lines
8.3 KiB
Markdown
238 lines
8.3 KiB
Markdown
---
|
||
name: declarative-openspec-loop
|
||
description: 声明式编程循环 - 用户提供校验方式,Agent 自动 propose/apply/校验并迭代直到通过。Use when the user provides expectations or a verification method and wants the agent to implement, verify, and iterate until expectations pass. Triggers on 声明式编程、按预期循环、做到校验通过、declarative loop.
|
||
---
|
||
|
||
# 声明式 OpenSpec 循环
|
||
|
||
用户提供**判断结果是否符合预期的方式**,Agent 按 OpenSpec 流程 propose → apply → 校验,不通过则分析原因并迭代,直到通过。通过后输出变更点与思路。
|
||
|
||
**前置**:需要 openspec CLI 及三个子 skill。预期/校验写法的详细说明和端到端示例见 [reference.md](reference.md)。
|
||
|
||
---
|
||
|
||
## 何时使用
|
||
|
||
- 用户说「按我给的预期/校验方式做,做到通过为止」
|
||
- 用户提供了校验命令、预期文档、校验清单或自由描述,并希望自动迭代
|
||
- 用户提到「声明式编程」「按预期循环」「做到校验通过」
|
||
|
||
---
|
||
|
||
## 输入:预期与校验方式
|
||
|
||
用户必须提供**如何判断结果符合预期**(可组合):
|
||
|
||
| 形式 | 示例 |
|
||
| -------- | --------------------------------------------- |
|
||
| 校验命令 | `make test-one2`,退出码 0 即通过 |
|
||
| 预期文档 | `docs/tmp/expect_desc.md` 中的校验项表格 |
|
||
| 校验清单 | 日志须含 `阶段2 圆弧起点`、`阶段3 右边竖边` … |
|
||
| 自由描述 | 「拟合轮廓与 PLY 逆时针顺序一致」 |
|
||
|
||
若用户未给清,**必须先问**。详细格式说明见 [reference.md § 预期/校验方式](reference.md#预期校验方式的写法)。
|
||
|
||
---
|
||
|
||
## 如何调用子 skill(关键)
|
||
|
||
本 skill 编排三个子 skill,每次调用子 skill 时**必须先读取对应 SKILL.md 并遵循其中的完整步骤**:
|
||
|
||
| 步骤 | 子 skill | 读取路径 |
|
||
| ---- | --------------------- | ----------------------------------------------- |
|
||
| 探索 | openspec-explore | `.cursor/skills/openspec-explore/SKILL.md` |
|
||
| 提案 | openspec-propose | `.cursor/skills/openspec-propose/SKILL.md` |
|
||
| 实现 | openspec-apply-change | `.cursor/skills/openspec-apply-change/SKILL.md` |
|
||
|
||
**不要凭记忆执行子 skill 的流程**,每次都读取最新的 SKILL.md 再做。
|
||
|
||
---
|
||
|
||
## 主流程
|
||
|
||
```
|
||
用户输入:目标 + 校验方式
|
||
│
|
||
▼
|
||
1. 初始化:change 名称 + docs/tmp/<name>/ + expectation.md
|
||
│
|
||
▼
|
||
2. [可选] explore:目标复杂/模糊时先探索
|
||
│
|
||
▼
|
||
3. propose:生成 proposal / design / tasks(任务带验收标准)
|
||
│
|
||
▼
|
||
4. apply:按 tasks 实现
|
||
│
|
||
▼
|
||
5. 校验 ──通过──▶ 6a. 完成:输出变更与思路
|
||
│
|
||
不通过
|
||
│
|
||
▼
|
||
6b. 分级处理(见下)──▶ 回到 4 或 3
|
||
```
|
||
|
||
---
|
||
|
||
## 迭代分级:失败后怎么做
|
||
|
||
校验不通过时,**根据失败根因选择不同路径**,避免小 bug 也走完整提案流程:
|
||
|
||
### Level 1:代码小修复(最常见)
|
||
|
||
**触发**:编译错误、运行时 bug、坐标写反、off-by-one、日志格式不对等实现层面问题。
|
||
|
||
**动作**:
|
||
|
||
1. 定位出错代码,直接修复
|
||
2. 重新编译(若适用)
|
||
3. 回到**步骤 5 校验**
|
||
|
||
不需要 explore,不需要修改 proposal/design/tasks。
|
||
|
||
### Level 2:任务遗漏或不完整
|
||
|
||
**触发**:某个校验项没有对应的 task、task 描述模糊导致实现偏差。
|
||
|
||
**动作**:
|
||
|
||
1. 分析缺失的校验项对应什么工作
|
||
2. 在 `tasks.md` 中**补充或修正** task
|
||
3. 回到**步骤 4 apply** 执行新增/修正的 task → **步骤 5 校验**
|
||
|
||
### Level 3:设计级问题(最少见)
|
||
|
||
**触发**:整体方向错误、架构不合适、预期理解有偏差、多个校验项系统性失败。
|
||
|
||
**动作**:
|
||
|
||
1. 读取子 skill **openspec-explore** 并执行:基于校验结果 + 当前 proposal/design 分析根因
|
||
2. 将分析写入 `docs/tmp/<change-name>/iteration_<N>.md`
|
||
3. 修订 proposal.md / design.md / tasks.md(在原有 change 上修改,不新建)
|
||
4. 回到**步骤 4 apply** → **步骤 5 校验**
|
||
|
||
### 判断依据
|
||
|
||
| 信号 | Level |
|
||
| ---------------------------------------- | ------ |
|
||
| 编译报错 | 1 |
|
||
| 运行崩溃 / 段错误 | 1 |
|
||
| 单个校验项不通过,其余都通过 | 1 或 2 |
|
||
| 多个校验项不通过,但原因各异 | 2 |
|
||
| 多个校验项不通过,原因相同(方向性错误) | 3 |
|
||
| 校验项全部不通过 | 3 |
|
||
|
||
---
|
||
|
||
## 最大迭代次数
|
||
|
||
- 默认上限:**5 轮**(一轮 = 一次 apply + 一次校验)。
|
||
- 到达上限后**暂停并询问用户**:展示当前进度、未通过的校验项、已尝试的修复方向,让用户决定是否继续。
|
||
- 用户可在初始化时指定不同的上限(如「最多跑 3 轮」「不限轮次」)。
|
||
- Level 1 的小修复(如编译错误修复后重新编译)**不计入**轮次,仅 apply+校验 计一轮。
|
||
|
||
---
|
||
|
||
## 编译失败处理
|
||
|
||
对于需要编译的项目(C/C++、Rust、Go 等):
|
||
|
||
1. apply 完成后、运行校验命令前,**先编译**(或校验命令本身触发编译)。
|
||
2. 若编译失败:属于 **Level 1**,直接修复编译错误,重新编译,不计入迭代轮次。
|
||
3. 若编译成功但校验不通过:按正常分级处理。
|
||
4. 编译错误的修复**不需要** explore 或修订 proposal。
|
||
|
||
---
|
||
|
||
## 重复失败检测
|
||
|
||
若连续 **2 轮**校验结果中,**同一个校验项以相同原因失败**:
|
||
|
||
1. 停止自动迭代
|
||
2. 向用户报告:哪个校验项、什么错误、已尝试的两次修复各做了什么
|
||
3. 请用户给出新方向或手动介入
|
||
|
||
避免 Agent 在同一个坑里反复打转。
|
||
|
||
---
|
||
|
||
## 恢复 / 续接
|
||
|
||
对话中断后重新进入时:
|
||
|
||
1. 检查 `docs/tmp/<change-name>/` 下已有的 `iteration_*.md` → 确定当前轮次
|
||
2. 检查 `openspec/changes/<name>/tasks.md` 中 `[x]` / `[ ]` → 确定 task 进度
|
||
3. 读取最近一轮的 `iteration_<N>.md` 和 `check_result_<N>.txt` → 了解上次失败原因
|
||
4. 从上次中断的步骤继续,不从头开始
|
||
|
||
---
|
||
|
||
## TodoWrite 跟踪
|
||
|
||
整个循环过程中用 **TodoWrite** 跟踪进度:
|
||
|
||
```
|
||
示例 todo 列表:
|
||
- [x] 初始化 change + expectation.md
|
||
- [x] propose: 生成 proposal/design/tasks
|
||
- [in_progress] 第 1 轮 apply + 校验
|
||
- [ ] 校验通过 → 输出变更摘要
|
||
```
|
||
|
||
每轮 apply + 校验 为一个 todo;校验不通过时更新 todo 内容(如「第 1 轮:3/8 校验项通过,Level 2 修复中」)。
|
||
|
||
---
|
||
|
||
## 过程数据存储
|
||
|
||
根目录:`docs/tmp/<change-name>/`
|
||
|
||
| 文件 | 内容 |
|
||
| ------------------------ | -------------------------------------------------- |
|
||
| `expectation.md` | 校验方式摘要(或引用路径) |
|
||
| `iteration_<NNN>.md` | 每轮:apply 要点、校验结果、失败项、分级、修复动作 |
|
||
| `check_result_<NNN>.txt` | 校验命令原始输出 |
|
||
| `iteration_final.md` | 通过后的最终摘要(可选) |
|
||
|
||
若 `docs/tmp` 不存在,先创建。
|
||
|
||
---
|
||
|
||
## 输出模板(校验通过时)
|
||
|
||
```markdown
|
||
## 声明式循环完成
|
||
|
||
**Change:** <change-name>
|
||
**校验方式:** <摘要>
|
||
**迭代轮次:** N
|
||
|
||
### 变更摘要
|
||
|
||
- <文件 1>:<改动>
|
||
- <文件 2>:<改动>
|
||
|
||
### 思路
|
||
|
||
<设计取舍、与预期的对应、关键实现要点>
|
||
|
||
### 过程数据
|
||
|
||
`docs/tmp/<change-name>/`
|
||
```
|
||
|
||
---
|
||
|
||
## Guardrails
|
||
|
||
- **未提供校验方式时**:不进入循环,先问用户。
|
||
- **每轮校验结果必须落盘**:至少记录通过/不通过与未满足项。
|
||
- **优先复用同一 change**:修订 proposal/design/tasks,不盲目新建。
|
||
- **任务带验收标准**:propose 时每个 task 尽量带可执行的验证步骤。
|
||
- **explore 只分析不改代码**:改代码通过 apply 或 Level 1 直接修复。
|
||
- **最大轮次到达时停下问用户**:不自动放弃也不无限跑。
|
||
- **重复失败时升级**:同一错误连续 2 轮 → 停下问用户。
|
||
- **用户可随时中断**:暂停并汇报当前状态。
|