feat(ack): add structured worker model routing

This commit is contained in:
2026-07-31 23:34:13 +08:00
parent ee66dbe9ce
commit ae3bce7b5d
23 changed files with 6491 additions and 327 deletions
+14 -2
View File
@@ -18,6 +18,9 @@
`docs/ack/knowledge.yaml`
- [ ] 技术栈、运行、构建、单测和集成测试命令均来自项目证据。
- [ ] Coordinator、Developer、Test 的模型档位和升级规则已明确。
- [ ] `project.orchestration` 使用受支持的 profileVersion,模型都命中项目
allowlist,默认 profile 与角色/档位一致。
- [ ] `allowedWorktrees` 只列出同一 Git common-dir 下已经核对的绝对 worktree。
## 路径权限
@@ -56,8 +59,17 @@
## 编排
- [ ] 已选择 Orca 或手动模式。
- [ ] 派发前优先复用同 worktree、同角色、同配置的空闲 worker。
- [ ] Developer 与 Test 的启动命令通过校验
- [ ] 自动创建只调用 `launch_worker.py plan|launch`,没有直接拼接
`orca terminal create --command` 或自由 worker 命令
- [ ] `launch` 使用刚审阅的 `plan.launchFingerprint` 作为
`--expected-launch-fingerprint`;漂移时重新 plan。
- [ ] Developer/Test 只使用 `read-only``workspace-write` profile
v0.10 没有 full-access、bypass、YOLO/force 或关闭 sandbox。
- [ ] v0.10 每次自动派发都启动 fresh worker;没有把历史 receipt checksum 或
Orca live metadata 当作自动复用授权。
- [ ] launcher receipt 已追加到顶层 `workerReceipts`,任务分别引用
`dispatch.developer``dispatch.test`;每个引用的 task/role/profile/attempt
都与当前任务、本轮 receipt 完全一致,没有用单一 handle 混淆两个角色。
- [ ] 多 worktree 场景只有一个权威 `tasks.yaml``knowledge.yaml`
- [ ] Test 使用的服务来自正确 worktree。
+50 -11
View File
@@ -2,8 +2,8 @@
本文件定义**与具体编排工具无关**的三角色协作闭环。运行时调度可以用 Orca(见 `orca-adapter.md`),也可以手动跑(见下方「手动模式」)。
原则:调度消息只是运行时载体,任务结论必须回写到 `tasks.yaml`跨任务复用、已经
验证的项目经验必须由 Coordinator 回写到 `knowledge.yaml`。不要把消息当最终记录。
原则:调度消息只是运行时载体,任务结论必须回写到 `tasks.yaml`;已经验证且可跨
任务使用的项目经验必须由 Coordinator 回写到 `knowledge.yaml`。不要把消息当最终记录。
角色定义见 `roles-and-permissions.md`Coordinator 只编排、Test 只验证、
Developer 只实现。
@@ -34,10 +34,13 @@ Coordinator 发现或读取 open 任务
-> 从 knowledge.yaml 按 scope 推荐 active 知识,Coordinator 确认固定 revision 的 knowledgeRefs
-> 为新轮次生成稳定 attemptId<task-id>-A<round>),Developer 与 Test 共用
-> 决定 worktree:当前 worktree 起子 agent,还是新建隔离 worktree(见下节「子任务放哪」)
-> 解析 worker:先复用同 worktree、同角色的空闲 worker;没有可复用项时才校验命令并新建(见 orca-adapter.md
-> 解析安全 profile:机器配置只读 tasks.yaml.project.orchestration
-> 运行 launcher plan 并审阅 launchFingerprint
-> 带 expected fingerprint 启动 fresh worker,把 receipt 写回 tasks.yaml(见 orca-adapter.md
-> dispatch 给 Developer--to <worker handle>
-> waitDeveloper 的 worker_done / escalation(含 knowledgeApplied / knowledgeCandidates
-> writeback fixed_by_dev
-> 为 Test 独立解析安全 profile,重新 plan/launch fresh worker 并写回 receipt
-> dispatch 给 Testretesting
-> waitTest 的 retest_result(含 knowledgeChecks 和 candidate 独立证据)
-> Test 通过:gateCoordinator 读证据对齐意图)
@@ -48,7 +51,9 @@ Coordinator 发现或读取 open 任务
```
一次派发只修一个明确问题(细则见 `optimization-method.md` §「每轮派发只修一个明确问题」)。
「决定 worktree」「解析 worker」两步的决策见下节与 `model-routing.md` / `orca-adapter.md`
「决定 worktree」「解析 profile/receipt」几步的决策见下节与 `model-routing.md` /
`orca-adapter.md`。v0.10 不自动复用历史 receipt 或既有终端;标题、preview、分支名、
worker 自报和无密钥 receipt checksum 都不能代替可信启动 attestation。
Coordinator 默认给新逻辑轮次生成 `<task-id>-A<round>`,并在记录轮次结果时写入
`tasks[].dispatch.rounds[].attemptId`。它独立于编排工具产生的 `taskId`
`dispatchId`:前者用于知识来源追溯,后两者只用于查询运行时。0.9.0 之前的历史
@@ -101,23 +106,48 @@ Test 对显式引用回报 `not_applicable` 时,说明 Coordinator 的选择
Coordinator 派发前先决定 Developer/Test 在哪工作。两种方式:
**方式 1:当前 worktree 复用或起子 agent(终端)**
**方式 1:当前 worktree 起 fresh 子 agent(终端)**
```bash
# 先按 orca-adapter.md 的 worker 复用流程查找空闲终端;没有时才创建
orca terminal create --worktree active --command "cursor-agent --yolo --model auto" --title "ACK-DEV-CURSOR-AUTO-1" --json
# v0.10 不自动复用既有终端;先审阅 plan:
python3 <ack-skill-dir>/scripts/launch_worker.py plan \
--project-root <project-root> --task-id <task-id> \
--attempt-id <task-id>-A<round> --role <developer-or-test> \
--profile-id <profile-id> --worktree <absolute-current-worktree> --slot <1..99>
python3 <ack-skill-dir>/scripts/launch_worker.py launch \
--project-root <project-root> --task-id <task-id> \
--attempt-id <task-id>-A<round> --role <developer-or-test> \
--profile-id <profile-id> --worktree <absolute-current-worktree> --slot <1..99> \
--expected-launch-fingerprint <plan 中的 sha256:...>
```
- 适合:串行闭环、一次一个 Developer 任务、小改动、Test 要复测的正是 Developer 改的那棵树。
- 优点:单一服务实例、无跨 worktree 对齐困扰、开销小。
- 风险:多个 agent 同时改同一棵树会互相踩(半构建状态、git 冲突)。
- 记录:`launch` 成功后把 receipt 追加到权威 `tasks.yaml.workerReceipts`,并把
`receipt.id` 写入 `dispatch.<role>.receiptId`、把 `profileId` 写入
`dispatch.<role>.profileId`、把本轮稳定 ID 写入 `dispatch.<role>.attemptId`
receipt 的 task/role/profile/attempt 必须与当前 dispatch 完全一致,不能只记录
一个裸 handle,也不能引用旧任务或旧轮次 receipt。
**方式 2:新建隔离 worktree,再在其中起子 agent**
创建成功后,先把 Orca 返回的绝对路径加入权威任务板的
`project.orchestration.allowedWorktrees` 并重新运行 `validate_tasks.py`;未进入
allowlist 的路径不能交给 launcher。
```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"
# 对返回的绝对路径调用 ACK launcher
python3 <ack-skill-dir>/scripts/launch_worker.py plan \
--project-root <project-root> --task-id <task-id> \
--attempt-id <task-id>-A<round> --role <developer-or-test> \
--profile-id <profile-id> --worktree <absolute-new-worktree> --slot <1..99>
python3 <ack-skill-dir>/scripts/launch_worker.py launch \
--project-root <project-root> --task-id <task-id> \
--attempt-id <task-id>-A<round> --role <developer-or-test> \
--profile-id <profile-id> --worktree <absolute-new-worktree> --slot <1..99> \
--expected-launch-fingerprint <plan 中的 sha256:...>
```
- 适合:并行多个互不依赖的子任务、大/高风险/实验性改动、要保持基线分支干净(如 prod 不动、feature 走独立分支)、要独立 build 或跑独立服务实例、best-of-N 尝试。
@@ -136,8 +166,13 @@ orca terminal create --worktree path:<new> --command "cursor-agent --yolo --mode
**项目状态(SSOT)只落一处**:无论开几个 worktree`tasks.yaml`
`knowledge.yaml` 都只认一个权威副本(通常在基线/协调所在 worktree),由
Coordinator 单写。不要每个 worktree 各留一份会分叉的项目状态。模型固定方式见
`model-routing.md``orca-adapter.md`
Coordinator 单写。`project.orchestration`、顶层 `workerReceipts` 和任务 dispatch
也只写入这个副本;不要每个 worktree 各留一份会分叉的项目状态。profile 解析、
launcher 与 receipt 规则见 `model-routing.md``orca-adapter.md`
两种 worktree 方式都只允许 profile 中的 `read-only` / `workspace-write` 安全权限。
v0.10 的 full-access 授权与撤销机制仍是 Deferredlauncher 遇到 full-access 或等价
的 sandbox 绕过请求必须 fail closed。
---
@@ -158,6 +193,10 @@ Coordinator 单写。不要每个 worktree 各留一份会分叉的项目状态
手动模式下同样遵守:worker_done / 复测报告都不等于最终结论、只有 Coordinator
`tasks.yaml``knowledge.yaml`、三轮失败留档。
手动交给用户已打开的会话不等于产生 ACK receipt。该会话可以完成本次显式 handoff,
但不能因此进入 Orca 自动派发信任路径;后续自动派发仍需重新通过 ACK launcher
创建 fresh worker。
---
## Test 复测(编排无关)
+10 -1
View File
@@ -68,10 +68,14 @@ docs/ack/
编辑 `docs/ack/tasks.yaml`
- `ackVersion` 使用 ACK Skill 的 `VERSION`
- `ackVersion` 使用 ACK Skill 的合法 SemVer `VERSION`;从 `0.10.0`
`project.orchestration` 与顶层 `workerReceipts` 必须同时存在。
- `updatedAt` 使用当前带时区时间。
- `project.name``repoPath``devWorktree``overlayFile``knowledgeFile` 使用
真实值。
- `project.orchestration.allowedWorktrees` 使用已核对的绝对 worktree;模型
allowlist、profiles 和 defaults 使用项目实际允许值。不要把完整启动命令、
`extraArgs``env` 或任意 executable 写进任务板。
- 非服务项目的 `baseUrl` 写为 `n/a`
- 没有真实任务时使用 `tasks: []`,不要保留或虚构示例任务。
@@ -109,6 +113,11 @@ python3 <ack-skill-dir>/scripts/validate_knowledge.py docs/ack/knowledge.yaml --
- `project.overlayFile` 指向真实文件。
- `project.knowledgeFile` 指向 `docs/ack/knowledge.yaml`
- Developer 与 Test 的验证命令可执行。
- `project.orchestration` 的 profile/allowlist/defaults 通过校验,自动模式只允许
`read-only``workspace-write`;旧任务板未迁移时保持手动模式。
- 顶层 `workerReceipts``dispatch.developer/test` 的 task/role/profile/attempt
引用一致;`receiptId``attemptId` 同时为空或同时填写。持久 receipt 只作审计,
v0.10 不自动复用旧终端。
- 网站或 API 项目写清服务启动、重启和 Base URL。
- 任务中的固定 revision `knowledgeRefs` 都能解析,非 `active` 条目没有被派发。
+64 -21
View File
@@ -6,7 +6,11 @@
## 前提:谁是 Coordinator
**你(发起编排的强模型会话)就是 Coordinator (PM) / 产品。** 你负责写文档、拆任务、编排、终检,**不亲自写代码、不亲自跑测试**。开发和测试是另起的 worker agent;具体 CLI、模型、reasoning effort 和执行模式必须先读项目覆盖层 `docs/ack/project.md`,禁止照抄未核对的默认命令。
**你(发起编排的强模型会话)就是 Coordinator (PM) / 产品。** 你负责写文档、拆任务、
编排、终检,**不亲自写代码、不亲自跑测试**。开发和测试是另起的 worker agent
具体 CLI、模型、reasoning effort 和执行模式的机器事实源是
`docs/ack/tasks.yaml``project.orchestration``docs/ack/project.md` 只解释项目
差异,不能提供另一套启动命令。
---
@@ -16,7 +20,7 @@
我要做一个新需求:<一句话需求>。
你作为 ack 的 Coordinator(PM),按 ACK Skill 的 references 规范执行:
1. 先读 docs/ack/project.md、docs/ack/tasks.yaml,校验 docs/ack/knowledge.yaml 并
1. 先读 docs/ack/project.md、docs/ack/tasks.yaml(包括 project.orchestration,校验 docs/ack/knowledge.yaml 并
用 `scripts/select_knowledge.py` 只读取当前任务相关的 active 条目,再读
references/roles-and-permissions.md、closed-loop.md、optimization-method.md。
2. 写产品文档到 docs/(PRD / 交互 / 验收),把需求拆成任务,每个任务的验收写成可观测信号(可见文本 / API 结果 / 交互结果)。
@@ -24,7 +28,8 @@
knowledgeRefs 写入任务;不要派发 candidate 或全量知识库。
4. 把任务写进 docs/ack/tasks.yaml(只有你写),校验 tasks.yaml 和 knowledge.yaml。
5. 先把「产品文档 + 任务拆分 + 验收信号 + 适用知识引用」给我确认,不要急着派发。
6. 我确认后,按 ack 闭环循环:先按 docs/ack/project.md 校验 Developer/Test worker 启动命令,
6. 我确认后,按 ack 闭环循环:先用 `scripts/launch_worker.py` 校验结构化
Developer/Test profile,审阅 plan 后用 expected fingerprint 创建 fresh worker
dispatch 开发 → worker_done → dispatch 测试独立复测 → 你读证据终检 → 回写 tasks.yaml
每个任务最多三轮,三轮不过记 leftover 并升级我复盘。
```
@@ -45,6 +50,9 @@ python3 <ack-skill-dir>/scripts/validate_tasks.py docs/ack/tasks.yaml
python3 <ack-skill-dir>/scripts/validate_knowledge.py docs/ack/knowledge.yaml --tasks docs/ack/tasks.yaml
```
`project.orchestration` 是 worker profile 的机器 SSOT;未知字段、非 allowlist 模型、
不匹配的角色/档位和非安全权限必须在派发前 fail closed。
5. **停下来给人确认**:这是强模型该花时间的地方,不要跳过。
---
@@ -58,26 +66,58 @@ python3 <ack-skill-dir>/scripts/validate_knowledge.py docs/ack/knowledge.yaml --
---
## 第 3 步:复用或启动 worker
## 第 3 步:审阅并启动 worker
先读 `docs/ack/project.md` 的项目覆盖规则,再按 `orca-adapter.md` §「解析并复用 worker」执行:先列出现有终端和活跃任务,优先复用同 worktree、同角色、配置兼容且空闲的 worker。只有没有可复用项时才创建新终端;如果项目提供 `validate_worker_command.py`,校验未通过时不得创建。
先读 `tasks.yaml.project.orchestration` 的结构化 profiles。v0.10 不把历史 receipt
或既有 Orca terminal 当作自动复用授权;每次自动派发都创建 fresh worker。原因和
边界见 `model-routing.md` §「Receipt、审计与复用边界」。
先查看目标 profile hash,确认本次结构化配置。这个 hash 只用于审计和漂移比较,
不能用于匹配或复用旧 receipt / 既有终端:
```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
python3 <ack-skill-dir>/scripts/launch_worker.py profile-hash \
--project-root <project-root> --profile-id <profile-id>
```
上面的 `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`
生成只读计划:
```bash
python3 <ack-skill-dir>/scripts/launch_worker.py plan \
--project-root <project-root> --task-id <task-id> \
--attempt-id <task-id>-A<round> --role <developer-or-test> \
--profile-id <profile-id> --worktree <absolute-worktree> --slot <1..99>
```
审阅计划后执行唯一创建入口:
```bash
python3 <ack-skill-dir>/scripts/launch_worker.py launch \
--project-root <project-root> --task-id <task-id> \
--attempt-id <task-id>-A<round> --role <developer-or-test> \
--profile-id <profile-id> --worktree <absolute-worktree> --slot <1..99> \
--expected-launch-fingerprint <plan 中的 sha256:...>
```
`launch` 的 fingerprint 必须来自刚才审阅的 plan;若中间任何关键事实漂移,重新
plan,不得覆盖检查。标准输出是单一 JSON。Coordinator 校验其中的 receipt 后,把
receipt 原样追加到 `tasks.yaml.workerReceipts`,把 `receipt.id` 写入该任务
`dispatch.<role>.receiptId`、把 `profileId` 写入 `dispatch.<role>.profileId`,并把
本轮稳定 ID 写入 `dispatch.<role>.attemptId`。三者必须与 receipt 的当前
task/role/profile/attempt 完全绑定;不得把旧任务或旧轮次的 receipt 改挂到当前
dispatch。后续
紧随其后的本次 Orca dispatch 只使用这次 fresh receipt binding 中的 handle;持久化
receipt 仅用于审计,不能在后续轮次自动复用。不要自行拼装 Agent CLI 或 Orca 的
底层创建命令。
新 worktree 时可先运行
`orca worktree create --name <feature> --base-branch <base> --json`,再对返回的绝对
worktree 走同一套 `plan` -> 带 expected fingerprint 的 `launch`。在调用 launcher
前,先把新
路径加入 `project.orchestration.allowedWorktrees` 并重新运行任务板校验。profile
只允许 `read-only``workspace-write`v0.10 的 full-access 授权通道尚未实现,
任何 bypass、YOLO/force 或关闭 sandbox 的请求都必须失败,不能手写命令兜底。
选型与升级见 `model-routing.md`
---
@@ -85,6 +125,7 @@ orca terminal create --worktree active --command "$CURSOR_CMD" --title "ACK-DEV-
```text
task-create → dispatch 给 DEV → 等 worker_done
→ 每个角色都通过 plan + expected fingerprint launch fresh worker 并写回 receipt
→ 每轮使用 Coordinator 分配的稳定 <task-id>-A<round>
→ 回写 fixed_by_dev → dispatch 给 TEST 复测 → 等 retest_result
→ Developer 回 knowledgeApplied / knowledgeCandidatesTest 回 knowledgeChecks
@@ -110,6 +151,8 @@ Coordinator 只内联本轮 `knowledgeRefs` 指向的少量知识,不要求 wo
## 一句话
产品文档 + 验收信号写在前(你,强模型)→ 确认显式 `knowledgeRefs`按项目
覆盖层校验并启动 DEV/TEST → 核对实际模型 → dispatch / 复测 / 终检循环 → 任务
结论落 `tasks.yaml`,验证后的跨任务知识由 Coordinator 落 `knowledge.yaml`
产品文档 + 验收信号写在前(你,强模型)→ 确认显式 `knowledgeRefs`
`tasks.yaml.project.orchestration` 解析安全 profile → 审阅 plan 并用 expected
fingerprint 启动 fresh DEV/TEST → dispatch / 复测 / 终检循环 → 任务结论落
`tasks.yaml`,验证后的
跨任务知识由 Coordinator 落 `knowledge.yaml`
+164 -41
View File
@@ -1,8 +1,11 @@
# 模型路由(稳定核心)
本文件是**三角色默认模型档位**和**升级规则**的单一事实源(SSOT)。目标:在不牺牲质量的前提下降低 token 和模型成本——把昂贵的强模型留给需要判断的工作,把机械执行交给较弱模型
本文件是**三角色默认模型档位、升级规则和 worker profile 选择规则**的单一规范源
目标是在不牺牲质量的前提下降低 token 和模型成本:把昂贵的强模型留给需要判断的
工作,把机械执行交给较弱模型。
角色定义见 `roles-and-permissions.md`Coordinator 编排 / Test 验证 / Developer 实现)。本文件只补一层正交的「用哪个档位的模型」。
角色定义见 `roles-and-permissions.md`Coordinator 编排 / Test 验证 / Developer
实现)。本文件只补一层正交的「用哪个档位、以什么安全 profile 启动 worker」。
---
@@ -14,7 +17,9 @@
| Test | 中低模型 | 按既定验收信号执行浏览器/API/脚本,主要做观察、记录、逐条 pass/fail |
| Developer | 中低模型(按任务升级) | 多数实现可照规格执行;跨系统、数据迁移、重复失败时再升级 |
关键点:Coordinator 用强模型但**不亲自跑测试**(测试由 Test 承担),所以强模型的 token 花在思考和终检上,而不是反复点击页面、跑 smoke、复制日志。这一分工天然省 token,同时保持「验证者 ≠ 实现者」。
Coordinator 用强模型但**不亲自跑测试**(测试由 Test 承担),所以强模型的 token
花在思考和终检上,而不是反复点击页面、跑 smoke、复制日志。这一分工天然省 token,
同时保持「验证者 != 实现者」。
---
@@ -51,67 +56,183 @@
- 需要设计新的抽象。
- 低档位反复产出表面修复。
升级动作本身由 Coordinator 判断并记录(可写进 `tasks.yaml``dispatch` 备注或 `resolution`)。
升级由 Coordinator 判断并记录原因。升级不是修改一个正在运行的终端:必须选择
对应强档 profile,重新计算 `profileHash`,再通过 launcher 创建新的 worker。
v0.10 不自动复用持久化 receipt 指向的旧终端,Test 也不得使用 Developer 的强档
worker。
---
## 如何给 worker 指定模型(编排相关)
## 结构化 worker profile
**模型不由编排层设置。** Orca 的 `orchestration task-create` / `dispatch` 没有 `--model` 参数——`dispatch` 只是把任务投递给一个已存在的终端 handle。**模型在创建 worker 终端、启动 agent CLI 时用 CLI 自带的 flag 固定**,之后该终端的所有 dispatch 都用这个模型。
### 机器事实源
**默认不跨 Agent CLI 创建 worker。** Coordinator 应按自己所在的运行环境选择同类 worker:Cursor 会话创建 `cursor-agent` workerCodex 会话创建 `codex` worker。不要依赖 Coordinator 凭模型回答来猜测运行环境或精确模型名;以实际 CLI / 终端环境为准。只有项目 overlay 或用户明确指定跨 Agent 时,才混用不同 CLI,并记录原因。
worker 路由的机器可读事实只保存在 `docs/ack/tasks.yaml`
`project.orchestration``project.md` 可以解释项目为何选某个档位,但不能另写一份
完整启动命令或覆盖机器配置。字段结构以 `templates/tasks.schema.json` 为准。
因此「档位 → 具体模型」的映射是 **agent 相关** 的,落地方式见 `orca-adapter.md` §「给 worker 终端固定模型」。常见 CLI
每个 profile 明确声明
| 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 的模型参数或配置 |
- `role``developer``test`
- `cli`:受支持的 Agent CLI
- `tier`:角色模型档位;
- `model`:项目 allowlist 中的精确模型 ID
- `reasoningEffort`CLI 支持时显式声明;
- `permissionMode`:只允许 `read-only``workspace-write`
执行模式也必须在创建 worker 时固定,并服从项目覆盖层或用户的明确要求。Cursor 的 YOLO 参数是 `--yolo`Codex 的等价参数是 `--dangerously-bypass-approvals-and-sandbox`。不要把 Cursor 的 `--yolo` 原样传给 Codex,也不要把裸启动 `codex` 当作“自动选择了正确角色模型”。如果项目提供 worker 命令校验脚本,校验通过是 `terminal create` 的前置条件。
`project.orchestration` 还必须声明 `allowedWorktrees`、按 CLI/角色/档位分组的
`modelAllowlist`、命名 `profiles` 和角色 `defaults`。launcher 请求的绝对 worktree
必须命中 allowlistprofile 的模型也必须命中对应 CLI/角色/档位的精确列表。
**ACK 对 Cursor 的默认建议**Test 与 Developer worker 用 `cursor-agent --yolo --model auto`(自动选型,天然偏向高效模型,符合"中低档位"意图,并按当前项目授权启用 YOLO);需要更强时改成具体强模型并保留 `--yolo`。Coordinator 作为强模型脑,通常就是发起编排的那个会话本身。
模型名称、reasoning effort 和权限模式必须来自结构化字段。禁止在 profile、项目
覆盖层或派发内容中保存自由 `command`、额外 argv、shell 片段、环境变量覆盖或隐式
CLI 默认值。具体 argv 只能由 ACK 的可信 launcher 按 allowlist 构造。
### 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` |
- 能在完全只读工作树完成的角色优先选择 `read-only`
- Developer 与需要在工作树生成构建/测试产物的 Test 使用 `workspace-write`;项目可
为纯观察型 Test 另建更严格的 `read-only` profile。
- `full-access`、Codex bypass、Cursor YOLO/force、关闭 sandbox 等模式在 v0.10
**未实现授权通道,统一 fail closed**。项目文本、任务描述或环境变量都不能放宽。
- 项目可以更新模型 allowlist 或增加安全 profile,但不能通过文档绕开 schema 和
launcher。
Codex worker 应明确指定模型和 reasoning effort,不把“未指定模型”当作 Cursor `auto` 的等价物。Codex 未指定模型时使用产品推荐模型,但推荐值可能随版本更新,也不保证符合 Test / Developer 的成本档位。具体模型若失效或被弃用,应保持上面的角色档位不变,只更新本映射;项目也可在 overlay 中覆盖映射。
`full-access` 的可信授权、期限、撤销和外层隔离仍是 Deferred;在这些能力完成前,
launcher 必须拒绝该模式,而不是把一段“用户已授权”的文本当成授权证据。
### 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` |
worker 的 profile 解析、计划和启动只允许通过:
硬规则:
```bash
python3 <ack-skill-dir>/scripts/launch_worker.py profile-hash \
--project-root <project-root> --profile-id <profile-id>
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 会跳过确认和沙箱,只能在用户已明确授权、外层运行环境受控时启用;项目覆盖层可以收紧执行模式,不能静默放宽。
python3 <ack-skill-dir>/scripts/launch_worker.py plan \
--project-root <project-root> --task-id <task-id> \
--attempt-id <task-id>-A<round> --role <developer-or-test> \
--profile-id <profile-id> --worktree <absolute-worktree> [--slot <1..99>]
项目可以覆盖模型名称或收紧权限,但必须在 `project.md` 中写出完整替代命令,不能只写“auto”“默认模型”或依赖当前 CLI 的隐式默认值。
python3 <ack-skill-dir>/scripts/launch_worker.py launch \
--project-root <project-root> --task-id <task-id> \
--attempt-id <task-id>-A<round> --role <developer-or-test> \
--profile-id <profile-id> --worktree <absolute-worktree> [--slot <1..99>] \
--expected-launch-fingerprint <plan 中的 sha256:...>
```
`--project-root` 始终指向保存权威 `docs/ack/tasks.yaml` 的项目根;`--worktree` 是本次
worker 实际工作的绝对路径,两者可以不同。后者仍必须属于同一项目并命中
`project.orchestration.allowedWorktrees`
- `profile-hash` 读取 `tasks.yaml` 中的 profile,输出确定性 hash。
- `plan` 只校验并展示将使用的结构化计划,不创建终端。
- `launch` 是唯一允许创建 worker 的入口;它要求传入刚审阅的
`plan.launchFingerprint`,当前 profile、任务/attempt、worktree、CLI 或 argv
任一事实漂移都会在创建前失败。它内部固定 Orca 调用和 Agent argv,标准输出只有
一份 JSON 结果。
- launcher 的内部 bootstrap 属于私有协议,Coordinator 不直接调用、不复制到项目
文档,也不自行拼装 Orca 的底层终端创建文本。
Coordinator 在执行 `launch` 前必须先审阅 `plan`。任何校验失败、字段未知、路径不
匹配、CLI 不可用或权限模式不支持,都停止创建并回报,不回退到裸 Agent 命令。
---
## 可执行信任边界
v0.10 的 launcher 还执行以下约束:
- 不读取调用者传入的 `PATH` 来寻找 `git`、Orca 或 Agent CLI,只在固定的系统与
当前用户工具目录中解析受支持的可执行文件;候选目标必须由 root/当前用户拥有、
不是 group/other writable,并在 plan 与 bootstrap 间保持相同 device/inode。
- Git、Orca 和 CLI version probe 使用不含供应商凭据的控制环境;worker 使用
`per-cli-allowlist-v1`Codex 只取得 Codex 所需凭据,Cursor 只取得 Cursor 凭据,
不跨 CLI 透传。`DBUS_*``DISPLAY``WAYLAND_DISPLAY``XDG_RUNTIME_DIR`
`LD_*``PYTHON*``NODE_OPTIONS``CODEX_HOME``GIT_*` 和调用者 PATH 均不会
透传给 worker。
- worktree 除了命中项目 allowlist、属于同一 Git common-dir,还必须精确出现在
`git worktree list --porcelain -z` 中;`.git` symlink 冒充的目录会失败。
- Orca 的 `--command` 只含固定 bootstrap 与随机 launch ID。终端创建后,父进程先
绑定 runtime/handle/incarnation/worktree,再通过该终端 stdin 发送一次性 nonce
bootstrap 校验 nonce 后才允许启动 Agent CLI,并把 child PID 与 nonce/launch
fingerprint 绑定的 proof 原子写入 ready 状态;父进程看到并核对 proof 后才把
worker 视为可派发。
- `orca terminal create` 一经发出,在取得确定 handle 前遇到超时、transport/解码
异常、进程中断、非零退出、畸形 JSON 或缺字段,一律标记为 `indeterminate`
禁止自动重试。
- 取得 handle 后若任一绑定或握手检查失败,launcher 会先用
`orca terminal close --tab --json` 请求持久关闭,并严格核对 runtime、handle、
tab 和 close mode。只有关闭回执完整匹配才记为普通 `failed`;关闭无法确认时保持
`indeterminate/reconcile-required`,调用方必须先人工核对,不能直接重试。
- bootstrap 在真正启动 Agent 前,会在同一 launch-record 锁内再次确认状态仍为
`awaiting-authorization` 且没有 cleanup;父进程一旦先进入 cleanup/reconcile
bootstrap 必须拒绝 `Popen`,不能让取消后的 workspace-write worker 继续启动。
- 异常路径的 launch record 写入失败不能阻断上述关闭动作,也不能遮蔽原始
`indeterminate`。即使关闭已确认,只要最终状态无法可靠持久化,也保守返回
`indeterminate/reconcile-required`
这些约束防止任务板、任务文本和普通环境变量变成第二个启动命令入口。它们不抵御已经
完全控制 Coordinator 用户账户、Orca 运行时、受信 Agent/Orca 可执行文件或
Coordinator 用户级 Agent 配置/插件/MCP 的攻击者;该场景需要独立 OS 身份、受控
Agent 配置或平台签发能力。`permissionMode` 约束的是 Agent CLI 的 shell/文件系统
执行模式,不是模型供应商或外部工具能力的 attestation。
---
## Receipt、审计与复用边界
成功启动返回的 JSON 含一个可校验 receipt。Coordinator 把 receipt 追加到
`tasks.yaml` 顶层 `workerReceipts`,并把它的 `id` 写入当前任务
`dispatch.<role>.receiptId`、把 `profileId` 写入 `dispatch.<role>.profileId`,同时把
本次 `<task-id>-A<round>` 写入 `dispatch.<role>.attemptId`
这三个字段不是可任意组合的历史索引。任务板校验器要求被引用 receipt 的
`createdFor.taskId` 等于当前 ACK `tasks[].id``createdFor.role` 等于 dispatch
角色,`profileId` 完全相同,且 `createdFor.attemptId` 等于
`dispatch.<role>.attemptId``receiptId: null``attemptId` 必须同为 `null`
`receiptId` 非空时 `attemptId` 必须存在并命中本轮。`dispatch.<role>.taskId` 是 Orca
运行时 task ID,不能拿来替代 ACK task ID 或稳定 attempt ID。
receipt 至少把以下事实绑定在一起:
- `profileHash` 与请求的角色、模型、effort、权限和精确 argv
- `slot`,确保 fingerprint 也绑定审阅过的 worker 槽位和派生标题;
- 任务、attempt、绝对 worktree 及 path/device/inode/git common-dir 等稳定身份;
- Orca `runtimeId`、terminal `handle``incarnationId`
- 创建时间、launcher 指纹和 `receiptHash`
`receiptHash` 是无密钥的规范 JSON checksum,只能发现意外漂移或未同步修改,**不是
launcher 身份证明,也不是复用授权**。项目内有写权限的一方可以修改 receipt 后重算
hash;而当前 Orca metadata 又不能证明终端最初执行的命令、模型和权限。因此 v0.10
明确禁止根据持久化 receipt 自动复用既有终端:每次需要自动派发 worker,都重新走
`plan` → 带 expected fingerprint 的 `launch`,只使用该次 launcher 标准输出中的
fresh handle 完成本次派发。
`launchFingerprint` 是确定性的完整计划漂移校验,不是一次性授权或幂等键。同一份
计划重复执行 `launch` 会创建新的 fresh terminal;成功后不得用同一 fingerprint
再次启动。若结果不确定,必须先 reconcile,不能把重跑当作恢复方式。未来需要自动
防重放时,应由 Orca/ACP 的原子 idempotency/claim 能力或项目外可信 launch intent
提供,而不是把 checksum 冒充成一次性令牌。
持久化 receipt 仍用于审计、dispatch 关联和检测配置漂移;标题、preview、分支名、
worker 自报或单独的 Orca live metadata 都不能把旧终端提升为可信 worker。未来只有
在 Orca/ACP 提供启动参数 attestation,或存在项目外可信签发与校验通道后,才开放
自动复用。CLI / 模型变更仍需更新 allowlist 并重新生成 receipt。
`ackVersion` 必须使用合法 SemVer。`0.10.0` 及以后版本的任务板必须同时存在
`project.orchestration` 与顶层 `workerReceipts`;其中任一字段出现,另一个也必须
出现,避免 schema-only 校验把半迁移任务板误判为可自动派发。
---
## 成本原则
强模型产出高密度、可复用的产物:需求、架构决策、验收信号、任务拆分、失败复盘。
中低模型消费这些产物,产出可核对的执行证据:测试结果、快照、API 响应、构建日志、改动文件清单。
中低模型消费这些产物,产出可核对的执行证据:测试结果、快照、API 响应、构建日志、
改动文件清单。
这样把昂贵推理挡在重复执行之外。
@@ -119,4 +240,6 @@ Codex worker 应明确指定模型和 reasoning effort,不把“未指定模
## 一句话
Coordinator 是脑,Test 是眼,Developer 是手。脑用最强的模型且不做机械测试,眼和手用便宜模型,只有常规闭环卡住时才升级。
Coordinator 是脑,Test 是眼,Developer 是手。脑用模型且不做机械测试,眼和手
默认用安全、较低成本的结构化 profile;只有常规闭环卡住时才升级,并且所有 worker
都必须经 launcher 产生可核对的 receipt。
+57 -53
View File
@@ -23,79 +23,83 @@ orca orchestration task-list --json
orca orchestration inbox --limit 20 --json
```
确认:Orca runtime 可达Coordinator、Developer、Test 三个终端存在;Developer 在正确 worktree;当前没有冲突的活跃编排任务。
确认:Orca runtime 可达并取得本次 `runtimeId`Coordinator 终端存在;当前没有冲突
的活跃编排任务。Developer/Test worker 必须通过本次 launcher 新建,不要求预先存在。
---
## 解析并复用 worker
## 既有 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 会过期。
复用决策:
v0.10 **不自动复用任何既有终端**`receiptHash` 是无密钥 checksumOrca 当前的
terminal metadata 也不包含原始 Agent argv、模型或权限 attestation;两者即使完全
匹配,仍不足以证明旧终端由可信 launcher 以目标 profile 创建。标题、preview、分支
名或 worker 自报更不能作为证明
| 情况 | 动作 |
|------|------|
| 任务已记录 worker,且该 handle 存活、兼容、空闲 | 优先复用原 handle |
| 有其它同 worktree、同角色、兼容的空闲 worker | 复用该 handle |
| 同角色 worker 存在但都 busy | 创建下一编号的临时并发 worker |
| worker 已关闭、断开或不存在 | 创建新 worker |
| 模型升级或 worktree 不同 | 不复用不兼容 worker,创建对应档位/路径的新 worker |
| 历史 receipt 与 live metadata 看似完全匹配 | 只作审计,不自动复用;重新 launch |
| 没有 receipt,或只有同名终端 | 复用;重新 launch |
| 需要并发 worker | 使用下一 `slot` 重新 launch |
| Developer 升级模型档位 | 选择强档安全 profile,重新 plan/launch |
只有刚刚成功返回的 `launch` 标准输出中的 fresh handle,才可用于紧随其后的本次
dispatch。未来若 Orca/ACP 增加启动参数 attestation,或 ACK 接入项目外可信签发
通道,再单独设计自动复用;不能用项目文档声明跳过这条限制。
---
## 给 worker 终端固定模型
## 通过 launcher 创建 worker
**编排层不设模型。** `task-create` / `dispatch` 都没有 `--model``dispatch --to <handle>` 只是把任务投给一个已存在的终端,用的是那个终端里 agent 会话启动时的模型。要固定模型,就在 **创建 worker 终端** 时用 agent CLI 的模型参数:
**模型不由 Orca dispatch 设置。** `task-create` / `dispatch` 只投递任务;Agent CLI
模型、reasoning effort 和权限由 `tasks.yaml.project.orchestration` 的结构化 profile
决定,并且只能由 ACK launcher 构造。
默认沿用 Coordinator 当前所在的 Agent CLICursor Coordinator 创建 Cursor workerCodex Coordinator 创建 Codex worker。不要通过询问模型来猜运行环境;以当前 CLI / 终端环境为准。除非项目 overlay 或用户明确指定,否则不跨 Agent CLI 创建 worker。
先只读生成计划:
```bash
# CursorTest / 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
# CodexDeveloper 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
# CodexTest 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
python3 <ack-skill-dir>/scripts/launch_worker.py plan \
--project-root <project-root> --task-id <task-id> \
--attempt-id <task-id>-A<round> --role <developer-or-test> \
--profile-id <profile-id> --worktree <absolute-worktree> --slot <1..99>
```
这些创建命令只在复用流程找不到空闲兼容 worker 时执行。拿到返回的 handle 后再 `task-create` + `dispatch --to <handle>`,并把 handle 写入 `tasks.yaml``dispatch.worker`。模型档位与选型策略见 `model-routing.md`
需要隔离/并行时,先建新 worktree 再在其中起 worker(是否新建见 `closed-loop.md` §「子任务放哪」):
确认计划中的任务、attempt、角色、profile hash、绝对 worktree 和安全权限模式后,再
执行唯一启动入口:
```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
python3 <ack-skill-dir>/scripts/launch_worker.py launch \
--project-root <project-root> --task-id <task-id> \
--attempt-id <task-id>-A<round> --role <developer-or-test> \
--profile-id <profile-id> --worktree <absolute-worktree> --slot <1..99> \
--expected-launch-fingerprint <plan 中的 sha256:...>
```
- `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 时改;要换模型需新建终端。
`launch` 必须携带刚才审阅的 `plan.launchFingerprint`;若 profile、任务/attempt、
worktree、CLI identity/version 或精确 argv 漂移,创建前就失败。它内部调用当前
Orca 后端并完成终端绑定;Coordinator 不自行执行或拼装 Orca 的底层终端创建文本,
也不直接调用 launcher 的私有 bootstrap
若 launcher 报告 `indeterminate``reconcile required`,说明终端可能已经创建且
持久关闭尚未得到可信确认;此时先按返回的 launch ID/record 和 Orca live state
人工核对,禁止直接重复执行 `launch`
标准输出是单一 JSON。成功后:
1. 校验返回 receipt 的 `receiptHash`
2. 把 receipt 原样追加到 `tasks.yaml.workerReceipts`
3. 把 `receipt.id` 写入当前任务 `dispatch.<role>.receiptId`,把 `profileId` 写入
`dispatch.<role>.profileId`,把本轮 `<task-id>-A<round>` 写入
`dispatch.<role>.attemptId`;校验器会要求 receipt 的 task/role/profile/attempt
与当前 ACK 任务完全一致;
4. 再用 receipt binding 中的 handle 创建/派发 Orca 子任务。
profile 只允许 `read-only``workspace-write`。v0.10 不提供可信的 full-access 授权
通道;bypass、YOLO/force、关闭 sandbox 及其它 full-access 请求必须由 schema 和
launcher fail closed,不能改用手写命令兜底。模型档位与升级规则见
`model-routing.md`
需要隔离/并行时,可以先用 Orca 创建 worktree。Coordinator 必须先把返回的绝对
路径加入 `project.orchestration.allowedWorktrees` 并重新校验 `tasks.yaml`,然后才在
该路径上走 `plan` -> 带 expected fingerprint 的 `launch`,并把 receipt 留作审计。
既有会话可以由用户直接操作,但不能进入 ACK v0.10 的自动派发信任路径。
---