refactor: fold ack kit into skill
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
# ACK
|
||||
|
||||
ACK 是一个显式调用的 Agent Skill,用三种独立角色运行工程协作闭环:
|
||||
|
||||
- Coordinator 拆解需求、派发任务并终检。
|
||||
- Developer 实现并执行白盒验证。
|
||||
- Test 独立执行黑盒复测。
|
||||
|
||||
关键约束是验证者不等于实现者。每个任务最多修复三轮,仍未通过时记录为
|
||||
`leftover`,然后继续处理其它任务。
|
||||
|
||||
## 安装
|
||||
|
||||
全局安装:
|
||||
|
||||
```bash
|
||||
skiff add ack -g
|
||||
```
|
||||
|
||||
或只安装到当前项目:
|
||||
|
||||
```bash
|
||||
skiff add ack
|
||||
```
|
||||
|
||||
ACK 只在用户显式调用 `/ack` 或 `$ack` 时运行。
|
||||
|
||||
## 初始化项目
|
||||
|
||||
```bash
|
||||
skiff init ack
|
||||
skiff init ack --project ~/code/my-app
|
||||
```
|
||||
|
||||
初始化后,项目只保存自己的 ACK 状态:
|
||||
|
||||
```text
|
||||
docs/ack/
|
||||
├── project.md
|
||||
└── tasks.yaml
|
||||
```
|
||||
|
||||
不会在项目中复制或链接 ACK Skill。通用规范、模板和脚本始终从已安装的 Skill
|
||||
目录读取。
|
||||
|
||||
## Skill 结构
|
||||
|
||||
```text
|
||||
skills/ack/
|
||||
├── SKILL.md
|
||||
├── README.md
|
||||
├── VERSION
|
||||
├── references/ # 三角色规范、闭环流程和初始化说明
|
||||
├── templates/ # project.md 与 tasks.yaml 模板和 schema
|
||||
├── examples/ # 完整示例
|
||||
└── scripts/ # tasks.yaml 与 worker 命令校验器
|
||||
```
|
||||
|
||||
`SKILL.md` 是 Agent 的工作流入口。`references/` 是按需读取的稳定规范;
|
||||
`docs/ack/project.md` 只保存当前项目的命令、路径和权限差异;
|
||||
`docs/ack/tasks.yaml` 保存当前任务状态。
|
||||
|
||||
## 检查任务板
|
||||
|
||||
Agent 会从当前 ACK Skill 目录解析校验脚本:
|
||||
|
||||
```bash
|
||||
python3 <ack-skill-dir>/scripts/validate_tasks.py docs/ack/tasks.yaml
|
||||
```
|
||||
|
||||
## 开始一个需求
|
||||
|
||||
初始化完成后可以直接说:
|
||||
|
||||
```text
|
||||
/ack 处理这个需求:<一句话需求>
|
||||
```
|
||||
|
||||
Coordinator 会先读取项目状态和 `references/kickoff.md`,生成产品文档、任务拆分与
|
||||
可观测验收信号;用户确认后才派发实现和复测。
|
||||
|
||||
## 版本
|
||||
|
||||
当前 Skill 版本见 `VERSION`。新项目在 `tasks.yaml` 中记录 `ackVersion`。旧项目的
|
||||
`kitVersion` 可以继续读取,但建议迁移为 `ackVersion`。
|
||||
+27
-22
@@ -1,15 +1,19 @@
|
||||
---
|
||||
name: ack
|
||||
description: >-
|
||||
初始化、检查并运行 ACK(Agent Collaboration Kit)三角色协作闭环。仅在用户显式调用
|
||||
/ack 或 $ack,并要求初始化 ACK、检查 docs/ack 配置、按 ACK 规划需求或指挥
|
||||
Coordinator/Developer/Test 工作时使用。
|
||||
初始化、检查并运行 ACK 三角色协作闭环。仅在用户显式调用 /ack 或 $ack,并要求
|
||||
初始化 ACK、检查 docs/ack 配置、按 ACK 规划需求或指挥 Coordinator/Developer/Test
|
||||
工作时使用。
|
||||
---
|
||||
|
||||
# ACK 项目协作入口
|
||||
|
||||
把全局 skill 作为入口,把项目状态留在 `docs/ack/`,把通用规范留在
|
||||
`~/.skills/kits/ack/`。不要在本 skill 复制或改写 kit 的核心规范。
|
||||
本 Skill 是 ACK 的完整能力包:`references/` 保存通用规范,`templates/` 保存项目
|
||||
状态模板,`scripts/` 保存校验工具。目标项目只在 `docs/ack/` 保存 `project.md` 和
|
||||
`tasks.yaml`,不要复制或链接 Skill 内容。
|
||||
|
||||
开始时解析当前 `SKILL.md` 所在目录,记为 `<ack-skill-dir>`。所有通用规范、模板和
|
||||
脚本都相对此目录访问,不依赖固定的全局安装路径。
|
||||
|
||||
## 选择模式
|
||||
|
||||
@@ -27,10 +31,11 @@ description: >-
|
||||
2. 不存在时执行:
|
||||
|
||||
```bash
|
||||
skiff kit init ack --project <project-root>
|
||||
skiff init ack --project <project-root>
|
||||
```
|
||||
|
||||
默认使用软链接模式。只有用户明确要求项目自带完整副本时才加 `--copy`。
|
||||
该命令从本 Skill 的 `templates/` 生成项目状态,不会在项目中创建 Skill
|
||||
软链接或资源副本。
|
||||
3. 如果 `docs/ack` 已存在,不重复初始化、不覆盖文件;转入“检查”,报告缺失项并
|
||||
只补用户授权且能安全确定的内容。
|
||||
4. 读取项目的公开配置和文档,例如 README、语言清单、包管理清单、测试配置与
|
||||
@@ -39,33 +44,32 @@ description: >-
|
||||
- 用实际项目值替换全部占位符。
|
||||
- 无服务地址时把 Base URL 写为 `n/a`,不要虚构端口。
|
||||
- 无法从项目证据确定的命令写为 `n/a`,并在结果中列为待配置项。
|
||||
- 保留 `docs/ack/kit/core/` 引用,不复制 core 内容。
|
||||
- 只写项目差异,不复制 `references/` 中的通用规范。
|
||||
6. 完善 `docs/ack/tasks.yaml` 的项目信息。纯初始化且用户没有提供真实任务时,
|
||||
删除模板示例任务并保留 `tasks: []`;不要虚构需求或缺陷。
|
||||
7. 更新 `updatedAt`,并运行:
|
||||
|
||||
```bash
|
||||
python3 docs/ack/kit/scripts/validate_tasks.py docs/ack/tasks.yaml
|
||||
python3 <ack-skill-dir>/scripts/validate_tasks.py docs/ack/tasks.yaml
|
||||
```
|
||||
|
||||
8. 检查 `project.md` 与 `tasks.yaml` 是否仍有 `<...>` 占位符。结构校验通过且
|
||||
必填项目事实完整时才称“初始化完成”;否则称“部分完成”并列出缺失值。
|
||||
9. 报告创建的路径、软链接或复制模式、检测到的命令、校验结果和下一步。除非用户
|
||||
明确要求,不提交、不推送。
|
||||
9. 报告创建的路径、检测到的命令、校验结果和下一步。除非用户明确要求,不提交、
|
||||
不推送。
|
||||
|
||||
## 检查
|
||||
|
||||
1. 检查以下路径:
|
||||
- `docs/ack/kit`
|
||||
- `docs/ack/project.md`
|
||||
- `docs/ack/tasks.yaml`
|
||||
2. 确认 `kit` 可访问 `VERSION`、`core/`、`templates/` 和 `scripts/`。软链接模式下
|
||||
同时报告其真实目标。
|
||||
3. 对比 `tasks.yaml` 的 `kitVersion` 与 `kit/VERSION`。
|
||||
4. 查找未替换占位符,并核对项目路径、覆盖层路径、Developer 白盒命令、Test
|
||||
2. 读取 `<ack-skill-dir>/VERSION`,对比 `tasks.yaml` 的 `ackVersion`。旧项目只有
|
||||
`ackVersion` 时仍可读取,但建议迁移为 `ackVersion`。
|
||||
3. 查找未替换占位符,并核对项目路径、覆盖层路径、Developer 白盒命令、Test
|
||||
黑盒命令和 Base URL。
|
||||
5. 运行任务板校验器。只报告证据明确的问题,不因可选字段缺失而宣称失败。
|
||||
6. 检查不会自动修复或覆盖现有配置;用户明确要求修复后再修改。
|
||||
4. 使用 `<ack-skill-dir>/scripts/validate_tasks.py` 校验任务板。只报告证据明确的
|
||||
问题,不因可选字段缺失而宣称失败。
|
||||
5. 检查不会自动修复或覆盖现有配置;用户明确要求修复后再修改。
|
||||
|
||||
## 工作
|
||||
|
||||
@@ -73,8 +77,8 @@ description: >-
|
||||
2. 依次读取:
|
||||
- `docs/ack/project.md`
|
||||
- `docs/ack/tasks.yaml`
|
||||
- `docs/ack/kit/core/kickoff.md`
|
||||
- kickoff 指定且与当前任务相关的 core 文件
|
||||
- `<ack-skill-dir>/references/kickoff.md`
|
||||
- kickoff 指定且与当前任务相关的 references 文件
|
||||
3. 当前会话担任 Coordinator,遵守项目覆盖层中的命令、路径权限、模型路由和
|
||||
worker 复用规则。项目覆盖层优先于通用示例命令。
|
||||
4. 新需求先写产品文档、任务拆分与可观测验收信号,更新 `tasks.yaml` 并校验,
|
||||
@@ -87,7 +91,8 @@ description: >-
|
||||
## 边界
|
||||
|
||||
- 不修改或追加任何项目 Agent 指令文件,包括 `AGENTS.md`。
|
||||
- 不在 skill 中维护第二份 ACK core、模板或任务 schema。
|
||||
- 不在项目中维护第二份 ACK 通用规范、模板或任务 schema。
|
||||
- 不猜测项目命令、服务地址、worker handle 或模型名称。
|
||||
- 不覆盖已有 `docs/ack` 文件,不擅自提交、推送、创建终端或新 worktree。
|
||||
- kit 初始化的机械操作始终委托给 `skiff kit init ack`。
|
||||
- 项目只保存 `docs/ack/project.md` 和 `docs/ack/tasks.yaml`;通用资源始终从当前
|
||||
ACK Skill 目录读取。
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
0.8.1
|
||||
@@ -0,0 +1,75 @@
|
||||
# notes-web Agent 协作协议(示例,项目覆盖层)
|
||||
|
||||
> 本项目基于 ack v0.8.1。
|
||||
> 通用规范由 `/ack` 从 Skill 自身的 `references/` 读取,本文件只填项目差异。
|
||||
> 覆盖层文件放在 `docs/ack/project.md`,不占用 `AGENTS.md`。
|
||||
> `docs/ack/` 只保存 `project.md` 与 `tasks.yaml`。
|
||||
|
||||
## 项目概览
|
||||
|
||||
- 项目:`notes-web`
|
||||
- 技术栈:`TypeScript + React (Vite) + Go`
|
||||
- 运行命令:`npm run dev`(前端)、`go run ./server`(后端)
|
||||
- Base URL:`http://localhost:5173`
|
||||
- 任务板:`docs/ack/tasks.yaml`
|
||||
- 覆盖层文件:`docs/ack/project.md`
|
||||
|
||||
## 稳定规范(引用,不重复)
|
||||
|
||||
- 开始一个需求(启动手册):`references/kickoff.md`
|
||||
- 角色 / 权限 / 状态机 / 完成定义:`references/roles-and-permissions.md`
|
||||
- 模型档位与升级规则:`references/model-routing.md`
|
||||
- 闭环流程(含手动模式、worktree 对齐):`references/closed-loop.md`
|
||||
- 优化方法(验收信号、三轮策略):`references/optimization-method.md`
|
||||
- 派发 prompt 模板:`references/prompt-templates.md`
|
||||
- Orca 编排命令:`references/orca-adapter.md`
|
||||
|
||||
## 模型档位
|
||||
|
||||
| 角色 | 默认档位 | 本项目实际 |
|
||||
|------|----------|------------|
|
||||
| Coordinator (PM) | 强模型 | claude-sonnet-5-thinking-high |
|
||||
| Test | 中低模型 | 默认(中低) |
|
||||
| Developer | 中低模型 | 默认(中低),架构任务临时升级 |
|
||||
|
||||
## 路径权限
|
||||
|
||||
| 路径 | Coordinator | Test | Developer | 说明 |
|
||||
|------|:-----------:|:----:|:---------:|------|
|
||||
| `docs/spec/**` | R/W | Read-only | Read-only | 产品规格(PM 拥有) |
|
||||
| `tests/browser/**` | Read-only | R/W | Read-only | 浏览器回归用例(Test 拥有) |
|
||||
| `.qa-records/**` | Read-only | R/W | Read-only | 复测记录(gitignore) |
|
||||
| `web/**`、`server/**` | Read-only | Read-only | R/W | 应用源码 |
|
||||
| `**/*_test.go`、`web/**/*.test.tsx` | Read-only | Read-only | R/W | 单元测试 |
|
||||
| `config/*.example.*` | Read-only | Read-only | R/W | 可提交配置模板 |
|
||||
| `.env`、`config/local.*` | Read-only | Read-only | Read-only | 本地私有配置 |
|
||||
| `tasks.yaml` | R/W | Read-only | Read-only | 只有 Coordinator 写 |
|
||||
|
||||
## 命令
|
||||
|
||||
Developer 白盒验证:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
go test ./...
|
||||
npm run dev # 本地起前端
|
||||
```
|
||||
|
||||
Test 黑盒复测:
|
||||
|
||||
```bash
|
||||
curl -s http://localhost:5173/api/health
|
||||
curl -s -X POST http://localhost:5173/api/fix/preview -d @fixtures/preview.json
|
||||
# 浏览器回归:tests/browser/cases/*.md
|
||||
```
|
||||
|
||||
任务板校验由 `/ack` 使用 Skill 自带的 `scripts/validate_tasks.py` 执行。
|
||||
|
||||
## 硬规则(其余见 references/)
|
||||
|
||||
- 三角色独立:Coordinator 只编排、Test 只验证、Developer 只实现。
|
||||
- 模型分层:Coordinator 强模型不跑测试,Test/Developer 中低模型(见 references/model-routing.md)。
|
||||
- `worker_done` 与复测报告都不等于完成,必须 Test 独立复测 + Coordinator 终检后才能 `verified`。
|
||||
- 只有 Coordinator 写 `tasks.yaml`;Test 与 Developer 只读。
|
||||
- 每个任务最多派发 3 轮,仍不过标记 `leftover` 并继续。
|
||||
- 不提交或推送,除非用户明确要求。
|
||||
@@ -0,0 +1,115 @@
|
||||
# 填好的最小示例(虚构的 notes-web 项目)。可用 scripts/validate_tasks.py 校验通过。
|
||||
version: 1
|
||||
updatedAt: "2026-07-06T09:40:00+08:00"
|
||||
source: "Coordinator (PM) Agent"
|
||||
ackVersion: "0.8.1"
|
||||
project:
|
||||
name: "notes-web"
|
||||
repoPath: "/home/dev/notes-web"
|
||||
baseUrl: "http://localhost:5173"
|
||||
devWorktree: "/home/dev/notes-web-wt/fix-preview"
|
||||
|
||||
summary:
|
||||
verified: ["BUG-002"]
|
||||
open: []
|
||||
failedRetest: []
|
||||
leftovers: ["BUG-003"]
|
||||
|
||||
tasks:
|
||||
- id: "BUG-002"
|
||||
type: "bug"
|
||||
title: "预览变更点击后不显示 diff 行"
|
||||
priority: "P0"
|
||||
status: "verified"
|
||||
assignee: "developer"
|
||||
component: "web/app/fix/page.tsx"
|
||||
specRefs:
|
||||
- "docs/spec/fix-preview.md#preview"
|
||||
testRefs:
|
||||
- "tests/browser/cases/01-preview.md"
|
||||
description: >
|
||||
用户在 /fix 页点击“预览变更”后,确认区不渲染 API 返回的 diff。
|
||||
stepsToReproduce:
|
||||
- "打开 /fix?fileId=1"
|
||||
- "搜索并选择候选项"
|
||||
- "点击“预览变更”"
|
||||
expected: >
|
||||
确认区出现 title、修改前值、修改后值、coverChanged 提示四行。
|
||||
actual: >
|
||||
API 返回 code=0,但页面确认区为空。
|
||||
evidence:
|
||||
browser: "确认区 DOM 为空,无 diff 行"
|
||||
api: "POST /api/fix/preview -> code=0, 含 diff 字段"
|
||||
logs: "无报错"
|
||||
verification:
|
||||
commands:
|
||||
- "npm run build"
|
||||
- "curl -s -X POST localhost:5173/api/fix/preview -d @fixtures/preview.json"
|
||||
browser:
|
||||
page: "/fix?fileId=1"
|
||||
checks:
|
||||
- "预览后出现 4 行 diff:title/before/after/coverChanged"
|
||||
dispatch:
|
||||
taskId: "orca-task-88"
|
||||
dispatchId: "orca-disp-91"
|
||||
worker: "dev-worker-1"
|
||||
rounds:
|
||||
- round: 1
|
||||
result: failed
|
||||
evidence: "只渲染了 title,缺少 before/after/coverChanged"
|
||||
- round: 2
|
||||
result: passed
|
||||
evidence: "复测 4 行 diff 全部出现,取消不触发写入"
|
||||
resolution:
|
||||
fixedBy: "dev-worker-1"
|
||||
verifiedBy: "test-worker-1"
|
||||
verifiedAt: "2026-07-06T09:38:00+08:00"
|
||||
leftoverReason: null
|
||||
|
||||
- id: "BUG-003"
|
||||
type: "bug"
|
||||
title: "并发保存偶发覆盖他人修改"
|
||||
priority: "P1"
|
||||
status: "leftover"
|
||||
assignee: "developer"
|
||||
component: "server/store/notes.go"
|
||||
specRefs:
|
||||
- "docs/spec/concurrency.md"
|
||||
testRefs: []
|
||||
description: >
|
||||
两个会话同时保存同一条 note 时,后写覆盖先写,无冲突提示。
|
||||
stepsToReproduce:
|
||||
- "会话 A、B 同时打开 note 42"
|
||||
- "A 保存,B 保存"
|
||||
expected: >
|
||||
B 保存时应检测到版本变化并提示冲突,而非静默覆盖。
|
||||
actual: >
|
||||
B 直接覆盖 A 的修改,无提示。
|
||||
evidence:
|
||||
api: "两次 PUT /api/notes/42 均返回 200,无版本校验"
|
||||
verification:
|
||||
commands:
|
||||
- "go test ./server/store/..."
|
||||
browser:
|
||||
page: "/notes/42"
|
||||
checks:
|
||||
- "并发保存时后写方收到冲突提示"
|
||||
dispatch:
|
||||
taskId: "orca-task-90"
|
||||
dispatchId: "orca-disp-95"
|
||||
worker: "dev-worker-1"
|
||||
rounds:
|
||||
- round: 1
|
||||
result: failed
|
||||
evidence: "加了版本号但未在写入路径校验"
|
||||
- round: 2
|
||||
result: failed
|
||||
evidence: "校验只覆盖 API,未覆盖批量导入路径"
|
||||
- round: 3
|
||||
result: failed
|
||||
evidence: "乐观锁与前端重试逻辑冲突,需重新设计"
|
||||
resolution:
|
||||
fixedBy: null
|
||||
verifiedBy: null
|
||||
verifiedAt: null
|
||||
leftoverReason: "failed after 3 supervised developer rounds; 需重新设计并发模型"
|
||||
@@ -0,0 +1,51 @@
|
||||
# ACK 接入清单
|
||||
|
||||
## 安装与初始化
|
||||
|
||||
- [ ] ACK Skill 已全局安装或安装到当前项目。
|
||||
- [ ] 已运行 `skiff init ack --project <project-root>`。
|
||||
- [ ] `docs/ack/` 只包含项目自己的 `project.md` 与 `tasks.yaml`。
|
||||
- [ ] 项目中没有 ACK Skill 的复制目录或 `kit`、`framework` 软链接。
|
||||
- [ ] `tasks.yaml` 使用 `ackVersion` 记录 ACK Skill 版本。
|
||||
|
||||
## 项目覆盖层
|
||||
|
||||
- [ ] `project.md` 只保存项目差异,不复制 Skill 的通用规范。
|
||||
- [ ] `tasks.yaml` 的 `project.overlayFile` 指向实际覆盖层。
|
||||
- [ ] 技术栈、运行、构建、单测和集成测试命令均来自项目证据。
|
||||
- [ ] Coordinator、Developer、Test 的模型档位和升级规则已明确。
|
||||
|
||||
## 路径权限
|
||||
|
||||
- [ ] Coordinator 可写规格和任务板。
|
||||
- [ ] Test 可写集成测试与复测记录,但不能改源码。
|
||||
- [ ] Developer 可写源码与单元测试,但不能改规格或黑盒验收。
|
||||
- [ ] 私有配置只读且不提交。
|
||||
- [ ] `tasks.yaml` 只有 Coordinator 写。
|
||||
|
||||
## 任务板
|
||||
|
||||
- [ ] 已替换项目名、仓库路径、Base URL、worktree 和覆盖层路径。
|
||||
- [ ] 没有真实任务时使用 `tasks: []`。
|
||||
- [ ] 真实任务的验收是可观测信号。
|
||||
- [ ] 已运行 `<ack-skill-dir>/scripts/validate_tasks.py` 并通过。
|
||||
|
||||
## 编排
|
||||
|
||||
- [ ] 已选择 Orca 或手动模式。
|
||||
- [ ] 派发前优先复用同 worktree、同角色、同配置的空闲 worker。
|
||||
- [ ] Developer 与 Test 的启动命令通过校验。
|
||||
- [ ] 多 worktree 场景只有一个权威 `tasks.yaml`。
|
||||
- [ ] Test 使用的服务来自正确 worktree。
|
||||
|
||||
## 闭环
|
||||
|
||||
- [ ] `worker_done` 不直接视为完成。
|
||||
- [ ] Test 独立复测后由 Coordinator 读取证据终检。
|
||||
- [ ] 每轮写入 `dispatch.rounds`。
|
||||
- [ ] 三轮失败后标记 `leftover` 并填写原因。
|
||||
- [ ] `leftover` 不阻塞其它任务。
|
||||
|
||||
首次接入建议选择一个低风险问题跑完整闭环。项目差异写回
|
||||
`docs/ack/project.md`;通用问题回流到 ACK Skill 的 `references/`、`templates/`
|
||||
或 `scripts/`,并更新 `VERSION`。
|
||||
@@ -0,0 +1,198 @@
|
||||
# 闭环流程(稳定核心,编排无关)
|
||||
|
||||
本文件定义**与具体编排工具无关**的三角色协作闭环。运行时调度可以用 Orca(见 `orca-adapter.md`),也可以手动跑(见下方「手动模式」)。
|
||||
|
||||
原则:调度消息只是运行时载体,**所有结论都必须回写到 `tasks.yaml`**(事实源),不要把消息当最终记录。角色定义见 `roles-and-permissions.md`:Coordinator 只编排、Test 只验证、Developer 只实现。
|
||||
|
||||
---
|
||||
|
||||
## 编排抽象
|
||||
|
||||
无论用什么工具,闭环都由这几个能力组成。注意 `dispatch` 有两个目标(Developer 与 Test):
|
||||
|
||||
| 抽象动作 | 含义 | Orca 实现 | 手动实现 |
|
||||
|----------|------|-----------|----------|
|
||||
| `prepare(task)` | Coordinator 把任务和验收信号写进 `tasks.yaml` | 同左 | 同左 |
|
||||
| `dispatch(task, developer)` | 把修复任务连同上下文交给 Developer | `orca orchestration dispatch` | 复制 prompt 到 Developer 终端/会话 |
|
||||
| `dispatch(task, test)` | 把复测任务连同验收信号交给 Test | `orca orchestration dispatch` | 复制 prompt 到 Test 终端/会话 |
|
||||
| `wait()` | 等待 `worker_done` / `retest_result` / `escalation` / `decision_gate` | `orca orchestration check --wait` | 人工等待回报 |
|
||||
| `gate(task)` | Coordinator 读 Test 证据并对齐原始意图(不重测) | 同左 | 同左 |
|
||||
| `writeback(task, result)` | Coordinator 把结果写回 `tasks.yaml` | 同左 | 同左 |
|
||||
|
||||
派发用的 prompt 见 `prompt-templates.md`。状态流转见 `roles-and-permissions.md` §「任务状态机」。**独立复测由 Test 执行,不是 Coordinator**;Coordinator 只做读证据的终检。
|
||||
|
||||
---
|
||||
|
||||
## 标准闭环
|
||||
|
||||
```text
|
||||
Coordinator 发现或读取 open 任务
|
||||
-> prepare:写/补全 tasks.yaml 验收信号
|
||||
-> 决定 worktree:当前 worktree 起子 agent,还是新建隔离 worktree(见下节「子任务放哪」)
|
||||
-> 解析 worker:先复用同 worktree、同角色的空闲 worker;没有可复用项时才校验命令并新建(见 orca-adapter.md)
|
||||
-> dispatch 给 Developer(--to <worker handle>)
|
||||
-> wait:Developer 的 worker_done / escalation
|
||||
-> writeback fixed_by_dev
|
||||
-> dispatch 给 Test(retesting)
|
||||
-> wait:Test 的 retest_result
|
||||
-> Test 通过:gate(Coordinator 读证据对齐意图)
|
||||
-> 通过 gate:writeback verified
|
||||
-> gate 不满足意图:writeback failed_retest,带意图差异再派发 Developer
|
||||
-> Test 失败:writeback failed_retest,追加证据,再派发 Developer(最多累计三轮)
|
||||
-> 累计三轮失败:writeback leftover,继续下一个任务
|
||||
```
|
||||
|
||||
一次派发只修一个明确问题(细则见 `optimization-method.md` §「每轮派发只修一个明确问题」)。
|
||||
「决定 worktree」「解析 worker」两步的决策见下节与 `model-routing.md` / `orca-adapter.md`。
|
||||
|
||||
---
|
||||
|
||||
## 子任务放哪:新 worktree 还是当前 worktree
|
||||
|
||||
Coordinator 派发前先决定 Developer/Test 在哪工作。两种方式:
|
||||
|
||||
**方式 1:当前 worktree 复用或起子 agent(终端)**
|
||||
|
||||
```bash
|
||||
# 先按 orca-adapter.md 的 worker 复用流程查找空闲终端;没有时才创建
|
||||
orca terminal create --worktree active --command "cursor-agent --yolo --model auto" --title "ACK-DEV-CURSOR-AUTO-1" --json
|
||||
```
|
||||
|
||||
- 适合:串行闭环、一次一个 Developer 任务、小改动、Test 要复测的正是 Developer 改的那棵树。
|
||||
- 优点:单一服务实例、无跨 worktree 对齐困扰、开销小。
|
||||
- 风险:多个 agent 同时改同一棵树会互相踩(半构建状态、git 冲突)。
|
||||
|
||||
**方式 2:新建隔离 worktree,再在其中起子 agent**
|
||||
|
||||
```bash
|
||||
orca worktree create --name <feature> --base-branch <base> --json
|
||||
# 然后先查该 worktree 的同角色空闲终端;没有时才创建
|
||||
orca terminal create --worktree path:<new> --command "cursor-agent --yolo --model auto" --title "ACK-DEV-CURSOR-AUTO-1"
|
||||
```
|
||||
|
||||
- 适合:并行多个互不依赖的子任务、大/高风险/实验性改动、要保持基线分支干净(如 prod 不动、feature 走独立分支)、要独立 build 或跑独立服务实例、best-of-N 尝试。
|
||||
- 优点:隔离 + 并行 + 易回滚(删 worktree 即可)。
|
||||
- 成本:各自 build/依赖、服务要用不同端口、必须处理下节的 worktree/服务对齐。
|
||||
|
||||
**决策速查:**
|
||||
|
||||
| 情况 | 选择 |
|
||||
|------|------|
|
||||
| 一次一个任务、串行修复 | 当前 worktree 子 agent |
|
||||
| 多个任务并行、互不依赖 | 每个任务一个新 worktree |
|
||||
| 高风险 / 实验 / 可能整体丢弃 | 新 worktree |
|
||||
| 要保持基线分支干净 | 新 worktree(feature 分支)|
|
||||
| 小改动、追求快 | 当前 worktree |
|
||||
|
||||
**任务板(SSOT)只落一处**:无论开几个 worktree,`tasks.yaml` 只认一个权威副本(通常在基线/协调所在 worktree),由 Coordinator 单写。不要每个 worktree 各留一份会分叉的任务板。模型固定方式见 `model-routing.md` 与 `orca-adapter.md`。
|
||||
|
||||
---
|
||||
|
||||
## 手动模式(无 Orca)
|
||||
|
||||
没有编排工具时,闭环不变,只是 `dispatch` / `wait` 由人工承担:
|
||||
|
||||
1. Coordinator 在 `tasks.yaml` 写好任务和验收信号。
|
||||
2. 用 `prompt-templates.md` §1 的初始派发模板生成 prompt,手动发给 Developer(另一个会话/终端/人)。
|
||||
3. Developer 完成后按 worker_done 模板回报。
|
||||
4. Coordinator 写回 `fixed_by_dev`,用 `prompt-templates.md` §3 的复测派发模板把任务发给 Test。
|
||||
5. Test 独立复测后按复测报告模板回报证据。
|
||||
6. Coordinator 做终检并回写 `tasks.yaml`:通过 `verified`,不过 `failed_retest`。
|
||||
7. 失败则用「复测失败再派发模板」重新发给 Developer,最多累计三轮。
|
||||
|
||||
手动模式下同样遵守:worker_done / 复测报告都不等于最终结论、只有 Coordinator 写 `tasks.yaml`、三轮失败留档。
|
||||
|
||||
---
|
||||
|
||||
## Test 复测(编排无关)
|
||||
|
||||
即使 Developer 的 worker_done 写了"全部通过",Test 仍必须独立复测:
|
||||
|
||||
```bash
|
||||
git status --short
|
||||
<test_commands>
|
||||
curl -s <base_url>/health-or-summary
|
||||
```
|
||||
|
||||
浏览器复测建议记录:
|
||||
|
||||
```text
|
||||
BASE_URL:
|
||||
page:
|
||||
steps:
|
||||
expected:
|
||||
actual:
|
||||
snapshot evidence:
|
||||
```
|
||||
|
||||
Test 只回传证据,不写 `tasks.yaml`;由 Coordinator 落盘。
|
||||
|
||||
---
|
||||
|
||||
## Coordinator 终检(gate)
|
||||
|
||||
Test 报通过后,Coordinator 不重测,而是做一次读证据的终检:
|
||||
|
||||
- Test 证据是否覆盖了任务的**每一条**验收信号(见 `optimization-method.md` §1)。
|
||||
- 结果是否符合任务的**原始意图**,而不只是通过了字面文案。
|
||||
- 运行环境是否对齐(见下方「服务与 worktree 对齐」)。
|
||||
|
||||
终检不通过(例如意图漂移、验收信号写漏)时,回写 `failed_retest` 并把意图差异带给下一轮 Developer,必要时先补全验收信号。
|
||||
|
||||
---
|
||||
|
||||
## 服务与 worktree 对齐(防假通过/假失败)
|
||||
|
||||
Test 复测前记录运行环境:
|
||||
|
||||
```bash
|
||||
pwd
|
||||
git rev-parse --abbrev-ref HEAD
|
||||
git rev-parse --short HEAD
|
||||
```
|
||||
|
||||
```text
|
||||
serverPid:
|
||||
serverCommand:
|
||||
BASE_URL:
|
||||
frontendDir:
|
||||
worktreePath:
|
||||
```
|
||||
|
||||
如果开发在 `<dev_worktree>` 修复,但服务跑的是另一个 worktree,必须**停止并重启正确服务**后再测。长跑服务或静态前端尤其要确认加载的是最新构建产物。
|
||||
|
||||
---
|
||||
|
||||
## 结果回写
|
||||
|
||||
Coordinator 回写 `tasks.yaml` 时按状态填写(字段结构见 `templates/tasks.schema.json`):
|
||||
|
||||
```yaml
|
||||
# 通过(Test 复测 + Coordinator 终检)
|
||||
status: verified
|
||||
resolution:
|
||||
verifiedAt: "<timestamp>"
|
||||
verifiedBy: "test"
|
||||
evidence:
|
||||
verification: "<commands passed>"
|
||||
browser: "<snapshot or API evidence>"
|
||||
```
|
||||
|
||||
```yaml
|
||||
# 失败但未满三轮
|
||||
status: failed_retest
|
||||
dispatch:
|
||||
rounds:
|
||||
- round: 1
|
||||
result: failed
|
||||
evidence: "<latest evidence from Test or gate>"
|
||||
```
|
||||
|
||||
```yaml
|
||||
# 累计三轮失败
|
||||
status: leftover
|
||||
resolution:
|
||||
leftoverReason: "failed after 3 supervised developer rounds"
|
||||
evidence:
|
||||
final: "<latest failing evidence>"
|
||||
```
|
||||
@@ -0,0 +1,92 @@
|
||||
# 在新项目初始化 ACK
|
||||
|
||||
本文件说明如何把 ACK 的项目状态初始化到目标项目。ACK Skill 自身已经通过 Agent
|
||||
的 Skill 机制安装;项目不复制、不链接 Skill 内容。
|
||||
|
||||
## 前提与边界
|
||||
|
||||
开始前确认:
|
||||
|
||||
1. 目标项目根目录。
|
||||
2. ACK Skill 已全局安装或安装到当前项目。
|
||||
3. `skiff` 命令可用。
|
||||
|
||||
不要覆盖已有的 `docs/ack/project.md`、`docs/ack/tasks.yaml`、`AGENTS.md` 或其它
|
||||
Agent 指令文件。不要把 token、`.env` 内容或其它私有配置写入 ACK 项目状态。
|
||||
|
||||
## 初始化
|
||||
|
||||
在目标项目执行:
|
||||
|
||||
```bash
|
||||
skiff init ack
|
||||
```
|
||||
|
||||
或显式指定项目:
|
||||
|
||||
```bash
|
||||
skiff init ack --project <project-root>
|
||||
```
|
||||
|
||||
命令从 ACK Skill 自带的 `templates/` 生成:
|
||||
|
||||
```text
|
||||
docs/ack/
|
||||
├── project.md
|
||||
└── tasks.yaml
|
||||
```
|
||||
|
||||
如果任一目标文件已经存在,命令会拒绝覆盖。初始化过程不会创建 `kit`、
|
||||
`framework` 或其它指向 Skill 的软链接。
|
||||
|
||||
## 完善项目覆盖层
|
||||
|
||||
编辑 `docs/ack/project.md`,填入:
|
||||
|
||||
- 项目名、技术栈、运行命令和 Base URL。
|
||||
- Coordinator、Developer、Test 的实际模型档位。
|
||||
- 规格、集成测试、源码、单元测试和私有配置的路径权限。
|
||||
- Developer 白盒验证命令。
|
||||
- Test 黑盒复测命令。
|
||||
|
||||
无法从项目证据确定的值写为 `n/a`,不要猜测。
|
||||
|
||||
## 完善任务板
|
||||
|
||||
编辑 `docs/ack/tasks.yaml`:
|
||||
|
||||
- `ackVersion` 使用 ACK Skill 的 `VERSION`。
|
||||
- `updatedAt` 使用当前带时区时间。
|
||||
- `project.name`、`repoPath`、`devWorktree` 和 `overlayFile` 使用真实值。
|
||||
- 非服务项目的 `baseUrl` 写为 `n/a`。
|
||||
- 没有真实任务时使用 `tasks: []`,不要保留或虚构示例任务。
|
||||
|
||||
每个真实任务的验收必须是可观测信号,例如可见文本、API 状态和字段,或明确的交互
|
||||
结果;不要只写“功能正常”。
|
||||
|
||||
## 校验
|
||||
|
||||
Agent 从当前 `SKILL.md` 解析 ACK Skill 目录后运行:
|
||||
|
||||
```bash
|
||||
python3 <ack-skill-dir>/scripts/validate_tasks.py docs/ack/tasks.yaml
|
||||
```
|
||||
|
||||
同时确认:
|
||||
|
||||
- `project.md` 和 `tasks.yaml` 没有未替换的 `<...>` 占位符。
|
||||
- `project.overlayFile` 指向真实文件。
|
||||
- Developer 与 Test 的验证命令可执行。
|
||||
- 网站或 API 项目写清服务启动、重启和 Base URL。
|
||||
|
||||
## 初始化报告
|
||||
|
||||
完成后报告:
|
||||
|
||||
- 创建或确认的两个项目文件。
|
||||
- 检测到的技术栈和验证命令。
|
||||
- 任务板校验结果。
|
||||
- 仍需用户补充的值。
|
||||
|
||||
只有结构校验通过且必填项目事实完整时才称“初始化完成”;否则称“部分完成”,并列出
|
||||
具体阻塞项。除非用户明确要求,不提交、不推送。
|
||||
@@ -0,0 +1,97 @@
|
||||
# 如何开始一个需求(Kickoff)
|
||||
|
||||
从零开一个需求的启动手册。角色/权限见 `roles-and-permissions.md`,闭环见 `closed-loop.md`,模型见 `model-routing.md`。
|
||||
|
||||
---
|
||||
|
||||
## 前提:谁是 Coordinator
|
||||
|
||||
**你(发起编排的强模型会话)就是 Coordinator (PM) / 产品。** 你负责写文档、拆任务、编排、终检,**不亲自写代码、不亲自跑测试**。开发和测试是另起的 worker agent;具体 CLI、模型、reasoning effort 和执行模式必须先读项目覆盖层 `docs/ack/project.md`,禁止照抄未核对的默认命令。
|
||||
|
||||
---
|
||||
|
||||
## 第 0 步:给 Coordinator 的开场指令(复制改需求)
|
||||
|
||||
```text
|
||||
我要做一个新需求:<一句话需求>。
|
||||
你作为 ack 的 Coordinator(PM),按 ACK Skill 的 references 规范执行:
|
||||
|
||||
1. 先读 docs/ack/project.md、references/roles-and-permissions.md、closed-loop.md、optimization-method.md。
|
||||
2. 写产品文档到 docs/(PRD / 交互 / 验收),把需求拆成任务,每个任务的验收写成可观测信号(可见文本 / API 结果 / 交互结果)。
|
||||
3. 把任务写进 docs/ack/tasks.yaml(只有你写),跑 validate 校验结构。
|
||||
4. 先把「产品文档 + 任务拆分 + 验收信号」给我确认,不要急着派发。
|
||||
5. 我确认后,按 ack 闭环循环:先按 docs/ack/project.md 校验 Developer/Test worker 启动命令,
|
||||
dispatch 开发 → worker_done → dispatch 测试独立复测 → 你读证据终检 → 回写 tasks.yaml;
|
||||
每个任务最多三轮,三轮不过记 leftover 并升级我复盘。
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 第 1 步:Coordinator 产出(确认前)
|
||||
|
||||
1. 产品文档 → `docs/PRD-<feature>.md` 等(Coordinator R/W)。
|
||||
2. 任务板 → `docs/ack/tasks.yaml`,每条任务带 `expected` + `verification`,验收写成可观测信号(见 `optimization-method.md` §1)。
|
||||
3. 校验结构:
|
||||
|
||||
```bash
|
||||
python3 <ack-skill-dir>/scripts/validate_tasks.py docs/ack/tasks.yaml
|
||||
```
|
||||
|
||||
4. **停下来给人确认**——这是强模型该花时间的地方,不要跳过。
|
||||
|
||||
---
|
||||
|
||||
## 第 2 步:决定 worktree
|
||||
|
||||
见 `closed-loop.md` §「子任务放哪」:
|
||||
|
||||
- 需求大 / 要并行 / 要保基线分支干净 → 新建隔离 worktree。
|
||||
- 小改动 / 串行修复 → 当前 worktree 起子 agent。
|
||||
|
||||
---
|
||||
|
||||
## 第 3 步:复用或启动 worker
|
||||
|
||||
先读 `docs/ack/project.md` 的项目覆盖规则,再按 `orca-adapter.md` §「解析并复用 worker」执行:先列出现有终端和活跃任务,优先复用同 worktree、同角色、配置兼容且空闲的 worker。只有没有可复用项时才创建新终端;如果项目提供 `validate_worker_command.py`,校验未通过时不得创建。
|
||||
|
||||
```bash
|
||||
# Codex 示例(模型与执行模式以项目覆盖层为准)
|
||||
DEV_CMD='codex --dangerously-bypass-approvals-and-sandbox -m gpt-5.6-terra -c model_reasoning_effort=medium'
|
||||
TEST_CMD='codex --dangerously-bypass-approvals-and-sandbox -m gpt-5.6-luna -c model_reasoning_effort=low'
|
||||
python3 <ack-skill-dir>/scripts/validate_worker_command.py --role developer --command "$DEV_CMD"
|
||||
python3 <ack-skill-dir>/scripts/validate_worker_command.py --role test --command "$TEST_CMD"
|
||||
orca terminal create --worktree active --command "$DEV_CMD" --title "ACK-DEV-CODEX-TERRA-1" --json
|
||||
orca terminal create --worktree active --command "$TEST_CMD" --title "ACK-TEST-CODEX-LUNA-1" --json
|
||||
|
||||
# Cursor 示例
|
||||
CURSOR_CMD='cursor-agent --yolo --model auto'
|
||||
python3 <ack-skill-dir>/scripts/validate_worker_command.py --role developer --command "$CURSOR_CMD"
|
||||
orca terminal create --worktree active --command "$CURSOR_CMD" --title "ACK-DEV-CURSOR-AUTO-1" --json
|
||||
```
|
||||
|
||||
上面的 `terminal create` 都是“没有空闲兼容 worker”时的兜底,不是每次 kickoff 的固定动作。新 worktree 时先 `orca worktree create --name <feature> --base-branch <base>`,再解析该 worktree 的 worker。选型与升级见 `model-routing.md`。新建终端后、dispatch 前必须读取启动信息,确认实际 CLI、模型和 reasoning effort;派发后把实际 handle 写入对应任务的 `dispatch.worker`。
|
||||
|
||||
---
|
||||
|
||||
## 第 4 步:跑闭环(每个任务)
|
||||
|
||||
```text
|
||||
task-create → dispatch 给 DEV → 等 worker_done
|
||||
→ 回写 fixed_by_dev → dispatch 给 TEST 复测 → 等 retest_result
|
||||
→ Coordinator 读证据终检 → 过则 verified,不过则 failed_retest 再派 DEV(最多累计 3 轮)
|
||||
→ 三轮失败:leftover,升级复盘,继续下一个
|
||||
```
|
||||
|
||||
具体命令见 `orca-adapter.md`(Orca)或 `closed-loop.md` §「手动模式」(无 Orca);派发文案见 `prompt-templates.md`。
|
||||
|
||||
---
|
||||
|
||||
## 第 5 步:收尾
|
||||
|
||||
一轮结束时 Coordinator 必须能回答 `optimization-method.md` §「结束条件」的问题:哪些 verified、哪些 leftover、各失败几轮、工作树是否干净、还有没有未处理项。
|
||||
|
||||
---
|
||||
|
||||
## 一句话
|
||||
|
||||
产品文档 + 验收信号写在前(你,强模型)→ 按项目覆盖层校验并启动 DEV/TEST → 核对实际模型 → dispatch / 复测 / 终检循环 → 结论只落 `tasks.yaml`。
|
||||
@@ -0,0 +1,122 @@
|
||||
# 模型路由(稳定核心)
|
||||
|
||||
本文件是**三角色默认模型档位**和**升级规则**的单一事实源(SSOT)。目标:在不牺牲质量的前提下降低 token 和模型成本——把昂贵的强模型留给需要判断的工作,把机械执行交给较弱模型。
|
||||
|
||||
角色定义见 `roles-and-permissions.md`(Coordinator 编排 / Test 验证 / Developer 实现)。本文件只补一层正交的「用哪个档位的模型」。
|
||||
|
||||
---
|
||||
|
||||
## 默认档位
|
||||
|
||||
| 角色 | 默认模型档位 | 理由 |
|
||||
|------|--------------|------|
|
||||
| Coordinator (PM) | 强模型 | 需求拆解、验收信号设计、优先级、终检对齐意图、三轮失败复盘都需要高质量推理 |
|
||||
| Test | 中低模型 | 按既定验收信号执行浏览器/API/脚本,主要做观察、记录、逐条 pass/fail |
|
||||
| Developer | 中低模型(按任务升级) | 多数实现可照规格执行;跨系统、数据迁移、重复失败时再升级 |
|
||||
|
||||
关键点:Coordinator 用强模型但**不亲自跑测试**(测试由 Test 承担),所以强模型的 token 花在思考和终检上,而不是反复点击页面、跑 smoke、复制日志。这一分工天然省 token,同时保持「验证者 ≠ 实现者」。
|
||||
|
||||
---
|
||||
|
||||
## 什么时候用强模型
|
||||
|
||||
- 新需求理解、产品取舍、范围决策。
|
||||
- 架构与数据模型决策。
|
||||
- 把验收写成可观测信号(见 `optimization-method.md` §1)。
|
||||
- 需求含糊、规格与实现/测试冲突时的裁决。
|
||||
- Coordinator 终检:读证据、对齐原始意图。
|
||||
- 重复失败后的根因复盘与重新拆分。
|
||||
|
||||
## 什么时候用中低模型
|
||||
|
||||
- Test:跑浏览器用例、API smoke、逐条比对期望与实际、产出证据。
|
||||
- Developer:从清晰规格实现范围明确的任务、跑构建与单测、回报 worker_done。
|
||||
|
||||
---
|
||||
|
||||
## 升级规则
|
||||
|
||||
**升级到 Coordinator(强模型)复盘**,当:
|
||||
|
||||
- 同一验收路径 Developer 连续失败三轮(见 `optimization-method.md` §4)。
|
||||
- Test 两次仍无法给出清晰失败证据。
|
||||
- 任务需要改动产品范围或验收标准。
|
||||
- 修复涉及持久化数据、破坏性文件操作、安全或回滚。
|
||||
- 规格、测试、实现三者出现冲突。
|
||||
|
||||
**升级 Developer 模型档位**,当:
|
||||
|
||||
- 任务横跨多个子系统。
|
||||
- 改动涉及数据模型或迁移。
|
||||
- 需要设计新的抽象。
|
||||
- 低档位反复产出表面修复。
|
||||
|
||||
升级动作本身由 Coordinator 判断并记录(可写进 `tasks.yaml` 的 `dispatch` 备注或 `resolution`)。
|
||||
|
||||
---
|
||||
|
||||
## 如何给 worker 指定模型(编排相关)
|
||||
|
||||
**模型不由编排层设置。** Orca 的 `orchestration task-create` / `dispatch` 没有 `--model` 参数——`dispatch` 只是把任务投递给一个已存在的终端 handle。**模型在创建 worker 终端、启动 agent CLI 时用 CLI 自带的 flag 固定**,之后该终端的所有 dispatch 都用这个模型。
|
||||
|
||||
**默认不跨 Agent CLI 创建 worker。** Coordinator 应按自己所在的运行环境选择同类 worker:Cursor 会话创建 `cursor-agent` worker,Codex 会话创建 `codex` worker。不要依赖 Coordinator 凭模型回答来猜测运行环境或精确模型名;以实际 CLI / 终端环境为准。只有项目 overlay 或用户明确指定跨 Agent 时,才混用不同 CLI,并记录原因。
|
||||
|
||||
因此「档位 → 具体模型」的映射是 **agent 相关** 的,落地方式见 `orca-adapter.md` §「给 worker 终端固定模型」。常见 CLI:
|
||||
|
||||
| Agent CLI | 指定模型的方式 |
|
||||
|-----------|----------------|
|
||||
| Cursor (`cursor-agent`) | `cursor-agent --model <model>`;`--model auto` 让 Cursor 自动选(推荐给 Test/Developer worker) |
|
||||
| Codex (`codex`) | `codex -m <model> -c model_reasoning_effort=<effort>` |
|
||||
| 其它(opencode 等) | 用各自 CLI 的模型参数或配置 |
|
||||
|
||||
执行模式也必须在创建 worker 时固定,并服从项目覆盖层或用户的明确要求。Cursor 的 YOLO 参数是 `--yolo`;Codex 的等价参数是 `--dangerously-bypass-approvals-and-sandbox`。不要把 Cursor 的 `--yolo` 原样传给 Codex,也不要把裸启动 `codex` 当作“自动选择了正确角色模型”。如果项目提供 worker 命令校验脚本,校验通过是 `terminal create` 的前置条件。
|
||||
|
||||
**ACK 对 Cursor 的默认建议**:Test 与 Developer worker 用 `cursor-agent --yolo --model auto`(自动选型,天然偏向高效模型,符合"中低档位"意图,并按当前项目授权启用 YOLO);需要更强时改成具体强模型并保留 `--yolo`。Coordinator 作为强模型脑,通常就是发起编排的那个会话本身。
|
||||
|
||||
### Codex 默认映射
|
||||
|
||||
| 角色 | 模型 | reasoning effort |
|
||||
|------|------|------------------|
|
||||
| Coordinator (PM) | `gpt-5.6-sol` | `high` |
|
||||
| Developer | `gpt-5.6-terra` | `medium` |
|
||||
| Test | `gpt-5.6-luna` | `low` |
|
||||
| Developer 升级 | `gpt-5.6-sol` | `high`;极复杂任务可用 `xhigh` |
|
||||
|
||||
Codex worker 应明确指定模型和 reasoning effort,不把“未指定模型”当作 Cursor `auto` 的等价物。Codex 未指定模型时使用产品推荐模型,但推荐值可能随版本更新,也不保证符合 Test / Developer 的成本档位。具体模型若失效或被弃用,应保持上面的角色档位不变,只更新本映射;项目也可在 overlay 中覆盖映射。
|
||||
|
||||
### Worker 固定启动命令
|
||||
|
||||
以下是 core 的默认完整命令。Developer/Test worker 禁止裸启动;必须同时固定 Agent CLI、角色模型和执行模式。
|
||||
|
||||
| Agent CLI | 角色 | 完整启动命令 |
|
||||
|-----------|------|--------------|
|
||||
| Codex | Developer | `codex --dangerously-bypass-approvals-and-sandbox -m gpt-5.6-terra -c model_reasoning_effort=medium` |
|
||||
| Codex | Test | `codex --dangerously-bypass-approvals-and-sandbox -m gpt-5.6-luna -c model_reasoning_effort=low` |
|
||||
| Codex | Developer 升级 | `codex --dangerously-bypass-approvals-and-sandbox -m gpt-5.6-sol -c model_reasoning_effort=high` |
|
||||
| Cursor | Developer / Test | `cursor-agent --yolo --model auto` |
|
||||
|
||||
硬规则:
|
||||
|
||||
1. Codex worker 必须带 `--dangerously-bypass-approvals-and-sandbox`;Cursor worker 必须带 `--yolo`。
|
||||
2. 禁止用裸 `codex`、裸 `cursor-agent` 或只指定 CLI 而不指定角色模型。
|
||||
3. 创建终端前先运行项目提供的 worker 命令校验器;校验失败时不得执行 `orca terminal create`。
|
||||
4. 创建终端后、dispatch 前读取启动信息,确认实际 CLI、模型和 reasoning effort 与命令一致。
|
||||
5. Developer 升级到强模型必须由 Coordinator 记录原因;Test 不得复用 Developer 的强模型终端。
|
||||
6. YOLO 会跳过确认和沙箱,只能在用户已明确授权、外层运行环境受控时启用;项目覆盖层可以收紧执行模式,不能静默放宽。
|
||||
|
||||
项目可以覆盖模型名称或收紧权限,但必须在 `project.md` 中写出完整替代命令,不能只写“auto”“默认模型”或依赖当前 CLI 的隐式默认值。
|
||||
|
||||
---
|
||||
|
||||
## 成本原则
|
||||
|
||||
强模型产出高密度、可复用的产物:需求、架构决策、验收信号、任务拆分、失败复盘。
|
||||
中低模型消费这些产物,产出可核对的执行证据:测试结果、快照、API 响应、构建日志、改动文件清单。
|
||||
|
||||
这样把昂贵推理挡在重复执行之外。
|
||||
|
||||
---
|
||||
|
||||
## 一句话
|
||||
|
||||
Coordinator 是脑,Test 是眼,Developer 是手。脑用最强的模型且不做机械测试,眼和手用便宜模型,只有常规闭环卡住时才升级。
|
||||
@@ -0,0 +1,150 @@
|
||||
# 优化方法(稳定核心)
|
||||
|
||||
减少"开发声称完成但复测不过"的循环成本。本文件是**验收信号写法**和**三轮失败策略**的 SSOT,其它文件引用这里。
|
||||
|
||||
三角色分工(Coordinator 编排 / Test 验证 / Developer 实现)见 `roles-and-permissions.md`;复测步骤、Coordinator 终检与环境对齐见 `closed-loop.md`。
|
||||
|
||||
---
|
||||
|
||||
## 1. 先把验收写成可观测信号(SSOT)
|
||||
|
||||
不要只写"页面可用""体验更好"。每个任务至少写三类信号:
|
||||
|
||||
| 类型 | 示例 |
|
||||
|------|------|
|
||||
| 可见文本 | 页面出现 `确认应用标签`、`取消`、`将修改` |
|
||||
| API 结果 | `POST /api/...` 返回 `code=0` 且字段存在 |
|
||||
| 交互结果 | 点击按钮后出现确认区;取消后不触发写入 |
|
||||
|
||||
好的验收:
|
||||
|
||||
```text
|
||||
点击"预览变更"后,页面必须出现 API 返回的 diff 行:
|
||||
- title
|
||||
- 修改前值
|
||||
- 修改后值
|
||||
- coverChanged 提示
|
||||
```
|
||||
|
||||
不好的验收:
|
||||
|
||||
```text
|
||||
预览功能正常。
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 回报必须带证据,不带结论
|
||||
|
||||
Developer 的 `worker_done` 应报告:改了哪些文件、跑了哪些命令、自己如何复现验收路径、仍可能有的风险。Test 的复测报告同理:跑了哪些命令、命中/缺失了哪些验收信号、实际观察到什么、证据(snapshot / API 结果)。两者的"结论"都不作数,只有 Coordinator 落盘的 `tasks.yaml` 才是事实。
|
||||
|
||||
不要写:
|
||||
|
||||
```text
|
||||
已完成,应该可以了。
|
||||
```
|
||||
|
||||
要写:
|
||||
|
||||
```text
|
||||
修改 web/app/fix/page.tsx。已运行 npm run build、go test ./...。
|
||||
手测 /fix?fileId=1:搜索、选择候选、预览、确认区都可见。
|
||||
风险:未执行真实写文件 apply。
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 验证权在 Test,Coordinator 只信证据
|
||||
|
||||
即使 Developer 的 worker_done 写了"全部通过",也必须由独立的 Test 复测(验证者 ≠ 实现者)。完整复测步骤与 worktree/服务对齐见 `closed-loop.md`。独立复测可避免三类假通过:测错服务实例、测到旧构建产物、开发只验证静态文本没验证真实交互。
|
||||
|
||||
Coordinator 不亲自复测,但要做终检:读 Test 的证据,确认它覆盖了每条验收信号且符合原始意图,避免"过了字面没过意图"。终检不通过就回写 `failed_retest`。
|
||||
|
||||
---
|
||||
|
||||
## 4. 三轮失败策略(SSOT)
|
||||
|
||||
每个任务最多自动派发三轮:
|
||||
|
||||
```text
|
||||
round 1: 常规修复
|
||||
round 2: 带复测失败证据的定向修复
|
||||
round 3: 明确指出重复失败点,要求 worker 自己复现完整路径
|
||||
failed after round 3: 标记 leftover,继续下一个任务
|
||||
```
|
||||
|
||||
三轮失败后不要继续消耗同一个 worker。常见原因:验收标准需要重新设计、Worker 对问题模型理解错了、UI 自动化与实际浏览器状态有差异、需要人工观察或调试工具介入。
|
||||
|
||||
留档字段(结构见 `templates/tasks.schema.json`):
|
||||
|
||||
```yaml
|
||||
status: leftover
|
||||
resolution:
|
||||
leftoverReason: "failed after 3 supervised developer rounds"
|
||||
dispatch:
|
||||
rounds:
|
||||
- round: 1
|
||||
result: failed
|
||||
evidence: "<why failed>"
|
||||
- round: 2
|
||||
result: failed
|
||||
evidence: "<why failed>"
|
||||
- round: 3
|
||||
result: failed
|
||||
evidence: "<why failed>"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 任务排序
|
||||
|
||||
1. P0 阻塞主流程。
|
||||
2. P1 高频用户路径。
|
||||
3. P1/P2 体验改进。
|
||||
4. 重构和内部质量。
|
||||
|
||||
三轮失败的 P0 可以留档,但发布前需人工决策:降级范围、改验收标准、换新 Agent / 新 worktree 重做、人工修复。
|
||||
|
||||
---
|
||||
|
||||
## 6. 每轮派发只修一个明确问题
|
||||
|
||||
不要一次让 Developer Worker 修太多失败项,除非它们共享同一根因:
|
||||
|
||||
```text
|
||||
one dispatch = one bug = one acceptance path
|
||||
```
|
||||
|
||||
优点:复测更快、失败原因更清楚、三轮失败留档更准确。
|
||||
|
||||
---
|
||||
|
||||
## 7. 把失败证据写给下一轮 worker
|
||||
|
||||
第二轮以后,派发 prompt 应突出"上一轮为什么没过",而非重复原始描述。模板见 `prompt-templates.md` §「复测失败再派发模板」。
|
||||
|
||||
---
|
||||
|
||||
## 8. 优先让测试可执行化
|
||||
|
||||
如果某个问题需要多轮修复,说明它值得沉淀成自动化检查。这类可执行测试由 Test 拥有并维护(见 `roles-and-permissions.md` 权限表的 `<integration_test_paths>`)。优先级:
|
||||
|
||||
1. API smoke。
|
||||
2. 浏览器脚本或 case 文档。
|
||||
3. 单元测试。
|
||||
4. 人工检查清单。
|
||||
|
||||
目标不是全部自动化,而是把最容易反复误判的路径自动化。
|
||||
|
||||
---
|
||||
|
||||
## 9. 结束条件
|
||||
|
||||
一轮闭环结束时,必须能回答:
|
||||
|
||||
- 哪些任务 verified?哪些 leftover?
|
||||
- 每个 leftover 失败了几轮?最后一轮失败证据是什么?
|
||||
- 当前工作树有哪些未提交改动?
|
||||
- 是否还有 open / failed_retest 未处理?
|
||||
|
||||
答不清楚,闭环就还没结束。
|
||||
@@ -0,0 +1,243 @@
|
||||
# Orca 适配器(稳定核心,一种编排实现)
|
||||
|
||||
Orca orchestration 是运行时调度层的一种实现。闭环流程本身与工具无关(见 `closed-loop.md`);本文件只提供 Orca 的具体命令。没有 Orca 时用 `closed-loop.md` §「手动模式」。
|
||||
|
||||
所有结论仍以 `tasks.yaml` 为准,Orca 消息不是最终记录。
|
||||
|
||||
---
|
||||
|
||||
## 何时用 Orca 编排
|
||||
|
||||
用:需要监督、等待结果、闭环修复、三轮重试;有多个可独立派发的任务;需要 `worker_done` 后再复测。
|
||||
|
||||
不用:单次问答;用户只要求完整 handoff 不需监督;不需要复测的小改动。
|
||||
|
||||
---
|
||||
|
||||
## 运行前检查
|
||||
|
||||
```bash
|
||||
orca status --json
|
||||
orca terminal list --json
|
||||
orca orchestration task-list --json
|
||||
orca orchestration inbox --limit 20 --json
|
||||
```
|
||||
|
||||
确认:Orca runtime 可达;Coordinator、Developer、Test 三个终端都存在;Developer 在正确 worktree;当前没有冲突的活跃编排任务。
|
||||
|
||||
---
|
||||
|
||||
## 解析并复用 worker
|
||||
|
||||
**默认复用,创建是兜底。** 每次向 Developer 或 Test 派发前都先解析 worker,不能直接照后文示例执行 `terminal create`:
|
||||
|
||||
1. 运行 `orca terminal list --json`,筛选 `connected=true`、`writable=true`、目标 `worktreePath` 一致、标题角色和配置一致的终端。稳定标题使用 `ACK-<ROLE>-<CLI>-<TIER>-<N>`,例如 `ACK-DEV-CODEX-TERRA-1`、`ACK-TEST-CODEX-LUNA-1`、`ACK-DEV-CURSOR-AUTO-1`;强档示例为 `ACK-DEV-CODEX-SOL-1`。
|
||||
2. 运行 `orca orchestration task-list --status dispatched --json`。若候选 handle 出现在活跃任务的 `assignee_handle`,视为 busy,不复用;不要仅凭终端预览文本或最近输出时间猜忙闲。
|
||||
3. 对空闲候选运行 `orca terminal show --terminal <handle> --json`,确认仍存活且 worktree、角色和 Agent CLI / 模型档位符合本次要求。符合就直接把该 handle 作为 `dispatch --to` 的目标。
|
||||
4. 只有不存在兼容的空闲候选时才创建。若同角色同配置已有 busy worker,使用下一个未占用序号,例如 `ACK-DEV-CODEX-TERRA-2`;不要创建另一个同名终端。
|
||||
5. dispatch 成功后,把实际 handle 写入对应 `tasks.yaml` 条目的 `dispatch.worker`。下一轮先尝试该 handle;若它已消失、断开、不可写、worktree/角色/档位不兼容或正忙,再回到第 1 步选择其它 worker。
|
||||
|
||||
`tasks.yaml.dispatch.worker` 记录“这个任务实际用了谁”,便于续跑和审计;`orca terminal list` 记录“谁现在还活着”,是运行时存活状态的事实源。不要另建一份永久 worker 池,因为终端关闭后其中的 handle 会过期。
|
||||
|
||||
复用决策:
|
||||
|
||||
| 情况 | 动作 |
|
||||
|------|------|
|
||||
| 任务已记录 worker,且该 handle 存活、兼容、空闲 | 优先复用原 handle |
|
||||
| 有其它同 worktree、同角色、兼容的空闲 worker | 复用该 handle |
|
||||
| 同角色 worker 存在但都 busy | 创建下一编号的临时并发 worker |
|
||||
| worker 已关闭、断开或不存在 | 创建新 worker |
|
||||
| 模型升级或 worktree 不同 | 不复用不兼容 worker,创建对应档位/路径的新 worker |
|
||||
|
||||
---
|
||||
|
||||
## 给 worker 终端固定模型
|
||||
|
||||
**编排层不设模型。** `task-create` / `dispatch` 都没有 `--model`;`dispatch --to <handle>` 只是把任务投给一个已存在的终端,用的是那个终端里 agent 会话启动时的模型。要固定模型,就在 **创建 worker 终端** 时用 agent CLI 的模型参数:
|
||||
|
||||
默认沿用 Coordinator 当前所在的 Agent CLI:Cursor Coordinator 创建 Cursor worker,Codex Coordinator 创建 Codex worker。不要通过询问模型来猜运行环境;以当前 CLI / 终端环境为准。除非项目 overlay 或用户明确指定,否则不跨 Agent CLI 创建 worker。
|
||||
|
||||
```bash
|
||||
# Cursor:Test / Developer worker 用 auto 模型,并按项目要求启用 YOLO
|
||||
orca terminal create --worktree path:<dev_worktree> \
|
||||
--command "cursor-agent --yolo --model auto" --title "ACK-DEV-CURSOR-AUTO-1" --json
|
||||
|
||||
# 需要更强模型时改成具体模型
|
||||
orca terminal create --worktree path:<dev_worktree> \
|
||||
--command "cursor-agent --yolo --model claude-opus-4-8-thinking-high" --title "ACK-DEV-CURSOR-STRONG-1" --json
|
||||
|
||||
# Codex:Developer worker
|
||||
orca terminal create --worktree path:<dev_worktree> \
|
||||
--command "codex --dangerously-bypass-approvals-and-sandbox -m gpt-5.6-terra -c model_reasoning_effort=medium" \
|
||||
--title "ACK-DEV-CODEX-TERRA-1" --json
|
||||
|
||||
# Codex:Test worker
|
||||
orca terminal create --worktree path:<test_worktree> \
|
||||
--command "codex --dangerously-bypass-approvals-and-sandbox -m gpt-5.6-luna -c model_reasoning_effort=low" \
|
||||
--title "ACK-TEST-CODEX-LUNA-1" --json
|
||||
|
||||
# Codex:复杂 Developer 任务升级
|
||||
orca terminal create --worktree path:<dev_worktree> \
|
||||
--command "codex --dangerously-bypass-approvals-and-sandbox -m gpt-5.6-sol -c model_reasoning_effort=high" \
|
||||
--title "ACK-DEV-CODEX-SOL-1" --json
|
||||
```
|
||||
|
||||
这些创建命令只在复用流程找不到空闲兼容 worker 时执行。拿到返回的 handle 后再 `task-create` + `dispatch --to <handle>`,并把 handle 写入 `tasks.yaml` 的 `dispatch.worker`。模型档位与选型策略见 `model-routing.md`。
|
||||
|
||||
需要隔离/并行时,先建新 worktree 再在其中起 worker(是否新建见 `closed-loop.md` §「子任务放哪」):
|
||||
|
||||
```bash
|
||||
orca worktree create --name <feature> --base-branch <base> --json
|
||||
orca terminal create --worktree path:<new_worktree> --command "cursor-agent --yolo --model auto" --title "ACK-DEV-CURSOR-AUTO-1" --json
|
||||
```
|
||||
|
||||
- `cursor-agent --list-models` 可列出合法模型;`auto` 表示由 Cursor 自动选型。
|
||||
- Codex 用 `-m / --model` 指定模型,用 `-c model_reasoning_effort=<effort>` 固定推理档位;不要把省略 `-m` 当作 Cursor `auto` 的等价物。
|
||||
- 本项目要求 Cursor worker 带 `--yolo`,Codex worker 带 `--dangerously-bypass-approvals-and-sandbox`;创建前先运行项目覆盖层指定的校验器。
|
||||
- 其它 CLI(opencode 等)用各自的模型参数或配置,`--command` 相应替换。
|
||||
- 若 worker 是已在跑的会话(用 `--inject` 投递),模型已由该会话启动时决定,无法在 dispatch 时改;要换模型需新建终端。
|
||||
|
||||
---
|
||||
|
||||
## 创建父任务
|
||||
|
||||
```bash
|
||||
orca orchestration task-create --spec "$(cat <<'EOF'
|
||||
Goal: Complete <release_or_feature> with supervised Coordinator -> Developer -> Test loop.
|
||||
|
||||
Coordinator (PM): owns task board, decomposition, dispatch, and final gate (reads Test evidence, does not test).
|
||||
Developer: owns implementation and white-box verification.
|
||||
Test: owns independent black-box retest and evidence (verifier != implementer).
|
||||
|
||||
Policy:
|
||||
- Each issue can be dispatched at most 3 rounds.
|
||||
- If still failing after 3 rounds, record as leftover and continue next issue.
|
||||
- worker_done and retest reports are not final completion; only Coordinator writes tasks.yaml.
|
||||
EOF
|
||||
)" --json
|
||||
```
|
||||
|
||||
## 创建子任务
|
||||
|
||||
```bash
|
||||
orca orchestration task-create --parent <parent_task_id> --spec "$(cat <<'EOF'
|
||||
Fix <task_id>: <title>
|
||||
|
||||
Repository:
|
||||
- Path: <repo_path>
|
||||
- Worktree: <dev_worktree>
|
||||
|
||||
Read: <overlay_file> (project overlay), tasks.yaml, <relevant_spec_or_test_doc>
|
||||
Failure evidence: <copy latest Test evidence>
|
||||
Acceptance: <copy expected behavior + verification commands>
|
||||
|
||||
Constraints:
|
||||
- Follow the overlay file path scope.
|
||||
- Do not write tasks.yaml, do not mark verified.
|
||||
- Do not commit or push unless user asks.
|
||||
EOF
|
||||
)" --json
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 派发给 Developer Worker
|
||||
|
||||
终端是 Orca 可识别的 Agent CLI 时:
|
||||
|
||||
```bash
|
||||
orca orchestration dispatch --task <task_id> --to <developer_handle> --inject --json
|
||||
```
|
||||
|
||||
不能 `--inject` 时,先登记 dispatch,再手动投递 `prompt-templates.md` §1 的初始派发 prompt:
|
||||
|
||||
```bash
|
||||
orca orchestration dispatch --task <task_id> --to <developer_handle> --json
|
||||
orca terminal send --terminal <developer_handle> --text "$(cat <<'EOF'
|
||||
<粘贴 prompt-templates.md §1 初始派发模板,已填占位符>
|
||||
EOF
|
||||
)" --enter --json
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 派发给 Test 复测
|
||||
|
||||
Developer 回报 worker_done、Coordinator 写回 `fixed_by_dev` 后,把复测任务发给 Test:
|
||||
|
||||
```bash
|
||||
orca orchestration dispatch --task <task_id> --to <test_handle> --inject --json
|
||||
```
|
||||
|
||||
不能 `--inject` 时,先登记再手动投递 `prompt-templates.md` §3 的复测派发 prompt:
|
||||
|
||||
```bash
|
||||
orca orchestration dispatch --task <task_id> --to <test_handle> --json
|
||||
orca terminal send --terminal <test_handle> --text "$(cat <<'EOF'
|
||||
<粘贴 prompt-templates.md §3 复测派发模板,已填占位符>
|
||||
EOF
|
||||
)" --enter --json
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 等待结果
|
||||
|
||||
```bash
|
||||
orca orchestration check \
|
||||
--terminal <coordinator_handle> \
|
||||
--wait \
|
||||
--types worker_done,retest_result,escalation,decision_gate \
|
||||
--timeout-ms 900000 \
|
||||
--json
|
||||
```
|
||||
|
||||
等待超时不等于失败。长任务可继续等待,或检查 worker 终端活性。`worker_done` 来自 Developer,`retest_result`(无该类型时用 `worker_done` + subject 区分)来自 Test。
|
||||
|
||||
---
|
||||
|
||||
## Developer 回报 worker_done
|
||||
|
||||
字段含义见 `prompt-templates.md` §3:
|
||||
|
||||
```bash
|
||||
orca orchestration send \
|
||||
--to <coordinator_handle> \
|
||||
--type worker_done \
|
||||
--subject "<task_id> fix ready round <n>" \
|
||||
--body "<修了什么。跑了哪些验证。如何复现。还有什么风险。>" \
|
||||
--payload '{
|
||||
"taskId": "<orca_task_id>",
|
||||
"dispatchId": "<orca_dispatch_id>",
|
||||
"filesModified": ["<file_a>", "<file_b>"],
|
||||
"verification": ["<command_a>: passed", "<command_b>: passed"],
|
||||
"risk": "<remaining risk or none>"
|
||||
}' \
|
||||
--json
|
||||
```
|
||||
|
||||
收到 worker_done 后,Coordinator 写回 `fixed_by_dev`,再按上文派发给 Test 复测。
|
||||
|
||||
---
|
||||
|
||||
## Test 回报复测结果
|
||||
|
||||
字段含义见 `prompt-templates.md` §5:
|
||||
|
||||
```bash
|
||||
orca orchestration send \
|
||||
--to <coordinator_handle> \
|
||||
--type retest_result \
|
||||
--subject "<task_id> retest round <n>" \
|
||||
--body "<逐条验收信号结论 + 实际观察 + 证据>" \
|
||||
--payload '{
|
||||
"taskId": "<orca_task_id>",
|
||||
"dispatchId": "<orca_dispatch_id>",
|
||||
"env": {"worktree": "<path>", "branch": "<branch>", "commit": "<sha>", "baseUrl": "<base_url>"},
|
||||
"signals": ["<signal 1>: pass", "<signal 2>: fail (<evidence>)"],
|
||||
"conclusion": "all-signals-pass | signals-failed"
|
||||
}' \
|
||||
--json
|
||||
```
|
||||
|
||||
无 `retest_result` 类型时用 `--type worker_done`,靠 subject `retest round <n>` 区分。收到复测结果后,Coordinator 按 `closed-loop.md` 做终检并回写 `tasks.yaml`:通过 `verified`,不过 `failed_retest`。
|
||||
@@ -0,0 +1,187 @@
|
||||
# 派发 Prompt 模板(稳定核心)
|
||||
|
||||
Coordinator 用这些模板向 **Developer** 派发修复、向 **Test** 派发复测。复制时替换尖括号占位符。模板与编排工具无关:Orca 模式用 `orca-adapter.md` 的命令投递,手动模式直接把文本发给对应 Agent。
|
||||
|
||||
角色分工见 `roles-and-permissions.md`;闭环顺序见 `closed-loop.md`。
|
||||
|
||||
派发时除了具体任务,Coordinator 应把对应角色的**能力要求**一并带上(`roles-and-permissions.md` §「三角色能力清单」的 Must Do / Must Not)。下面模板已内置关键条目,复制即可。
|
||||
|
||||
---
|
||||
|
||||
## 0. 可选 skills 路由(装了才用,不阻塞)
|
||||
|
||||
如果 worker 所在环境已安装以下 skill,可在对应环节调用以获得更强 playbook;未安装则按 `roles-and-permissions.md` 的能力清单执行:
|
||||
|
||||
- Coordinator 规划复杂需求:`/think` 或 `superpowers:brainstorming` / `writing-plans`。
|
||||
- Developer 排查缺陷:`/hunt` 或 `superpowers:systematic-debugging`;行为变更:`superpowers:test-driven-development`。
|
||||
- Test 复测 / 合并前检查:`/check` 或 `superpowers:verification-before-completion`。
|
||||
|
||||
派发时可加一行:「若已安装 <skill>,本环节可用它;未安装按 ack 角色能力清单执行。」
|
||||
|
||||
---
|
||||
|
||||
## 1. 初始派发给 Developer
|
||||
|
||||
```text
|
||||
你现在接到一个受监督的协作任务。请在 <dev_worktree> 开发工作树内完成。
|
||||
|
||||
任务:
|
||||
- 修复 <task_id>: <task_title>
|
||||
|
||||
请先读取:
|
||||
- <overlay_file>(项目覆盖层,路径见 tasks.yaml 的 project.overlayFile)
|
||||
- tasks.yaml
|
||||
- <relevant_spec_or_test_doc>
|
||||
|
||||
当前失败证据:
|
||||
<copy latest Test evidence>
|
||||
|
||||
验收标准(可观测信号,见 optimization-method.md §1):
|
||||
1. <expected behavior 1>
|
||||
2. <expected behavior 2>
|
||||
3. <expected behavior 3>
|
||||
|
||||
能力要求(见 roles-and-permissions.md §三角色能力清单 · Developer):
|
||||
- 动手前先复现失败现象,或先写一个会失败的测试再修。
|
||||
- bug 修复配可复现的失败用例;行为变更配单元测试。
|
||||
- 完成前亲自走一遍验收路径,不只满足静态文案。
|
||||
- 若是网站 / 常驻服务,改完重启服务并确认生效,别让 Test 测到旧进程或旧构建。
|
||||
|
||||
约束:
|
||||
- 只修改 Developer 可写路径(见覆盖层文件的权限表)。
|
||||
- 不要修改产品规格和集成测试文件(分别由 Coordinator 与 Test 拥有),除非任务明确要求。
|
||||
- 不要写 tasks.yaml,不要标记 verified。
|
||||
- 不要提交或推送,除非用户明确要求。
|
||||
- 最小 diff,只改本任务根因,避免无关重构;若必须先重构请停下说明并请示。
|
||||
|
||||
完成前必须运行:
|
||||
- <test command 1>
|
||||
- <test command 2>
|
||||
|
||||
完成后回报一次 worker_done(格式见 §4)。如果阻塞,请发送 escalation 或 ask。
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 复测失败再派发给 Developer
|
||||
|
||||
```text
|
||||
第 <n> 轮复测未通过,请继续修 <task_id>。
|
||||
|
||||
上一轮开发声称:
|
||||
<worker_done summary>
|
||||
|
||||
Test 独立复测结果:
|
||||
- 运行命令:<commands>
|
||||
- 失败页面/API:<page or endpoint>
|
||||
- 仍缺失:<missing expected checks>
|
||||
- 实际观察:<actual evidence>
|
||||
|
||||
关键提示:
|
||||
- 不要只满足静态文案,必须满足交互后的真实状态。
|
||||
- 如果后端/API 正常而 UI 不更新,请优先排查事件链、状态重置、异步请求、构建产物和服务 worktree。
|
||||
- 修复后请自己用浏览器或脚本复现 Test 的完整步骤。
|
||||
|
||||
验收不变:
|
||||
<copy acceptance criteria>
|
||||
|
||||
完成后回报 worker_done,subject 使用:"<task_id> fix ready round <n>"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 派发给 Test 复测
|
||||
|
||||
Developer 回报 worker_done 后,Coordinator 把复测任务发给 Test。
|
||||
|
||||
```text
|
||||
请对 <task_id>: <task_title> 做独立黑盒复测。
|
||||
|
||||
请先读取:
|
||||
- <overlay_file>(项目覆盖层,路径见 tasks.yaml 的 project.overlayFile)
|
||||
- tasks.yaml(该任务的验收信号)
|
||||
- <relevant_spec_or_test_doc>
|
||||
|
||||
Developer 本轮声称(仅供参考,不作数):
|
||||
- 改动文件:<files>
|
||||
- 自测命令:<commands>
|
||||
|
||||
复测要求(见 roles-and-permissions.md §三角色能力清单 · Test):
|
||||
- 先对齐运行环境(pwd / 分支 / commit / 服务 worktree,见 closed-loop.md),避免测错实例或旧构建;网站类先确认服务已按新代码重启。
|
||||
- 网站类任务优先用浏览器复测真实交互,其次才是 API / 脚本。
|
||||
- 逐条验证下列验收信号,不要只看静态文案,要验证交互后的真实状态:
|
||||
1. <observable signal 1>
|
||||
2. <observable signal 2>
|
||||
3. <observable signal 3>
|
||||
- 需要时把易反复误判的路径沉淀成可执行测试(见 optimization-method.md §8)。
|
||||
|
||||
约束:
|
||||
- 只读源码,不修改应用代码,不写 tasks.yaml。
|
||||
- 只回传证据和逐条结论,最终判定由 Coordinator 终检后落盘。
|
||||
|
||||
完成后回报一次复测报告(格式见 §5),subject:"<task_id> retest round <n>"。
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Developer worker_done 回报格式
|
||||
|
||||
无论 Orca 还是手动,回报都应包含以下字段:
|
||||
|
||||
```text
|
||||
subject: <task_id> fix ready round <n>
|
||||
filesModified: [<file_a>, <file_b>]
|
||||
verification:
|
||||
- <command_a>: passed
|
||||
- <command_b>: passed
|
||||
reproduce: 我如何复现验收路径 <steps>
|
||||
risk: <remaining risk or none>
|
||||
```
|
||||
|
||||
Orca 模式下用 `orca-adapter.md` §「Developer 回报 worker_done」的命令发送同样的字段。
|
||||
|
||||
---
|
||||
|
||||
## 5. Test 复测报告格式
|
||||
|
||||
Test 只回传证据和逐条结论,不下最终判定:
|
||||
|
||||
```text
|
||||
subject: <task_id> retest round <n>
|
||||
env:
|
||||
worktree: <path>
|
||||
branch: <branch>
|
||||
commit: <short sha>
|
||||
baseUrl: <base_url>
|
||||
commands:
|
||||
- <command_a>: passed/failed
|
||||
signals:
|
||||
- <signal 1>: pass/fail (<evidence>)
|
||||
- <signal 2>: pass/fail (<evidence>)
|
||||
browser: <snapshot / DOM / API evidence>
|
||||
conclusion: all-signals-pass / signals-failed
|
||||
notes: <observations, suspected cause if failed>
|
||||
```
|
||||
|
||||
Orca 模式下用 `orca-adapter.md` §「Test 回报复测结果」的命令发送同样的字段。
|
||||
|
||||
---
|
||||
|
||||
## 6. Coordinator 最终报告模板
|
||||
|
||||
```text
|
||||
本轮闭环完成。
|
||||
|
||||
已验证(Test 复测通过 + 终检):
|
||||
- <task_id>: <what passed>
|
||||
|
||||
遗留:
|
||||
- <task_id>: 三轮仍未通过,已记录为 leftover。最后失败证据:<evidence>
|
||||
|
||||
验证命令:
|
||||
- <command>: passed
|
||||
|
||||
工作树状态:
|
||||
- <repo_path>: <git status summary>
|
||||
- <dev_worktree>: <git status summary>
|
||||
```
|
||||
@@ -0,0 +1,149 @@
|
||||
# 角色与权限(稳定核心)
|
||||
|
||||
本文件是**角色模型、路径权限、任务状态机、完成定义**的单一事实源(SSOT)。其它文件只引用本文件,不重复定义。
|
||||
|
||||
目标:让每个 Agent 只处理自己能验证的事情,减少上下文污染和越权修改。
|
||||
|
||||
---
|
||||
|
||||
## 角色模型(三角色)
|
||||
|
||||
ACK 默认三个独立 Agent:**Coordinator 只编排、Test 只验证、Developer 只实现**。关键属性是**验证者 ≠ 实现者**:Developer 不能给自己盖章,验证权在独立的 Test。
|
||||
|
||||
| 角色 | 主要职责 | 验证方式 | 不应做的事 |
|
||||
|------|----------|----------|------------|
|
||||
| Coordinator (PM) | 需求拆解、定验收信号、排优先级、写 `tasks.yaml`、向 Developer/Test 派发、跑三轮闭环、做最终 gate | 读 Test 证据并对齐原始意图(不亲自跑测试) | 修改源码、亲自复测、凭 worker_done 直接标 `verified` |
|
||||
| Test | 黑盒复测、回归验证、沉淀可执行测试、产出证据 | 浏览器、API、集成脚本、用户可见行为 | 修改应用源码、修改产品规格、写 `tasks.yaml` |
|
||||
| Developer | 实现修复、写单元测试、运行构建和白盒验证 | 单元测试、类型检查、构建、本地运行 | 修改产品规格与集成测试、标记 `verified`、绕过测试声称完成 |
|
||||
| User / Decision Owner | 决定范围、优先级、阻塞项是否继续 | 审阅报告和遗留清单 | 直接替代复测证据 |
|
||||
|
||||
**独立验证权归 Test。** Coordinator 不亲自复测——它读 Test 的证据,并对照任务的原始意图做一次终检(见「完成定义」)。`worker_done` 不等于完成的原则同时适用于 Developer 和 Test:结论只有落到 `tasks.yaml` 才算数。
|
||||
|
||||
**模型档位(正交层)。** 三角色默认按成本分层:Coordinator 用强模型,Test 与 Developer 用中低模型,必要时升级。完整档位表与升级规则见 `model-routing.md`。Coordinator 用强模型但不跑测试,这一分工天然省 token 又不破坏「验证者 ≠ 实现者」。
|
||||
|
||||
---
|
||||
|
||||
## 三角色能力清单(SSOT)
|
||||
|
||||
上面的表定义了**边界**(谁能碰什么),这一节定义**能力**(每个角色到底该怎么做好自己的事)。每个角色用同一骨架描述:`Outcome`(产出什么)/ `Must Do`(必须做)/ `Must Not`(不能做)/ `Evidence`(拿什么证明)/ `Output`(交付格式)。派发 prompt 会引用这里,见 `prompt-templates.md`。
|
||||
|
||||
这些是**通用工程习惯**,不含项目命令与路径;项目差异写在覆盖层文件(默认 `docs/ack/project.md`)。装了外部 skill 的环境可按每个角色末尾的「可选 skills」加速,未装则照本清单执行,不阻塞。
|
||||
|
||||
### Coordinator (PM) —— 拆解与终检
|
||||
|
||||
- **Outcome**:把一句话需求变成可执行、验收可观测的任务集,并跑完闭环得到明确结论(verified / leftover)。
|
||||
- **Must Do**
|
||||
- 先澄清意图再动手:目标、成功标准、约束、明确「不做什么」。歧义有多解或多来源冲突时,先问清再拆。
|
||||
- 每个任务写**可观测验收信号**(可见文本 / API 结果 / 交互结果,见 `optimization-method.md` §1),而不是「功能正常」。
|
||||
- 拆任务时点明最脆弱的假设:「本任务假设 X,若 X 不成立则 Y」;列出被否掉的方案与原因。
|
||||
- 拆分/验收先给用户确认,再派发(`kickoff.md` 第 1 步的停顿点)。
|
||||
- 一次派发只针对一个明确问题(`optimization-method.md` §6);每任务最多三轮。
|
||||
- 终检:读 Test 证据,逐条对齐原始意图后才落 `verified`,不亲自复测。
|
||||
- **Must Not**:改源码、亲自跑测试、凭 `worker_done` 直接标 `verified`、把多个无关失败塞进一次派发。
|
||||
- **Evidence**:产品文档、`tasks.yaml` 里的 `expected` + `verification`、Test 回传的复测证据。
|
||||
- **Output**:确认前给「产品文档 + 任务拆分 + 验收信号」;闭环结束给最终报告(`prompt-templates.md` §6)。
|
||||
- **可选 skills**:复杂需求可先用 `/think` 或 `superpowers:brainstorming` / `writing-plans` 收敛设计与计划。
|
||||
|
||||
### Developer —— 实现与白盒验证
|
||||
|
||||
- **Outcome**:在授权路径内做出满足验收信号的最小改动,并用白盒证据证明它可复现。
|
||||
- **Must Do**
|
||||
- 动手前先读覆盖层文件、`tasks.yaml` 对应任务、相关规格;复现失败现象或先写会失败的测试。
|
||||
- 最小 diff,只改一个明确问题的根因,不顺手重构无关代码。
|
||||
- 行为变更配单元测试;bug 修复先有一个能复现的失败用例再修。
|
||||
- 完成前跑覆盖层里规定的命令(构建 / 单测 / 本地运行),亲自走一遍验收路径。
|
||||
- **网站 / 常驻服务**:改完重启服务(或触发热更并确认生效),保证运行实例跑的是新代码,避免 Test 测到旧进程 / 旧构建。
|
||||
- **Must Not**:改产品规格与集成测试、写 `tasks.yaml`、标 `verified`、绕过测试声称完成、把 bug 修复扩成大重构(需要就先停下说明并请示)。
|
||||
- **Evidence**:改了哪些文件、跑了哪些命令及结果、如何复现验收路径、残留风险。
|
||||
- **Output**:一次 `worker_done`,字段见 `prompt-templates.md` §4(只报证据,不下最终结论)。
|
||||
- **可选 skills**:排查用 `/hunt` 或 `superpowers:systematic-debugging`(先根因后修);实现行为变更用 `superpowers:test-driven-development`。
|
||||
|
||||
### Test —— 独立黑盒复测
|
||||
|
||||
- **Outcome**:以独立视角复现验收路径,逐条给出通过/失败的可观测证据,供 Coordinator 终检。
|
||||
- **Must Do**
|
||||
- 先对齐运行环境(pwd / 分支 / commit / 服务 worktree,见 `closed-loop.md`),避免测错实例或旧构建;网站类先确认服务已按新代码重启。
|
||||
- 逐条验证验收信号,验证交互后的真实状态,而不是只看静态文案。
|
||||
- **网站类任务优先用浏览器复测**真实交互(点击 / 跳转 / 渲染),其次才是 API / 脚本;纯后端 / CLI 则以 API smoke 或脚本为主。
|
||||
- 把最容易反复误判的路径沉淀成可执行测试(`optimization-method.md` §8)。
|
||||
- 只回传证据 + 逐条结论,最终判定留给 Coordinator。
|
||||
- **Must Not**:改应用源码、改产品规格、写 `tasks.yaml`、凭 Developer 的 `worker_done` 直接下结论。
|
||||
- **Evidence**:运行环境快照、命令结果、每条信号 pass/fail + 证据(snapshot / DOM / API 结果)。
|
||||
- **Output**:一次复测报告,字段见 `prompt-templates.md` §5。
|
||||
- **可选 skills**:合并 / 发版前检查可用 `/check` 或 `superpowers:verification-before-completion`(证据先于结论)。
|
||||
|
||||
---
|
||||
|
||||
## 路径权限模板
|
||||
|
||||
目标项目在自己的**覆盖层文件**中填入实际路径(模板见 `templates/project.template.md`;覆盖层默认 `docs/ack/project.md`,路径记在 `tasks.yaml` 的 `project.overlayFile`)。
|
||||
|
||||
| 路径 | Coordinator | Test | Developer | 说明 |
|
||||
|------|:-----------:|:----:|:---------:|------|
|
||||
| `<spec_paths>` | R/W | Read-only | Read-only | PRD、API spec、设计文档,Coordinator(PM)拥有 |
|
||||
| `<integration_test_paths>` | Read-only | R/W | Read-only | 浏览器用例、API smoke、回归清单,Test 拥有 |
|
||||
| `<test_records_path>` | Read-only | R/W | Read-only | 复测记录,通常可 gitignore |
|
||||
| `<source_paths>` | Read-only | Read-only | R/W | 应用源码 |
|
||||
| `<unit_test_paths>` | Read-only | Read-only | R/W | 单元测试 |
|
||||
| `<shared_config_templates>` | Read-only | Read-only | R/W | 可提交配置模板 |
|
||||
| `<local_config>` | Read-only | Read-only | Read-only | 本地私有配置,不提交 |
|
||||
| `tasks.yaml` | R/W | Read-only | Read-only | 见下方「任务板写入约定」 |
|
||||
|
||||
---
|
||||
|
||||
## 任务状态机(SSOT)
|
||||
|
||||
```text
|
||||
open
|
||||
-> dispatched (派发给 Developer)
|
||||
-> fixed_by_dev (Developer 声称已修)
|
||||
-> retesting (派发给 Test 复测)
|
||||
-> verified (Test 通过 + Coordinator 终检)
|
||||
```
|
||||
|
||||
失败分支:
|
||||
|
||||
```text
|
||||
dispatched -> blocked
|
||||
retesting -> failed_retest -> dispatched
|
||||
failed_retest(累计 3 轮) -> leftover
|
||||
```
|
||||
|
||||
状态定义(所有状态都只由 Coordinator 写入 `tasks.yaml`,来源不同):
|
||||
|
||||
| 状态 | 依据来源 | 含义 |
|
||||
|------|----------|------|
|
||||
| `open` | Coordinator 自己发现/记录 | 已发现,等待处理 |
|
||||
| `dispatched` | Coordinator 派发动作 | 已派发给 Developer |
|
||||
| `fixed_by_dev` | Developer 的 worker_done | 开发声称已修复并提供白盒验证 |
|
||||
| `retesting` | Coordinator 派发动作 | 已派发给 Test,正在黑盒复测 |
|
||||
| `failed_retest` | Test 的复测报告 | 复测失败,可继续派发 Developer |
|
||||
| `verified` | Test 通过 + Coordinator 终检 | 复测通过且符合原始意图 |
|
||||
| `blocked` | Coordinator 判断 | 需要用户决策或外部条件 |
|
||||
| `leftover` | Coordinator 判断 | 累计 3 轮仍未通过,留给人工或专项处理 |
|
||||
|
||||
三轮失败的处理细则见 `optimization-method.md` §「三轮失败策略」。
|
||||
|
||||
---
|
||||
|
||||
## 任务板写入约定(并发安全)
|
||||
|
||||
`tasks.yaml` 是持久事实源,为避免多 Agent 并发写冲突:
|
||||
|
||||
- **只有 Coordinator 写 `tasks.yaml`**。Test 与 Developer 对它都是只读的。
|
||||
- Developer 的实现状态、Test 的复测证据都通过消息回传(`worker_done` / 复测报告),由 Coordinator 落盘。
|
||||
- 每次写入前先读最新内容,写入后更新顶层 `updatedAt`。
|
||||
- 单次写入应是一个任务的一次状态跃迁,避免整表批量重写。
|
||||
|
||||
---
|
||||
|
||||
## 完成定义(Definition of Done)
|
||||
|
||||
一个任务只有同时满足以下条件,才能标记 `verified`:
|
||||
|
||||
- Developer 已提供修改文件和白盒验证证据(`worker_done`)。
|
||||
- Test 在正确 worktree 和正确服务实例上独立复测通过(对齐检查见 `closed-loop.md`),并产出可观测证据。
|
||||
- 相关单元测试、构建、集成或浏览器检查通过。
|
||||
- **Coordinator 终检**:读 Test 的证据,确认它满足任务的原始意图与验收信号(不是重测,是审证据 + 对齐意图;避免"过了字面没过意图")。
|
||||
- `tasks.yaml` 中记录了复测证据与 `resolution.verifiedBy`。
|
||||
- 用户可见行为符合验收标准。
|
||||
Executable
+167
@@ -0,0 +1,167 @@
|
||||
#!/usr/bin/env python3
|
||||
"""校验 tasks.yaml 是否符合 ack 任务板结构。
|
||||
|
||||
权威结构是同目录上层的 templates/tasks.schema.json(跨语言可用)。
|
||||
本脚本是参考实现:
|
||||
- 若安装了 jsonschema,则用 schema 做完整校验;
|
||||
- 否则回退到内置的关键规则校验(必填字段、状态枚举、三轮上限、leftover 留档)。
|
||||
YAML 解析优先用 pyyaml;未安装时给出提示而非崩溃。
|
||||
|
||||
用法:
|
||||
python3 validate_tasks.py [tasks.yaml]
|
||||
python3 validate_tasks.py --schema path/to/tasks.schema.json tasks.yaml
|
||||
|
||||
退出码: 0 通过 / 1 校验失败 / 2 环境或用法错误。
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
STATUS_ENUM = {
|
||||
"open",
|
||||
"dispatched",
|
||||
"fixed_by_dev",
|
||||
"retesting",
|
||||
"failed_retest",
|
||||
"verified",
|
||||
"blocked",
|
||||
"leftover",
|
||||
}
|
||||
MAX_ROUNDS = 3
|
||||
|
||||
|
||||
def load_yaml(path: Path) -> dict:
|
||||
try:
|
||||
import yaml # type: ignore
|
||||
except ImportError:
|
||||
sys.stderr.write(
|
||||
"需要 PyYAML 才能解析 YAML:pip install pyyaml\n"
|
||||
"(或把任务板导出为 JSON 后再校验)\n"
|
||||
)
|
||||
raise SystemExit(2)
|
||||
try:
|
||||
with path.open(encoding="utf-8") as fh:
|
||||
data = yaml.safe_load(fh)
|
||||
except yaml.YAMLError as exc: # type: ignore
|
||||
sys.stderr.write(f"YAML 解析失败: {exc}\n")
|
||||
raise SystemExit(1)
|
||||
if not isinstance(data, dict):
|
||||
sys.stderr.write("任务板顶层必须是对象(mapping)\n")
|
||||
raise SystemExit(1)
|
||||
return data
|
||||
|
||||
|
||||
def validate_with_schema(data: dict, schema_path: Path) -> list[str]:
|
||||
import jsonschema # type: ignore
|
||||
|
||||
schema = json.loads(schema_path.read_text(encoding="utf-8"))
|
||||
validator = jsonschema.Draft7Validator(schema)
|
||||
errors = []
|
||||
for err in sorted(validator.iter_errors(data), key=lambda e: list(e.path)):
|
||||
loc = "/".join(str(p) for p in err.path) or "<root>"
|
||||
errors.append(f"[schema] {loc}: {err.message}")
|
||||
return errors
|
||||
|
||||
|
||||
def validate_builtin(data: dict) -> list[str]:
|
||||
errors: list[str] = []
|
||||
|
||||
if not isinstance(data.get("version"), int) or data.get("version", 0) < 1:
|
||||
errors.append("version 必须是 >=1 的整数")
|
||||
project = data.get("project")
|
||||
if not isinstance(project, dict) or not project.get("name"):
|
||||
errors.append("project.name 必填")
|
||||
|
||||
tasks = data.get("tasks")
|
||||
if not isinstance(tasks, list):
|
||||
errors.append("tasks 必须是列表")
|
||||
return errors
|
||||
|
||||
seen_ids: set[str] = set()
|
||||
for i, task in enumerate(tasks):
|
||||
where = f"tasks[{i}]"
|
||||
if not isinstance(task, dict):
|
||||
errors.append(f"{where}: 必须是对象")
|
||||
continue
|
||||
tid = task.get("id")
|
||||
title = task.get("title")
|
||||
status = task.get("status")
|
||||
if not tid:
|
||||
errors.append(f"{where}: id 必填")
|
||||
else:
|
||||
where = f"tasks[{i}] {tid}"
|
||||
if tid in seen_ids:
|
||||
errors.append(f"{where}: id 重复")
|
||||
seen_ids.add(tid)
|
||||
if not title:
|
||||
errors.append(f"{where}: title 必填")
|
||||
if status not in STATUS_ENUM:
|
||||
errors.append(
|
||||
f"{where}: status={status!r} 非法,应为 {sorted(STATUS_ENUM)}"
|
||||
)
|
||||
|
||||
dispatch = task.get("dispatch") or {}
|
||||
rounds = dispatch.get("rounds") or []
|
||||
if isinstance(rounds, list):
|
||||
if len(rounds) > MAX_ROUNDS:
|
||||
errors.append(
|
||||
f"{where}: 派发轮次 {len(rounds)} 超过上限 {MAX_ROUNDS}"
|
||||
)
|
||||
for r in rounds:
|
||||
if isinstance(r, dict) and r.get("result") not in {"passed", "failed"}:
|
||||
errors.append(f"{where}: round.result 必须是 passed/failed")
|
||||
|
||||
if status == "leftover":
|
||||
resolution = task.get("resolution") or {}
|
||||
if not resolution.get("leftoverReason"):
|
||||
errors.append(f"{where}: leftover 必须填 resolution.leftoverReason")
|
||||
|
||||
return errors
|
||||
|
||||
|
||||
def main(argv: list[str] | None = None) -> int:
|
||||
parser = argparse.ArgumentParser(description="校验 tasks.yaml 结构")
|
||||
parser.add_argument("tasks", nargs="?", default="tasks.yaml", help="任务板路径")
|
||||
parser.add_argument("--schema", help="tasks.schema.json 路径(默认自动探测)")
|
||||
args = parser.parse_args(argv)
|
||||
|
||||
tasks_path = Path(args.tasks)
|
||||
if not tasks_path.is_file():
|
||||
sys.stderr.write(f"找不到任务板文件: {tasks_path}\n")
|
||||
return 2
|
||||
|
||||
data = load_yaml(tasks_path)
|
||||
|
||||
schema_path = Path(args.schema) if args.schema else (
|
||||
Path(__file__).resolve().parent.parent / "templates" / "tasks.schema.json"
|
||||
)
|
||||
|
||||
mode = "内置规则"
|
||||
try:
|
||||
import jsonschema # type: ignore # noqa: F401
|
||||
|
||||
if schema_path.is_file():
|
||||
errors = validate_with_schema(data, schema_path)
|
||||
mode = f"schema ({schema_path.name})"
|
||||
else:
|
||||
errors = validate_builtin(data)
|
||||
mode = "内置规则(未找到 schema 文件)"
|
||||
except ImportError:
|
||||
errors = validate_builtin(data)
|
||||
|
||||
if errors:
|
||||
sys.stderr.write(f"任务板校验失败({mode}),共 {len(errors)} 项:\n")
|
||||
for e in errors:
|
||||
sys.stderr.write(f" - {e}\n")
|
||||
return 1
|
||||
|
||||
sys.stdout.write(f"任务板校验通过({mode}):{tasks_path}\n")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
+172
@@ -0,0 +1,172 @@
|
||||
#!/usr/bin/env python3
|
||||
"""校验 Music Pilot 的 Developer/Test worker 启动命令。
|
||||
|
||||
用法:
|
||||
python3 validate_worker_command.py --role developer --command '<command>'
|
||||
python3 validate_worker_command.py --role test --command '<command>'
|
||||
python3 validate_worker_command.py --role developer --upgraded --command '<command>'
|
||||
python3 validate_worker_command.py --self-test
|
||||
|
||||
退出码:0 通过 / 1 规则不通过 / 2 用法或命令解析错误。
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import shlex
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
CODEX_YOLO = "--dangerously-bypass-approvals-and-sandbox"
|
||||
CURSOR_YOLO = "--yolo"
|
||||
|
||||
|
||||
def option_value(tokens: list[str], *names: str) -> str | None:
|
||||
for index, token in enumerate(tokens):
|
||||
for name in names:
|
||||
if token == name and index + 1 < len(tokens):
|
||||
return tokens[index + 1]
|
||||
prefix = f"{name}="
|
||||
if token.startswith(prefix):
|
||||
return token[len(prefix) :]
|
||||
return None
|
||||
|
||||
|
||||
def codex_effort(tokens: list[str]) -> str | None:
|
||||
configs: list[str] = []
|
||||
for index, token in enumerate(tokens):
|
||||
if token in {"-c", "--config"} and index + 1 < len(tokens):
|
||||
configs.append(tokens[index + 1])
|
||||
elif token.startswith("--config="):
|
||||
configs.append(token.split("=", 1)[1])
|
||||
for config in configs:
|
||||
if config.startswith("model_reasoning_effort="):
|
||||
return config.split("=", 1)[1].strip('"\'')
|
||||
return None
|
||||
|
||||
|
||||
def validate(role: str, command: str, upgraded: bool = False) -> list[str]:
|
||||
try:
|
||||
tokens = shlex.split(command)
|
||||
except ValueError as exc:
|
||||
return [f"命令无法解析:{exc}"]
|
||||
if not tokens:
|
||||
return ["启动命令不能为空"]
|
||||
|
||||
executable = Path(tokens[0]).name
|
||||
errors: list[str] = []
|
||||
|
||||
if upgraded and role != "developer":
|
||||
errors.append("只有 Developer 可以使用 --upgraded")
|
||||
|
||||
if executable == "codex":
|
||||
if CODEX_YOLO not in tokens:
|
||||
errors.append(f"Codex worker 必须包含 {CODEX_YOLO}")
|
||||
|
||||
model = option_value(tokens, "-m", "--model")
|
||||
effort = codex_effort(tokens)
|
||||
if upgraded:
|
||||
expected_model = "gpt-5.6-sol"
|
||||
allowed_efforts = {"high", "xhigh"}
|
||||
elif role == "developer":
|
||||
expected_model = "gpt-5.6-terra"
|
||||
allowed_efforts = {"medium"}
|
||||
else:
|
||||
expected_model = "gpt-5.6-luna"
|
||||
allowed_efforts = {"low"}
|
||||
|
||||
if model != expected_model:
|
||||
errors.append(
|
||||
f"Codex {role} 模型应为 {expected_model},实际为 {model or '未指定'}"
|
||||
)
|
||||
if effort not in allowed_efforts:
|
||||
expected = "/".join(sorted(allowed_efforts))
|
||||
errors.append(
|
||||
f"Codex {role} reasoning effort 应为 {expected},实际为 {effort or '未指定'}"
|
||||
)
|
||||
elif executable == "cursor-agent":
|
||||
if upgraded:
|
||||
errors.append("Cursor worker 不使用 Codex --upgraded 映射")
|
||||
if CURSOR_YOLO not in tokens:
|
||||
errors.append(f"Cursor worker 必须显式包含 {CURSOR_YOLO}")
|
||||
model = option_value(tokens, "--model")
|
||||
if model != "auto":
|
||||
errors.append(f"Cursor {role} 模型应为 auto,实际为 {model or '未指定'}")
|
||||
else:
|
||||
errors.append(f"不支持的 worker CLI:{executable};只允许 codex 或 cursor-agent")
|
||||
|
||||
return errors
|
||||
|
||||
|
||||
def run_self_test() -> int:
|
||||
cases = [
|
||||
(
|
||||
"codex developer",
|
||||
"developer",
|
||||
f"codex {CODEX_YOLO} -m gpt-5.6-terra -c model_reasoning_effort=medium",
|
||||
False,
|
||||
True,
|
||||
),
|
||||
(
|
||||
"codex test",
|
||||
"test",
|
||||
f"codex {CODEX_YOLO} -m gpt-5.6-luna -c model_reasoning_effort=low",
|
||||
False,
|
||||
True,
|
||||
),
|
||||
(
|
||||
"codex upgraded developer",
|
||||
"developer",
|
||||
f"codex {CODEX_YOLO} -m gpt-5.6-sol -c model_reasoning_effort=high",
|
||||
True,
|
||||
True,
|
||||
),
|
||||
("cursor worker", "test", "cursor-agent --yolo --model auto", False, True),
|
||||
("naked codex", "developer", "codex", False, False),
|
||||
(
|
||||
"wrong codex role model",
|
||||
"test",
|
||||
f"codex {CODEX_YOLO} -m gpt-5.6-terra -c model_reasoning_effort=medium",
|
||||
False,
|
||||
False,
|
||||
),
|
||||
("cursor without yolo", "developer", "cursor-agent --model auto", False, False),
|
||||
]
|
||||
failures: list[str] = []
|
||||
for name, role, command, upgraded, expected_pass in cases:
|
||||
passed = not validate(role, command, upgraded)
|
||||
if passed != expected_pass:
|
||||
failures.append(name)
|
||||
if failures:
|
||||
sys.stderr.write("worker 命令校验器自测失败:" + ", ".join(failures) + "\n")
|
||||
return 1
|
||||
print(f"worker 命令校验器自测通过:{len(cases)} 项")
|
||||
return 0
|
||||
|
||||
|
||||
def main(argv: list[str] | None = None) -> int:
|
||||
parser = argparse.ArgumentParser(description="校验 Developer/Test worker 启动命令")
|
||||
parser.add_argument("--role", choices=("developer", "test"))
|
||||
parser.add_argument("--command")
|
||||
parser.add_argument("--upgraded", action="store_true", help="校验升级后的 Codex Developer")
|
||||
parser.add_argument("--self-test", action="store_true")
|
||||
args = parser.parse_args(argv)
|
||||
|
||||
if args.self_test:
|
||||
return run_self_test()
|
||||
if not args.role or not args.command:
|
||||
parser.error("非自测模式必须同时提供 --role 和 --command")
|
||||
|
||||
errors = validate(args.role, args.command, args.upgraded)
|
||||
if errors:
|
||||
sys.stderr.write("worker 启动命令校验失败:\n")
|
||||
for error in errors:
|
||||
sys.stderr.write(f" - {error}\n")
|
||||
return 1
|
||||
print(f"worker 启动命令校验通过:role={args.role}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -0,0 +1,79 @@
|
||||
# <项目名> Agent 协作协议(项目覆盖层)
|
||||
|
||||
> 本项目基于 ACK Skill v<ack_version>。通用规范由 `/ack` 从 Skill 自身的
|
||||
> `references/` 读取;本文件只保存项目差异。
|
||||
>
|
||||
> **本文件是「项目覆盖层」,文件名可配置。** 默认放 `docs/ack/project.md`,
|
||||
> 不占用 `AGENTS.md`,避免与团队已有的 `AGENTS.md` 约定冲突。
|
||||
> 若希望 Agent 自动加载,可在项目 `AGENTS.md` 里加一行指向本文件,或直接把本文件命名为 `AGENTS.md`。
|
||||
> 无论叫什么,都在 `tasks.yaml` 的 `project.overlayFile` 记录实际路径。
|
||||
> `docs/ack/` 只保存本项目的 `project.md` 与 `tasks.yaml`,不复制或链接 Skill。
|
||||
|
||||
## 项目概览
|
||||
|
||||
- 项目:`<project_name>`
|
||||
- 技术栈:`<tech_stack>`
|
||||
- 运行命令:`<run_command>`
|
||||
- Base URL:`<base_url>`
|
||||
- 任务板:`docs/ack/tasks.yaml`
|
||||
- 覆盖层文件:`<overlay_file_path>`(默认 `docs/ack/project.md`)
|
||||
|
||||
## 通用规范(由 ACK Skill 按需读取)
|
||||
|
||||
- 开始需求:`references/kickoff.md`
|
||||
- 角色、权限、状态机与完成定义:`references/roles-and-permissions.md`
|
||||
- 模型档位与升级规则:`references/model-routing.md`
|
||||
- 闭环流程与 worktree 对齐:`references/closed-loop.md`
|
||||
- 验收信号与三轮策略:`references/optimization-method.md`
|
||||
- 派发 prompt 模板:`references/prompt-templates.md`
|
||||
- Orca 编排命令(可选):`references/orca-adapter.md`
|
||||
|
||||
## 模型档位(项目可覆盖,默认见 references/model-routing.md)
|
||||
|
||||
| 角色 | 默认档位 | 本项目实际 |
|
||||
|------|----------|------------|
|
||||
| Coordinator (PM) | 强模型 | `<model_or_default>` |
|
||||
| Test | 中低模型 | `<model_or_default>` |
|
||||
| Developer | 中低模型 | `<model_or_default>` |
|
||||
|
||||
## 路径权限(项目覆盖层,必须填实际路径)
|
||||
|
||||
| 路径 | Coordinator | Test | Developer | 说明 |
|
||||
|------|:-----------:|:----:|:---------:|------|
|
||||
| `<spec_paths>` | R/W | Read-only | Read-only | 产品规格、API 文档、计划(PM 拥有) |
|
||||
| `<integration_test_paths>` | Read-only | R/W | Read-only | 浏览器/API 回归(Test 拥有) |
|
||||
| `<test_records_path>` | Read-only | R/W | Read-only | 复测记录 |
|
||||
| `<source_paths>` | Read-only | Read-only | R/W | 应用源码 |
|
||||
| `<unit_test_paths>` | Read-only | Read-only | R/W | 单元测试 |
|
||||
| `<shared_config_templates>` | Read-only | Read-only | R/W | 可提交配置模板 |
|
||||
| `<local_config_paths>` | Read-only | Read-only | Read-only | 本地私有配置 |
|
||||
| `tasks.yaml` | R/W | Read-only | Read-only | 只有 Coordinator 写 |
|
||||
|
||||
## 命令(项目覆盖层)
|
||||
|
||||
Developer 白盒验证:
|
||||
|
||||
```bash
|
||||
<unit_test_command>
|
||||
<build_command>
|
||||
<local_run_command>
|
||||
```
|
||||
|
||||
Test 黑盒复测:
|
||||
|
||||
```bash
|
||||
<preflight_command>
|
||||
<api_smoke_command>
|
||||
<browser_regression_command>
|
||||
```
|
||||
|
||||
任务板校验由 `/ack` 使用 Skill 自带的 `scripts/validate_tasks.py` 执行。
|
||||
|
||||
## 硬规则(其余见 references/)
|
||||
|
||||
- 三角色独立:Coordinator 只编排、Test 只验证、Developer 只实现(验证者 ≠ 实现者)。
|
||||
- 模型分层:Coordinator 用强模型且不亲自跑测试,Test/Developer 用中低模型,必要时升级(见 references/model-routing.md)。
|
||||
- `worker_done` 与复测报告都不等于完成。必须 Test 独立复测 + Coordinator 终检后才能 `verified`。
|
||||
- 只有 Coordinator 写 `tasks.yaml`;Developer 与 Test 都只读,通过消息回报。
|
||||
- 每个任务最多派发 3 轮,仍不过标记 `leftover` 并继续下一个。
|
||||
- 不提交或推送,除非用户明确要求。
|
||||
@@ -0,0 +1,136 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"$id": "https://git.yumee.top/laily/skills/skills/ack/templates/tasks.schema.json",
|
||||
"title": "ACK task board",
|
||||
"description": "tasks.yaml 的权威结构。跨语言可用;参考校验实现见 scripts/validate_tasks.py。",
|
||||
"type": "object",
|
||||
"required": ["version", "project", "tasks"],
|
||||
"additionalProperties": true,
|
||||
"properties": {
|
||||
"version": { "type": "integer", "minimum": 1 },
|
||||
"updatedAt": { "type": "string" },
|
||||
"source": { "type": "string" },
|
||||
"ackVersion": {
|
||||
"type": "string",
|
||||
"description": "接入时所基于的 ack 版本,便于日后 diff 升级"
|
||||
},
|
||||
"kitVersion": {
|
||||
"type": "string",
|
||||
"description": "旧版 ACK 版本字段;兼容读取,新项目应使用 ackVersion"
|
||||
},
|
||||
"project": {
|
||||
"type": "object",
|
||||
"required": ["name"],
|
||||
"additionalProperties": true,
|
||||
"properties": {
|
||||
"name": { "type": "string" },
|
||||
"repoPath": { "type": "string" },
|
||||
"baseUrl": { "type": "string" },
|
||||
"devWorktree": { "type": "string" },
|
||||
"overlayFile": {
|
||||
"type": "string",
|
||||
"description": "项目覆盖层文件路径,默认 docs/ack/project.md,可自定义"
|
||||
}
|
||||
}
|
||||
},
|
||||
"summary": {
|
||||
"type": "object",
|
||||
"additionalProperties": true,
|
||||
"properties": {
|
||||
"verified": { "type": "array", "items": { "type": "string" } },
|
||||
"open": { "type": "array", "items": { "type": "string" } },
|
||||
"failedRetest": { "type": "array", "items": { "type": "string" } },
|
||||
"leftovers": { "type": "array", "items": { "type": "string" } }
|
||||
}
|
||||
},
|
||||
"statusReference": { "type": "object" },
|
||||
"tasks": {
|
||||
"type": "array",
|
||||
"items": { "$ref": "#/definitions/task" }
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"open",
|
||||
"dispatched",
|
||||
"fixed_by_dev",
|
||||
"retesting",
|
||||
"failed_retest",
|
||||
"verified",
|
||||
"blocked",
|
||||
"leftover"
|
||||
]
|
||||
},
|
||||
"round": {
|
||||
"type": "object",
|
||||
"required": ["round", "result"],
|
||||
"additionalProperties": true,
|
||||
"properties": {
|
||||
"round": { "type": "integer", "minimum": 1 },
|
||||
"result": { "type": "string", "enum": ["passed", "failed"] },
|
||||
"evidence": { "type": "string" }
|
||||
}
|
||||
},
|
||||
"task": {
|
||||
"type": "object",
|
||||
"required": ["id", "title", "status"],
|
||||
"additionalProperties": true,
|
||||
"properties": {
|
||||
"id": { "type": "string", "minLength": 1 },
|
||||
"type": { "type": "string" },
|
||||
"title": { "type": "string", "minLength": 1 },
|
||||
"priority": { "type": "string" },
|
||||
"status": { "$ref": "#/definitions/status" },
|
||||
"assignee": { "type": "string" },
|
||||
"component": { "type": "string" },
|
||||
"specRefs": { "type": "array", "items": { "type": "string" } },
|
||||
"testRefs": { "type": "array", "items": { "type": "string" } },
|
||||
"description": { "type": "string" },
|
||||
"stepsToReproduce": { "type": "array", "items": { "type": "string" } },
|
||||
"expected": { "type": "string" },
|
||||
"actual": { "type": "string" },
|
||||
"evidence": { "type": "object" },
|
||||
"verification": { "type": "object" },
|
||||
"dispatch": {
|
||||
"type": "object",
|
||||
"additionalProperties": true,
|
||||
"properties": {
|
||||
"taskId": { "type": ["string", "null"] },
|
||||
"dispatchId": { "type": ["string", "null"] },
|
||||
"worker": { "type": ["string", "null"] },
|
||||
"rounds": {
|
||||
"type": "array",
|
||||
"items": { "$ref": "#/definitions/round" }
|
||||
}
|
||||
}
|
||||
},
|
||||
"resolution": {
|
||||
"type": "object",
|
||||
"additionalProperties": true,
|
||||
"properties": {
|
||||
"fixedBy": { "type": ["string", "null"] },
|
||||
"verifiedBy": { "type": ["string", "null"] },
|
||||
"verifiedAt": { "type": ["string", "null"] },
|
||||
"leftoverReason": { "type": ["string", "null"] },
|
||||
"evidence": { "type": "object" }
|
||||
}
|
||||
}
|
||||
},
|
||||
"allOf": [
|
||||
{
|
||||
"if": { "properties": { "status": { "const": "leftover" } } },
|
||||
"then": {
|
||||
"properties": {
|
||||
"resolution": {
|
||||
"required": ["leftoverReason"]
|
||||
}
|
||||
},
|
||||
"required": ["resolution"]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
# 复制为 docs/ack/tasks.yaml,替换占位符。结构见 templates/tasks.schema.json。
|
||||
version: 1
|
||||
updatedAt: "<YYYY-MM-DDTHH:mm:ss+TZ>"
|
||||
source: "Coordinator (PM) Agent"
|
||||
ackVersion: "<接入时的 ack skill 版本>"
|
||||
project:
|
||||
name: "<project_name>"
|
||||
repoPath: "<repo_path>"
|
||||
baseUrl: "<base_url>"
|
||||
devWorktree: "<dev_worktree>"
|
||||
overlayFile: "docs/ack/project.md"
|
||||
|
||||
summary:
|
||||
verified: []
|
||||
open: []
|
||||
failedRetest: []
|
||||
leftovers: []
|
||||
|
||||
tasks:
|
||||
- id: "BUG-001"
|
||||
type: "bug"
|
||||
title: "<short title>"
|
||||
priority: "P0"
|
||||
status: "open"
|
||||
assignee: "developer"
|
||||
component: "<source file or module>"
|
||||
specRefs:
|
||||
- "<docs/spec.md#section>"
|
||||
testRefs:
|
||||
- "<tests/browser/cases/01-case.md>"
|
||||
|
||||
description: >
|
||||
<What is wrong, in user-visible terms.>
|
||||
|
||||
stepsToReproduce:
|
||||
- "<step 1>"
|
||||
- "<step 2>"
|
||||
|
||||
expected: >
|
||||
<Expected behavior.>
|
||||
|
||||
actual: >
|
||||
<Actual behavior observed by Test.>
|
||||
|
||||
evidence:
|
||||
browser: "<snapshot text, screenshot path, or UI finding>"
|
||||
api: "<curl result or API mismatch>"
|
||||
logs: "<relevant log line if any>"
|
||||
|
||||
verification:
|
||||
commands:
|
||||
- "<unit/build command>"
|
||||
- "<browser/API smoke command>"
|
||||
browser:
|
||||
page: "<page path>"
|
||||
checks:
|
||||
- "<visible text or interaction expected>"
|
||||
|
||||
dispatch:
|
||||
taskId: null
|
||||
dispatchId: null
|
||||
worker: null
|
||||
rounds: []
|
||||
|
||||
resolution:
|
||||
fixedBy: null
|
||||
verifiedBy: null
|
||||
verifiedAt: null
|
||||
leftoverReason: null
|
||||
@@ -2,9 +2,9 @@
|
||||
name: skiff
|
||||
description: >-
|
||||
创建和维护 ~/.skills 自研 skill:把项目开发中产生的想法提炼为草稿,完善并校验后发布,
|
||||
用 skiff add/remove 在项目及全局挂卸 skill,或用 skiff kit init 初始化项目规范包。
|
||||
用 skiff add/remove 在项目及全局挂卸 skill,或用 skiff init 初始化 skill 项目状态。
|
||||
触发词:skiff、自研 skill、创建 skill、想做一个 skill、publish skill、安装自研 skill、
|
||||
更新 skill 到项目、初始化 kit。
|
||||
更新 skill 到项目、初始化 skill。
|
||||
---
|
||||
|
||||
# skiff 自研 Skill 工作流
|
||||
@@ -136,15 +136,15 @@ skiff rm discussion-notes -g -y # rm 别名
|
||||
skiff add --list
|
||||
```
|
||||
|
||||
初始化项目 kit:
|
||||
使用 Skill 自带模板初始化项目状态:
|
||||
|
||||
```bash
|
||||
skiff kit init ack # 当前项目,默认软链接到 SSOT
|
||||
skiff kit init ack --project ~/app # 指定项目
|
||||
skiff kit init ack --copy # 用户明确要求时整份复制
|
||||
skiff init ack
|
||||
skiff init ack --project ~/app
|
||||
```
|
||||
|
||||
`skiff` 只负责可靠地创建 kit 文件。需要分析项目并完善 ACK 配置、检查接入状态或
|
||||
`skiff` 只负责可靠地生成项目状态文件,不复制或链接 Skill。需要分析项目并完善
|
||||
ACK 配置、检查接入状态或
|
||||
运行三角色闭环时,显式调用全局 `/ack` skill。
|
||||
|
||||
---
|
||||
@@ -173,7 +173,7 @@ skiff kit init ack --copy # 用户明确要求时整份复制
|
||||
| `create <name> --idea TEXT [--from-project PATH]` | 创建自研 skill 草稿 |
|
||||
| `check <name>` | 校验草稿或正式 skill |
|
||||
| `finalize <name>` | 校验草稿并转为正式 skill |
|
||||
| `kit init <name> [--project DIR] [--copy]` | 在项目中初始化 kit |
|
||||
| `init <name> [--project DIR]` | 使用 skill 模板初始化项目状态 |
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user