mcpField
D
delegate

delegate

github.com/lvlup-swAgent 工作流22102 次安装1 天前更新
代码仓库

关于 delegate

用于通过准备、派发和结算流程协调子 Agent 实现工作的技能,面向已有待执行功能任务的编排者。它强调任务上下文完整、使用独立 worktree,并在验收时验证结果。

主要功能

  1. 01准备并固定任务批次
  2. 02向子 Agent 派发任务
  3. 03在 git worktree 中隔离工作
  4. 04结算并验证任务结果
  5. 05按任务风险选择模型等级

适用场景

  1. 01并行处理独立实现任务
  2. 02派发功能工作流任务
  3. 03集成前验证委派成果

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/lvlup-sw/exarchos --skill delegate

安装后在 Claude Code 中输入/delegate确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
adaptive-orchestration.md
agent-teams-saga.md
fix-mode.md
fixer-prompt.md
fixer-prompt.md.test.sh
implementer-prompt.md
implementer-prompt.md.test.sh
parallel-strategy.md
pbt-patterns.md
rationalization-refutation.md
state-management.md
testing-patterns.md
troubleshooting.md
worked-example.md
workflow-steps.md
worktree-enforcement.md

详细介绍

委派技能

将实现任务分派给子 Agent,并提供适当的上下文、工作树隔离和 TDD 要求。此技能遵循三步流程:准备、分派、结算。

prepare 会将工作流中尚未完成的任务编译为一个不可变的任务包——任务图、每项任务的结果契约与验证条款,以及用于评判工作的权威依据——并将其固定。子 Agent 批量运行任务,期间不进行任何治理调用。settle 会将它们的结果作为一个批次提交:根据固定的任务包裁定每项声明,自行运行每项已接受任务的验证,并将任务标记为完成。随后,编排器会合并工作树并完成状态转换。

该任务包针对 feature 工作流编译。工作流类型为 prepare 时会拒绝执行(WORKFLOW_TYPE_UNSUPPORTED),并改用本技能末尾附录中的原始流程。

触发条件

在以下情况下启用此技能:

  • 用户运行 {{COMMAND_PREFIX}}delegate 命令
  • 实现计划已就绪,且其中包含可提取的任务
  • 用户希望将工作并行分派给多个子 Agent

例外——oneshot 工作流完全跳过委派。 oneshot 操作手册会在主 Agent 的上下文中运行会话内 TDD 循环,不分派子 Agent,也不进行审核阶段。如果 workflowType === "oneshot",不要调用此技能——轻量级流程请参阅 @skills/oneshot/SKILL.md。

核心原则

每项任务使用全新上下文(强制要求)

每个子 Agent 都必须从干净、完整独立的上下文开始。正如 Anthropic 多 Agent 协作最佳实践所述:

  • 不得假设共享状态。 每条子 Agent 提示词都必须包含完整的任务描述、文件路径、TDD 要求和验收标准。绝不要说“参阅计划”或“如前所述”。
  • 不得交叉依赖其他 Agent。 除非计划中明确通过依赖边进行排序,否则子 Agent A 不得依赖子 Agent B 的输出。
  • 隔离工作树。 每个子 Agent 都在自己的 git worktree 中运行。在同一工作树中运行并行 Agent 会破坏分支状态。

违反此原则的合理化模式收录于 references/rationalization-refutation.md。

委派模式

默认的 subagent 模式使用运行时的生成原语 {{TASK_TOOL}} 来分派每项任务。

在 Claude Code(以及任何未来声明 team:agent-teams 的运行时)中,还可以使用 agent-team 模式——Task 调用会绑定到 team_name,以便进行交互式多窗格协作。

模式机制最适合
subagent(默认)运行时生成原语1~3 项独立任务、CI、无头模式
agent-team使用 team_name 的 Task3 项以上相互依赖的任务、交互式会话

**自动检测:**存在 tmux 和 CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS 时使用 agent-team,否则使用 subagent。使用 {{COMMAND_PREFIX}}delegate --mode subagent|agent-team 可覆盖此设置。

模型选择——推理层级,而非版本

任务的层级是 capsule 的 settlementContract.taskVerification[taskId].riskTier——在批次编译时根据计划冻结(规划器的 **Risk Tier:** 标记优先;否则由文件和层级启发式规则决定)。通过 agents.tier-models 根据该值解析模型层级(默认值为 low → haiku、medium → sonnet、high → opus;操作员可在 .exarchos.yml 中覆盖,且会进行单调性验证,确保更高的风险层级绝不会解析为更弱的模型)。如果任务没有对应的项(例如在批次之外派发修复任务),则省略 model,继承会话默认值。

如果运行时仍会提供 recommendedModel,它表示的是推理层级(haiku | sonnet | opus),而非模型版本。

以下三条规则构成完整策略:

  1. 绝不在任何地方写入模型版本——无论是派发指令、Agent 规范、技能还是提示词。不要使用 claude-*-YYYYMMDD,不要使用 -latest,也不要使用次版本号。内容中固定的版本字符串会成为第二个模型权威,悄无声息地凌驾于操作员的层级策略之上,并在下一次发布时过时。传递层级别名,让运行框架根据自身当前的目录解析它。
  2. 模型强度取决于风险,而非角色。 Agent 的选择决定角色(实现者/修复者/审查者/脚手架);层级阶梯决定强度。在 Agent 规范中固定模型 ID 是缺陷——因此所有随附的规范都声明 model: inherit。
  3. 如果需要版本,请查阅目录,不要凭记忆。 在派发时,从运行框架自身的模型列表中解析当前的层级→版本映射。根据训练数据回忆模型信息,本身就会过时;猜测标识符,最好的情况是安全失败,最坏的情况是悄然降级。

unless otherwise specified 指在 .exarchos.yml 中明确设置操作员覆盖项(agents.default-model、agents.models、agents.tier-models),而不是在派发时自行判断。

派发前的架构发现

派发前,先查询决策手册,对工作进行分类并选择合适的策略:

  1. 任务复杂度: 调用 exarchos_orchestrate({ action: "runbook", id: "task-classification" }),获取认知复杂度分类树。低复杂度任务可使用脚手架 Agent 规范,以加快执行速度。
  2. 派发策略: 调用 exarchos_orchestrate({ action: "runbook", id: "dispatch-decision" }),获取派发策略(并行还是顺序、团队规模、隔离模式)。

步骤 1:准备

步骤 1——编译批次
exarchos_orchestrate({ action: "prepare", featureId: "<featureId>", repoRoot: "<absolute path of the worktree that holds baseRef>" })

prepare 会读取工作流计划,并将其就绪前沿——所有尚未完成且其 blockedBy 任务均已完成的任务——编译到一个 capsule 中,在托管状态下按摘要固定,并在与其记录相同的提交中逐一发布每个任务的 task.assigned 事件——此前不会发生任何调用。保留回执:settle 以 capsuleVersion 为键,而每个子 Agent 的数据包都基于 capsule 构建。

repoRoot 为必填项,且必须是绝对路径。传入包含 baseRef 的工作树:即检出集成分支的工作树。prepare 从该检出中读取仓库、配置和不变量目录,而不是从服务端所在目录读取。它会在 capsule 中固定仓库和检出(settlementContract.scope),并为每个任务固定 baseRef 的提交(baseCommit)。

在封装中你从中读取的内容
graph.tasks[]、graph.dependencies[]、graph.joins[]批次及其必须遵循的运行顺序——dependencies 边 { from, to } 表示 to 必须等待 from
settlementContract.taskVerification[taskId]任务的 riskTier 和 boundaryTouching,它们根据计划冻结——模型层级以及结算将运行的关卡;任务的 baseRef,即集成分支,杀伤性探测会以此测量任务的差异;以及任务的 baseCommit,即 prepare 时 baseRef 的提交,任务的工作树从这里开始
settlementContract.scope仓库(repository,即其 git 公共目录)、prepare 读取的检出(checkout),以及该检出配置文件的摘要(configDigest)。结算会拒绝不在此范围内的已声明工作树,也会拒绝 prepare 后发生变化的配置
knowledge.patterns[]批次中每个层级的一条陈述,列出这些关卡——将其原样插入工作者的提示词
contracts.taskResults[taskId]任务必须报告的内容:worktreePath(必填)、branch,以及其来源信息(files、implements、tests、acceptanceTestRef)
contracts.deviationEnvelope当封装假设被证明有误时,工作者可提出的内容(invalidated-assumption、missing-context)——而不是猜测——以及其中哪些类型属于重大偏差(materialDeviationKinds:invalidated-assumption),因此接受此类偏差会修订设计
authority.invariants[]、authority.escalationBoundaries[]评判工作的依据,以及必须上报而不能自行决定的事项——粘贴到每个任务包中
authority.delegatedDecisions[]封装留给工作者决定的事项,每项都有一个 id。声明可以用其中一个 ID 作为 rationale 记录选择。将它们粘贴到每个任务包中
knowledge.rationale[]设计的权威记录;对于基于修订后设计(design-v2 或更高版本)编译的封装,还包括此后的已接受变更:每项变更用一条陈述说明由谁决定、给出提案时所提的变更,以及偏差说明了什么;最多列出八项变更,之后用一条陈述统计其余变更
executionProfile.capabilities此运行时必须具备的条件才能运行到这里;prepare 已经拒绝了不符合要求的运行时

拒绝项,均未编译任何内容:

代码含义操作
WORKFLOW_TYPE_UNSUPPORTED不是功能工作流采用基本流程(附录)
PHASE_NOT_PREPARABLE不在 delegate 阶段先进行阶段转换
NOTHING_TO_PREPARE所有计划任务均已完成转换到审查阶段
NO_READY_TASKS任务仍待处理,但每项任务都在等待某个尚未完成的任务(消息中会列出这些任务)先解决或修复阻塞任务;互相等待的任务构成循环,需要在计划中打破
BASE_UNRESOLVED工作流未记录集成分支(或分支名称不是安全的引用名称),因此没有任务的基准exarchos_workflow({ action: "update", featureId: "<featureId>", updates: { "synthesis.integrationBranch": "<branch the tasks fork from>" } }),然后再次执行 prepare
BASE_UNRESOLVED检出仓库中没有集成分支的任何提交,或批次任务的某个已完成阻塞任务落在基准不包含的提交上(消息中会指出两者)创建该分支,或传入包含它的 repoRoot。合入阻塞任务,然后再次执行 prepare。在 serialize_merge 之外通过压缩合并或变基合入的阻塞任务,需要有记录的 merge.executed 行(references/troubleshooting.md)
SCOPE_UNRESOLVEDrepoRoot 不在 git 工作树中,或位于与最新 capsule 不同的仓库;检出的配置无法加载;已注册目录无法解析;或配置未将 check_static_analysis 设为阻塞项(消息中会指出具体情况)修复消息中指出的问题,然后再次执行 prepare(references/troubleshooting.md)
UNKNOWN_DEPENDENCY、INVALID_TASK_ID、INVALID_TASK_STAMP、CAPSULE_UNSOUND计划无法表示为批次修复计划,然后再次执行 prepare
RUNTIME_UNFIT此运行时缺少结算所需的能力,无法验证该批次(消息中会指出具体情况)停止;不要派发——该批次永远无法在此处结算
REVISION_UNREADABLEcapsule 将说明某个设计修订所接受的更改,但包含这些更改的结算包(消息中会指出)无法读取,或缺少该修订列出的偏差或已接受的决策在运行包存储中恢复该包,然后再次执行 prepare。没有绕过办法:在包恢复前,工作流会停在此处

输入未变时,重试会返回已记录的 capsule;如果计划、集成分支或基准提交发生变化,使用了其他检出,编辑了配置文件或设计记录,或记录了新的设计修订,则会编译下一个版本,并标记编译时的设计版本(identity.designVersion、design-v<N>)。每一轮都要执行 prepare,不能每个工作流只执行一次:capsule 只包含就绪的前沿,因此第一轮结算后才会编译第二轮的 capsule。

Worktree

每项任务都在其独立的关联 worktree 中执行。该 worktree 由宿主在原生隔离环境中创建,或通过 setup_worktree 按规范路径 .worktrees/<taskId>-<taskName> 布置。任务绝不会在 prepare 读取的检出目录或仓库的主 worktree 中运行。settle 和 task_complete 都会拒绝这两种情况(the-checkout),因为已准备的工作流中的每项任务都必须在自己的关联 worktree 中运行。在原生隔离环境中,必须在任何 Agent 编辑文件之前,确认每个 Agent 的工作目录都位于 .worktrees/ 下(检查其首次报告的 pwd);如果 Agent 位于共享检出目录,则停止该 Agent,手动为其创建 worktree(git worktree add --detach .worktrees/<taskId>-<taskName> <baseCommit>,使用 capsule 中该任务的 baseCommit),之后才允许其编辑。手动创建的 worktree 处于分离状态,因此 Agent 的基础步骤会为任务创建分支。任务声明中携带的路径就是 worktree 路径,结算时也会对此路径进行验证。

工作者从 <baseCommit> 开始。在入口检查完成后、任何文件改动之前,实现者或脚手架构建者会运行 git switch -c <own branch> <baseCommit>(其 Agent 定义中的基础步骤),这样每次运行时,其 worktree 都会基于该提交。<own branch> 必须是当前尚未被任何分支占用的名称。它不能是 setup_worktree 或 git worktree add -b 创建的 worktree 分支,因为分支已存在时,git 会拒绝执行 git switch -c。修复者会继续使用该任务之前的分支(见下文“修复失败任务”)。如果 worktree 的 HEAD 未包含 <baseCommit>(base-not-held),或者 worktree 位于 baseRef 分支上(on-the-base-branch),结算都会拒绝。终止探针会根据 baseRef 测量任务的差异。每个 worktree 都必须保持干净:如果 git status --porcelain 的输出不为空(uncommitted-changes),结算会拒绝。链接的 node_modules 需要使用忽略规则 node_modules,末尾不能有斜杠。

提取任务

capsule 固定的是条款;计划包含的是正文。根据实现计划,为每个 capsule 任务提取:

  • 完整任务说明(直接粘贴,不得引用外部文件)
  • 要创建或修改的文件,使用相对于 worktree 根目录的路径(例如 src/foo.ts);不得使用仓库父目录中的绝对路径,也不得包含逃出 worktree 根目录的 .. 序列。这两种路径形式都会解析到 Agent worktree 当前工作目录之外,并会悄悄将更改写入主 worktree。这是平台无关的防护措施,在每种运行环境中都必须遵守。
  • 测试文件路径(相对于 worktree)和预期的测试名称
  • 对其他任务的依赖项,取自 graph.dependencies,该字段是计划中 blockedBy 编译后的结果
  • 基于属性的测试标志(testingStrategy.propertyTests)

如需查看此流程的完整示例,请参阅 references/worked-example.md。


第 2 步:分派

使用 references/implementer-prompt.md 作为模板,构建子 Agent 提示词。每个提示词都必须包含完整的任务上下文——这是新鲜上下文原则的实际应用。

构建提示词

适用于支持原生 Agent 定义的运行环境:

实现者 Agent 定义已包含系统提示词、模型、隔离设置、技能、钩子和记忆。分派提示词应仅包含任务专属上下文:

  1. 完整任务说明(需求、验收标准)
  2. 工作目录(第 1 步中的 worktree 路径)
  3. 要创建或修改的文件路径,以及测试文件路径
  4. 质量提示(如有)
  5. 当 propertyTests: true 时,包含 PBT 标志

完整提示词模板(默认):

对于每项任务:

  1. 在实现者提示词模板中填写任务专属详情
  2. 将 Working Directory 设置为第 1 步中的 worktree 路径
  3. 在 Quality Signals 部分中加入质量提示(如有)
  4. 当 propertyTests: true 时,加入 references/pbt-patterns.md 中的 PBT 部分
  5. 加入 references/testing-patterns.md 中的测试模式
提示词中的 capsule 条款

每个数据包都会原样包含 capsule 中的内容:

  1. 任务的验证条款——其 riskTier 和 boundaryTouching,以及该层级对应的 knowledge.patterns[] 声明。这样,worker 就知道结算会对其工作树运行哪些门禁(低风险层级任务:静态分析;中风险层级任务:还包括测试充分性 kill probe;涉及边界的任务:还会运行契约漂移检查),并编写确实可能失败的测试,而不是走过场。这些条款还会给出基准:提示词会在集成分支尖端所在的位置写明 <baseCommit>,即任务的 baseCommit,worker 会从该提交开始创建自己的分支。
  2. 结果契约——contracts.taskResults[taskId] 字段。worker 的完成报告就是其声明:worktreePath、branch、files、implements、tests。无需填写证据字段:结算运行门禁时会记录证据。未完成任务的 worker 应报告状态和原因,不填写任何结果字段(Build the batch,Step 3)。
  3. 权限依据——authority.invariants[] 和 authority.escalationBoundaries[],以及 偏差范围:如果 capsule 的某项假设被证明有误,worker 应报告偏差(从 contracts.deviationEnvelope.allowedDeviationKinds 中选择 deviationKind,说明哪些内容不成立,并提出变更方案),而不是悄悄绕过。出现偏差会暂停批次,等待人工处理;悄悄绕过则会在结算时被拒绝,或者更糟,被接受。
  4. 委派的决策——authority.delegatedDecisions[],其中每项均包含 id 及其声明。worker 可以自行做出这些选择,无需审批。它可以在报告中以理由说明某项选择,并注明对应的 id。理由不能注明其他 id:委派决策之外的选择应作为偏差报告。
  5. 已接受的设计变更——在根据修订后的设计编译的 capsule 中,knowledge.rationale[] 声明会遵循当前设计。worker 从干净的上下文开始,因此数据包会向它说明有哪些变更。

派发时使用该数据包,而不是静态 Agent 默认提示。 随附的 agents/implementer.md 固定写入了一条中风险层级说明(为预先绑定命名 Agent 的运行时提供的独立备用方案)。只有在不存在 capsule 条款时(例如派发修复任务),才原样使用该说明。层级是 capsule 中的纯数据;这里不涉及按工作流类型分支处理。

决策手册

对于派发策略决策,请查询决策手册: exarchos_orchestrate({ action: "runbook", id: "dispatch-decision" })

此手册提供结构化标准,用于判断并行还是顺序派发、确定团队规模,以及处理失败升级。

并行派发

使用运行时原生的 spawn 原语,在单条消息中派发所有相互独立的任务,使其并行运行。

{{SPAWN_AGENT_CALL agent="implementer" description="Implement task-001: [title]" prompt="Task-specific context: requirements, file paths, acceptance criteria"}}

注意: 在派发载荷中加入 references/implementer-prompt.md 中的完整 implementer 提示词模板,确保启动的 Agent 拥有独立完整的上下文——会预先将 implementer 提示词绑定到命名 Agent 的运行时会自动丢弃重复内容。

并行分组策略和模型选择请参阅 references/parallel-strategy.md。

Agent Teams 派发

使用 --mode agent-team 时,请遵循 references/agent-teams-saga.md 中的 6 步 saga。该 saga 要求先发出事件再执行副作用:每个步骤都必须先发出事件,再执行副作用。

Agent Teams 的事件发出契约:完整载荷格式和补偿协议请参阅 references/agent-teams-saga.md。

事件发出契约(必需)

委派阶段需要发出以下事件(由 check-event-emissions 检查):

事件触发时机发出方
team.spawned创建团队后、派发前Orchestrator
team.task.planned计划中的每项任务(使用 batch_append)Orchestrator
team.teammate.dispatched每个子 Agent 启动后Orchestrator
task.progressed每个 TDD 阶段(red/green/refactor)结束后子 Agent
team.disbanded所有子 Agent 完成后Orchestrator

完整的事件架构和发出顺序请参阅 references/agent-teams-saga.md。

由运行时代表你发出,绝不可由你发出:task.assigned(prepare 时与其记录在同一提交中;在原语路径中,prepare_delegation 会在读取就绪状态之前发出)、task.completed 和 task.failed(由 task_complete 和 task_fail 直接发出,或作为叶节点结算流程的一部分发出)。

注意: task.progressed 事件由子 Agent 在 TDD 执行期间发出,而非由 Orchestrator 发出。Orchestrator 只发出团队生命周期事件。

验证责任契约(每项声明仅由一方负责)

每项验证声明都恰好只有一个责任方。重复验证你不负责的声明并非纵深防御,而是重复劳动——会增加此轮的成本,并且当两次验证结果不一致时,难以确定哪次才是权威结果。

声明责任方运行位置其他所有人
“此任务的行为已有测试覆盖,且测试能够失败”结算流程settle 会针对每项已接受的任务,在进程内按照任务完成手册执行,并在该声明所指的工作树中、按 capsule 锁定的级别运行实现者在自己的工作树中运行测试并报告;它不会运行任何 Exarchos 门禁。负责人阅读验证结果,不重新运行门禁
“此任务的差异干净(类型、lint、契约、模拟对象)”结算流程同一组合阶段同上
“整轮任务没有发生级联问题”负责人每轮边界仅一次——每轮合并完成后运行 check_integration_suite实现者绝不运行累积套件
“此轮任务已完成”结算流程 + 转换守卫已结算的批次会使所有已接受的任务都完成;all-tasks-complete 允许进行状态转换无需单独检查完成状态

以下两点约束了各手册的执行方式:

  1. task_complete 是任务完成手册的最后一步,而结算流程会运行该手册:所有阻塞性门禁都通过后,任务才会被记录为完成,无论由谁推动完成。 exarchos_orchestrate({ action: "runbook", id: "task-completion" }) 会列出结算流程组合执行的步骤;你无需运行这些步骤。
  2. check_integration_suite 是轮次边界的兜底检查,而非逐任务门禁。根据其自身的操作说明,它在每轮合并后恰好运行一次。逐任务的级联风险由该任务自身范围内的门禁覆盖。

负责人的唯一独立验证是抽查——阅读结算流程的验证结果和已记录的证据,并且最多抽查一项自己有具体理由怀疑的声明。全面重新运行逐任务验证链属于违反契约。


第 3 步:收集并结算

监控子 Agent

使用运行时的结果收集原语获取后台任务结果(根据运行时不同,这可能是逐项轮询/等待,也可能是内联回复):

{{SUBAGENT_RESULT_API}}
构建批次

根据每个子 Agent 的完成报告,构建一个声明。字段必须来自结果契约,不得包含其他字段——未声明的字段会被视为问题:

const claims = reports.map((r) => ({
  taskId: r.taskId,
  fields: {
    worktreePath: r.worktreePath,        // required: where the work is
    branch: r.branch,
    files: r.files,
    implements: r.implements,
    tests: r.tests,
  },
  evidence: [],                          // settlement records the evidence; a claim cites none
}))

切勿相信实现者的自我评估。 声明说明工作所在的位置;是否已完成由结算流程判定。报告存在偏差的工作者应归入 deviations({ deviationKind, statement, affectedTasks?, proposedChange? }),不得将其塞入一份粉饰过的声明中。 未完成的任务会获得状态,而不是结果。 claim 可包含可选的 status。默认值为 completed。如果没有可供结算验证的任务结果,请发送其他三个值之一:

status发送时机
failed工作人员尝试了该任务,但没有可供验证的结果
blocked在任务之外的某项内容发生变化之前,任务无法继续
skipped本次运行未尝试该任务
const notCompleted = {
  taskId: "<taskId>",
  status: "blocked",                     // or "failed", or "skipped"
  reason: "<why the task is not completed>",
}

使用这三个值之一的 claim 需要包含不超过 280 个字符的 reason。此类 claim 不包含 fields、evidence 或 rationale。已完成的 claim 不包含 reason。如果 claim 违反其中任一规则,结算会将其作为无效输入(INVALID_INPUT)拒绝,且不进行任何裁定。

对此类 claim,结算不会运行任何门禁,也不会据此记录任务完成。任务仍未解决,且不会因该 claim 而完成。结算仍会验证批次中已完成的 claim(见下文的 corrective-capsule)。状态仅存在于 claim 上:结算不会记录 task.failed 行,tasks[].status 也不会更改。如果流中已显示任务完成,则已记录的完成状态保持不变,且该 claim 不会产生任何判定。

委派权限范围内的选择应作为 rationale 写入 claim。 capsule 会列出留给工作人员决定的事项(authority.delegatedDecisions),每项都带有一个 id。prepare 编译的 capsule 会列出两项:implementation-approach 和 execution-order。已完成的 claim 可以使用其中一个 id 记录选择:

const withChoice = {
  taskId: r.taskId,
  fields: { worktreePath: r.worktreePath /* and the other fields of the result contract */ },
  evidence: [],
  rationale: [
    { delegatedDecision: "implementation-approach", statement: "<the choice, in the words of the worker>" },
  ],
}

每个 claim 最多记录四项选择,每条 statement 最多 280 个字符。rationale 不会改变任何门禁:无论是否附带 rationale,结算都会对任务执行相同的验证。它不是证据,也不会使带有判定结果的 claim 获得通过。capsule 未列出的 id 会被判定为 rationale-not-delegated,并导致批次被拒绝。委派决策范围之外的选择属于偏离,因此应写入 deviations。

偏离应说明发生了什么变化,以及涉及哪些任务。 proposedChange 由工作人员提供,按其报告填写;affectedTasks 则由编排器填写,因为只有编排器掌握计划。每个失败的假设报告一项偏离;同一假设的报告应合并为一项:每个批次最多包含十六项偏离,每项偏离最多列出三十二个任务。如果两项偏离的 statement 不同,应为它们填写不同的 statement——在响应预算内返回的回执会按 id、kind、statement 和受影响任务列出偏离,因此,如果两项偏离仅在 proposed change 上不同,负责决策的人看到的内容会完全相同。以摘要形式返回的回执(见下文的 Settle)仅按 id 和 kind 列出偏离;其 statement 和受影响任务见结算包,其中由 bundleRefs 指明。

设计修订将以 affectedTasks 中的任务为对象,并且修订只命名未完成的任务。结算会拒绝以下三类条目,随后直接拒绝批次,而不是将其暂存:

  • 计划显示已完成的任务(deviation-names-finished-task)
  • 本批次声明为已完成的任务(deviation-names-claimed-task)
  • 计划中不存在的 id(deviation-unknown-task)

已完成的工作不会重新打开——应将其返工作为新任务进行规划,并命名该新任务。

如果工作人员自己的任务依赖于错误的假设,应将该任务报告为 blocked。 该任务的 claim 应将状态设为 blocked 并提供 reason,且偏离应在 affectedTasks 中列出该任务。只有当 claim 将该任务报告为 failed、blocked 或 skipped 时,偏离才能列出同一批次中的任务。此类 claim 不会返回结果,因此偏离会改变仍待完成的工作。决策轮次会将该任务保留为未解决状态(见下文的 deviation-pending)。 结算前验证工作树状态:工作树中 git status 显示有未提交更改,意味着存在声明中未提及的工作。结算会拒绝此类工作树(uncommitted-changes)。提交任务的文件,移除每次门禁运行遗留的文件,不要提交这些文件。

结算

胶囊要求的每项任务(settlementContract.requiredResults)都需要一条声明,除非流中已显示该任务完成。提交的批次至少包含一条声明。提交批次一次,并使用你选择的 ID。该 ID 就是结算键:

exarchos_orchestrate({
  action: "settle",
  featureId: "<featureId>",
  capsuleVersion: <capsuleVersion>,      // from the prepare receipt
  batchId: "<featureId>:wave-1",
  claims,
  deviations: [],
})

客户端错误或中断不会停止调用。 服务端不会读取客户端的取消请求,因此第一次调用仍可能运行至结束。然后:

  • 在同一会话中使用相同的批次 ID 重试。服务端一次只会为每个批次 ID 运行一个调用。重试会等待第一次调用完成,然后获取第一次调用记录的判定结果。
  • 从其他会话或 CLI 重试会在另一个服务端进程中运行。它不会等待。它可能会在第一次调用仍在运行时,在同一工作树上再次运行任务的门禁。
  • 在判定结果返回之前,不要在任务工作树中编辑、提交或分派工作。每项任务的探测都会在其工作树中还原任务源文件,然后将其快照写回受跟踪的文件。此期间的更改会丢失,此期间的提交则会包含已还原的源文件。

结算首先会根据胶囊读取每条声明和每项偏差。如果胶囊固定了范围,结算还会在任何门禁运行之前,通过 git 检查每条已完成声明的工作树:工作树超出范围时,该任务会出现 worktree-out-of-scope 发现项(见下文)。任何会使批次过期、遭拒或暂缓的发现项都会停止批次,结算随后不会进行任何验证。如果没有发现项停止批次,结算会通过执行器运行每条无发现项的已完成声明的验证。报告状态的声明不会停止批次,其任务也不会接受验证。如果流中已显示某项任务完成,结算不会再次运行该任务。回执会在一次调用中列出所有原因:findings 列出每项故障,verification[] 列出每项任务的环节(operationId、outcome、failedLeaf)。

超出响应预算的回执会以摘要形式返回。摘要始终保留轮次、designRevision、每项待处理偏差(ID 和类型)以及每项决策(ID 和决策)。在 corrective-capsule 下,摘要还会保留未解决任务的数量(counts.unresolved)。摘要会保留第一页发现项(firstPage,不含消息),以及最多四个 verification[] 结果,失败项优先。每个失败项都包含其 operationId 和 failedLeaf。每项未解决任务都会以 taskId 和 cause 的形式保留。为符合预算,摘要会先删除发现项页面,再删除验证结果。然后从末尾开始删除未解决任务条目,counts.unresolvedOmitted 会说明省略的数量。bundleRefs 指向的结算包会保留完整的发现项和验证结果。

回执会列出一种结果,每种结果都有对应的下一次调用:

结果结算验证内容下一次调用
settled每项必需任务均已完成无
accepted-with-rationale每项必需任务均已完成,且有一条声明记录了委派的选择无
corrective-capsule已通过的任务均已完成,且至少有一项任务尚未解决在同一胶囊上使用新的 batchId 结算一个批次,其中仅包含 unresolved 任务
rejected无使用新的 batchId 结算修正内容
deviation-pending无使用相同的 batchId 结算,且仅包含 decisions
recompile-required无准备后,在新胶囊下结算
Settlement 会在各个分段完成后、提交过程中再次读取流。如果两次读取之间行发生变化,结果可能会改变。在读取发生变化前已由某个分段验证通过的任务仍保持完成。因此,recompile-required 或 rejected 回执的 verification[] 中可能列出 Settlement 在读取发生变化前验证通过的任务。

在 settled 或 accepted-with-rationale 后,转到步骤 4。带有 designRevision 的回执会使下一次调用进入各个结果下的 recompile-required(见下文的 designRevision)。

无论结果如何,settle 都不会编译任何 capsule。只有 prepare 会编译。设计将 settled 称为“已接受”,将 deviation-pending 称为“需要决策”。它将 accepted-with-rationale 所记录的选择称为获准的偏离。保留这些记录名称,因为已存储的行、bundle 和重放的回执都会携带这些名称。

settled — 每项必需任务都记录为已完成(task.completed,来自该原语路径所使用的叶节点)。除非流中已显示任务完成,否则已认领的任务在此批次中通过了其门禁。未认领的必需任务此前已完成。转换守卫读取的状态文档处于稳定状态。转到步骤 4。

accepted-with-rationale — 此批次已结算,且获准的认领记录了一项委托选择(见上文“构建批次”)。与 settled 一样,每项必需任务都记录为已完成,且运行了相同的门禁。execution.settled 行通过任务及其决策 ID(rationales)列出每项选择。bundleRefs 指定的结算 bundle 会保留每条说明。回执中没有用于记录这些选择的字段,因为该结果本身表示认领记录了一项选择。转到步骤 4。

发现项会先于理由决定结果。因此,含有未解决任务的批次属于 corrective-capsule,其行仍会列出已通过任务的选择。该批次的修正结果为 settled,除非其自身的某项认领记录了选择。

corrective-capsule — 至少有一项任务未解决。Settlement 已验证此批次,且已通过的任务已完成(acceptedTasks)。这些任务会保持完成。该结果沿用设计中的名称,但 settle 不会编译任何内容。

查看 unresolved。其中每项待修正任务都有一个条目,包含 taskId 和 cause。cause 表示针对该任务的发现项类型:

cause含义修正前的操作
verification-failed该任务的一项门禁已中止。条目还包含该分段的 failedLeaf 和 operationId将修复人员派遣到该任务的工作树(见下文“修复失败任务”)
worktree-out-of-scope已认领的工作树违反 capsule 的某项范围规则,因此未运行任何门禁。发现消息会指出违反的规则(unobservable、not-a-worktree-root、other-repository、the-checkout、on-the-base-branch、other-branch、base-not-held、uncommitted-changes 或 shared-worktree)以及恢复方法按照消息说明操作:从 baseRef 的 baseCommit 创建独立工作树,或提交该任务列出的文件,并移除每个门禁运行时留下的文件。references/troubleshooting.md 对每条规则都有说明
task-failed认领报告该任务为 failed派遣修复人员,或重新派遣该任务
task-blocked认领报告该任务为 blocked移除阻碍。如果某项偏离指定了该任务,回执可能会带有 designRevision(见下文)
task-skipped认领报告该任务为 skipped派遣该任务
若在叶节点保留其契约的情况下于门控叶节点停止,则会得到 verification-failed。未能运行到判定结果的门控也会得到 verification-failed:准入被拒绝、没有处理程序,或处理程序运行失败。片段也可能在完成叶节点、运行手册未列出的叶节点处停止,或因叶节点违反其契约(INTENT_EMISSION_CONTRACT_VIOLATED)而停止(包括在门控叶节点处)。这类停止不属于门控判定结果。所有片段运行完毕后,结算会再次读取完成记录。若此时流记录显示已停止的任务已完成,则以完成状态为准:该任务已完成,且 verification[] 会将其列为 already-complete。否则,非门控判定结果的停止会导致调用失败,且不会产生判定结果(见下文“错误”)。

已停止片段的发现消息会指出叶节点及停止原因。已报告状态的发现消息会给出工作器的原因。在摘要中,每个条目仅包含 taskId 和 cause,且所有发现都没有消息。bundleRefs 指向的结算包会保存每条消息。

要读取已停止片段的回执,请发送结算针对该任务发出的调用。从该任务的 verification[] 条目或 unresolved 条目中获取 operationId。只能使用该 operationId,因为使用其他 ID 会在结算之外重新运行整个片段,包括 task_complete。达到上限的摘要不会在 unresolved 条目中保留 operationId,因此此时请从 bundleRefs 指向的结算包的 verification 列表中获取。请从胶囊中该任务的条款(settlementContract.taskVerification[taskId])获取 riskTier、boundaryTouching 和 baseRef。从批次中获取 capsuleVersion,并从声明中获取其他参数:

exarchos_orchestrate({
  action: "execute_intent",
  intent: "task-completion",
  featureId: "<featureId>",
  operationId: "<operationId>",          // of the segment of the task
  args: {
    taskId: "<taskId>",
    worktreePath: "<worktreePath>",      // from the claim
    branch: "<branch>",                  // from the claim, only when the claim has one
    riskTier: "<riskTier>",              // from the capsule terms of the task
    boundaryTouching: <boundaryTouching>,
    baseRef: "<baseRef>",
    result: claimFields,                 // each field of the claim, in the key order of the claim
    capsuleVersion: <capsuleVersion>,    // the capsule of the batch
  },
})

此调用不会重新运行任何内容,而是返回已记录的回执。对于已停止的片段,回执为代码 INTENT_SEGMENT_FAILED、叶节点的消息以及 error.intentReceipt。其他参数,或 result 中键的不同顺序,都会构成不同的请求。此时调用会因 INTENT_REPLAY_DIGEST_MISMATCH 失败,且不会运行任何内容。

然后,在同一胶囊上结算一个新的批次 ID,并且只声明未解决的任务:

exarchos_orchestrate({
  action: "settle",
  featureId: "<featureId>",
  capsuleVersion: <capsuleVersion>,      // the same capsule
  batchId: "<featureId>:wave-1:correction-1",
  claims: unresolvedClaims,              // one claim for each `unresolved` entry
})

已记录的完成状态满足必需结果,因此已完成的任务无需声明。更正操作的回执会在 verification[] 中将每个此类任务列为 already-complete。

如果任务仍未完成,请再次以其状态和原因声明该任务。该批次仍是 corrective-capsule,且任务仍处于未解决状态。结算不会限制更正次数,因此请自行决定何时停止并咨询人工。

如果摘要省略了未解决条目(counts.unresolvedOmitted 大于 0),请再次声明所有必需任务。对于已完成的任务,结算不会再次运行门控,而会将该任务作为 already-complete 返回。

如果回执还包含 designRevision,请先调用 prepare(见下文“designRevision”)。然后在 prepare 返回的胶囊下进行结算。声明该胶囊要求且尚未完成的每项任务。被阻止且在其自身偏差中列出的任务也要按此流程处理。修订会列出该任务,因此在较早的胶囊上创建新批次会得到 recompile-required。

acceptedTasks 中的任务均已完成,因此 prepare 可以编译依赖其中某项任务的任务。工作树从其任务的 baseRef(即集成分支)分叉,而该分支只包含已合入的工作。在创建依赖任务的工作树之前,请先合入 acceptedTasks 中的每项任务(步骤 4,第 1 项)。 rejected — 请求或偏离存在错误。在读取时,结算未验证任何内容。在读取前已由某个阶段验证的任务仍保持完成状态,并列于 verification[] 中。请阅读 findings:

  • 形状问题(missing-field、undeclared-field、field-type-mismatch、unknown-task、undeclared-result-shape、duplicate-claim、missing-claim、inadmissible-evidence):修正声明。missing-claim 表示某个必需任务尚未完成,且没有声明。带有状态和理由的内容即为声明。对于未完成的任务,请发送一条声明。
  • rationale-not-delegated:理由指定了 capsule 未列出的决策 ID。问题消息会列出 capsule 的 ID。请删除该条目,或将该选择报告为偏离。
  • 偏离问题(deviation-outside-envelope、deviation-unknown-task、deviation-names-finished-task、deviation-names-claimed-task):批次未被暂缓。请修正偏离。超出 envelope 范围的类型属于升级处理。其余三种情况分别是偏离无法指定的 affectedTasks 条目(见上文“构建批次”)。在决策轮次中,deviation-names-finished-task 源自一个已暂缓的批次(见下文 deviation-pending)。
  • deviation-rejected:决策拒绝了该偏离(见下文 deviation-pending)。

然后,在同一个 capsule 下,使用新的批次 ID 结算修正后的请求。已有判定结果的批次 ID 已被占用,因此修正时必须使用新的批次:

exarchos_orchestrate({
  action: "settle",
  featureId: "<featureId>",
  capsuleVersion: <capsuleVersion>,
  batchId: "<featureId>:wave-1:retry-1",
  claims: correctedClaims,
})

较早的一次构建也会因声明已被取代或验证失败而返回 rejected。重放时会按该构建存储的内容返回此类回执,其 acceptedTasks 可能处于完成状态。

deviation-pending — 偏离正在等待决策。工作者提出了 envelope 范围内的偏离,而 envelope 要求审批。在读取时,结算未验证任何内容,且批次未完成任何任务。回执中的 pendingDeviations 会通过每条偏离的 deviationId 列出这些偏离,流中也会为每条记录保留一行 deviation.proposed。人工检查点:展示每条偏离及其提出的变更(回执不包含该变更)。由人员决定每条偏离。你不能决定,提出偏离的工作者也不能决定。如果运行中没有人员,则在暂缓的批次处停止:报告暂缓的回执及其待决偏离,不发送任何决策。人员作出决定后,使用这些决策且不带声明,再次结算同一个批次。结算会从记录中读取暂缓的批次:

exarchos_orchestrate({
  action: "settle",
  featureId: "<featureId>",
  capsuleVersion: <capsuleVersion>,
  batchId: heldBatchId,            // the batch the held receipt names, not a new one
  decisions: pendingDeviations.map(({ deviationId }) => ({
    deviationId,
    decision: "accepted",          // or "rejected"
    actor: "human:<who decided>",
    rationale: "<why>",
  })),
})

在一次调用中决定所有待决偏离。如果有任何一条未作决定,结算会拒绝该决策(DECISION_INCOMPLETE)。

结算会记录一项 accepted 决策(deviation.decided)。随后会验证暂缓的工作,并给出结果:settled、accepted-with-rationale 或 corrective-capsule。暂缓的声明会保留各自的状态、理由和 rationale。如果之后的设计修订指定了暂缓批次中的某项任务,结果将为 recompile-required,且结算在读取时不会验证任何内容。如果已接受的偏离指定了本轮读取时已完成的任务,结果将为 rejected,并附带 deviation-names-finished-task。该偏离不会记录任何修订,其他每项已接受的实质性偏离仍会记录其修订。请将已完成任务的返工作为新任务规划,并指定新任务。接受决策后的修正无需再次陈述该偏离。该偏离已作出决策,再次陈述它会成为一项新的提议,并暂缓新的批次。

偏离指定的被阻塞任务。 暂缓的批次将该任务报告为 blocked,且偏离指定了该任务。作出 accepted 决策后,结算会验证该批次中已完成的声明。被阻塞的任务尚未解决,因此结果为 corrective-capsule,原因是 task-blocked。 如果偏差类型属于实质性,回执还会携带 designRevision,且该修订会指明受阻任务。先调用 prepare。后续操作会在新的设计版本下编译任务,其 capsule 会说明已接受的变更。在创建依赖某个任务的任务的 worktree 之前,先完成 acceptedTasks(第 4 步,第 1 项)中的每个任务。从新数据包分派任务,并在新的 capsule 下完成结算。在较早 capsule 上执行的批次会标记为 recompile-required,无论它是否认领该任务、再次报告该任务,还是未提及该任务。

如果偏差类型不属于实质性,回执不会携带 designRevision。移除阻塞,然后在同一个 capsule 上通过新批次完成任务结算。

结算也会记录 rejected 决策。结果为 rejected,并附带 deviation-rejected 发现;结算在读取时不会验证任何内容。基于该偏差开展的工作不予接受。修正该工作,并在不包含该偏差的新批次 ID 下完成结算。如果计划中有用于处理被拒绝偏差的返工任务,则移除该任务。然后再次调用 prepare,并在其返回的 capsule 下完成结算。

结算只会记录一次决策。再次发送相同的决策会返回其裁决。对于已作出决策的批次,结算会拒绝不同的决策。

回执中的 designRevision — 该轮至少接受了一个实质性偏差,并为其记录了一项设计修订(design.revised,设计版本从 N 到 N+1),与该轮的裁决无关。回执会列出两个版本和偏差(priorDesignVersion、nextDesignVersion、deviationIds)。收到携带设计修订的回执后,如果已接受的变更需要调整计划,则先调整计划,然后再次调用 prepare — 修订指明的任务只能在修订后编译的 capsule 下完成结算。recompile-required 回执也需要同样调用 prepare。

修订后第一次调用 prepare 就是后续编译:与第 1 步相同的调用,始终会在新的设计版本下编译就绪的任务前沿,并在同一次提交中记录重新编译(capsule.recompiled)。返回的回执会携带 recompile — 其所基于的 capsule 版本和涵盖的设计版本(priorCapsuleVersion、priorDesignVersion、nextDesignVersion)、修订指明的任务(declaredTasks),以及修订使其失效的任务(invalidatedTasks):每个被指明的未完成任务,以及每个直接或通过其他未完成任务依赖这些任务的未完成任务。已完成的工作保持不变,仅依赖已完成工作的任务也保持不变。其 capsule 会携带已接受的变更(knowledge.rationale[])。尚未就绪的失效任务会列在该列表中,但不会包含在该 capsule 中:阻塞任务完成后,后续调用 prepare 会在相同设计版本下编译它。重放的回执会重复记录的重新编译;这不是新的重新编译,也不会追加任何内容。

recompile-required — 批次到达时,capsule 已过时。数据流在该 capsule 之后记录了一项设计修订。该修订指明了批次认领的某个任务,或尚未完成的必需任务。发现为 claim-superseded-by-revision。结算期间提交的修订也会导致此结果。在读取时,结算未验证任何内容,批次中的未完成任务仍未完成。修订提交前已由某个片段验证的任务仍保持完成状态,并会列在 verification[] 中。包含修订所指明的未完成必需任务的 capsule 不会结算任何新批次。决策轮也可能返回此结果,且其决策仍会被记录。 再次调用 prepare。然后在 prepare 返回的胶囊下继续。认领此胶囊要求完成且尚未完成的每项任务。修订版中提到的任务,其工作使用了早先的术语。新胶囊会说明已接受的更改(knowledge.rationale[]),因此再次认领工作前,请先阅读该更改。

说明:提到某项任务的修订版会在该任务的工作段运行期间提交。随后,作为该工作段最后一个叶节点的 task_complete 会以 TASK_SUPERSEDED_BY_REVISION 拒绝该任务。工作段结束后的读取会返回 recompile-required。如果直接调用 task_complete,则修订版在同一胶囊中提到该任务后,该调用也会以相同方式拒绝该任务。然后再次调用 prepare,并在新胶囊下完成该任务。

错误(未进行任何裁定)。以下每个代码都表示调用失败,且未进行任何裁定:

  • CAPSULE_INVALID:提交的胶囊不符合胶囊契约。
  • CAPSULE_NOT_PREPARED:此处没有记录对此胶囊版本的 prepare 调用。
  • CAPSULE_DIGEST_MISMATCH:提交的胶囊不是已记录的胶囊。
  • CAPSULE_UNRESOLVED:结算无法应用已记录的胶囊。如果任务没有验证条款,请再次运行 prepare。需要分段的批次还会因另外两种原因而遇到此问题。胶囊未固定任何范围,或者批次中的某个任务没有 baseCommit:请再次运行 prepare,然后在新批次中认领任务。prepare 之后检出内容的配置文件发生了变化:请使用相同的 repoRoot 再次运行 prepare,然后在新批次中认领任务。在决策轮次中,新的 prepare 无济于事,因为被挂起的批次仍使用其胶囊版本,因此此消息会指出其他处理途径(references/troubleshooting.md)。
  • OPERATION_DIGEST_MISMATCH:此批次 ID 已有针对不同请求的裁决,或者已有不同的决策生效。请使用新的批次 ID,或发送当前生效的决策。没有裁决但其分段已由早期构建运行过的批次也会出现此错误,因为此构建会将 capsuleVersion 添加到每个分段的请求中。请使用新的批次 ID 结算此类批次的认领。
  • CONCURRENCY_CONFLICT:决定裁决结果的读取内容在三次提交前都发生了变化,因此此次调用未记录任何裁决。请再次结算相同的批次 ID。重试会重新播放已验证任务的分段,但不会再次运行其门禁。
  • BATCH_NOT_HELD:决策指向的批次没有裁决,或者该批次并未处于挂起状态。没有偏差在等待决策。
  • DECISION_INCOMPLETE:决策回答的偏差少于该批次正在等待的偏差。
  • STATE_SYNC_FAILED:状态文档写入失败,但流中的事实仍然有效。请运行 exarchos_workflow reconcile,然后再次结算相同的批次。如果仍然被拒绝,请停止并报告给相关人员。存储文档中的版本间隔会导致每次重试都失败。重试已有裁决的批次时,error.settlementReceipt 会保留该裁决。超过回执预算时,它会保留经过截断的摘要。
  • INTENT_SEGMENT_FAILED 或 INTENT_EMISSION_CONTRACT_VIOLATED:某个任务的分段已中止,且此次中止不是门禁裁决。要么叶节点不是门禁,要么叶节点违反了契约。如果 task_complete 拒绝该任务,完成叶节点就会中止;连续发生 8 次序列冲突后也会中止。只有当批次在分段之后读取时仍处于验证状态,此次中止才会导致调用失败。消息会指出任务和叶节点。分段记录会保留,因此重试相同的批次 ID 会得到相同的中止结果,除非流随后记录了任务已完成。请修正原因,然后使用新的批次 ID 结算这些认领一次。如果再次出现相同的中止,请停止并报告给相关人员。静态分析门禁跳过运行(无工具链)不会中止分段。随后 task_complete 会以 GATE_NOT_PASSED 拒绝任务。这也属于此类中止,使用新的批次 ID 仍会再次遇到。分段运行期间,如果在工作树中提交更改或切换分支,也会导致 task_complete 拒绝(other-tree、tree-out-of-scope):在裁决返回前,请勿改动各任务的工作树。
  • INVALID_INPUT:结算无法根据认领构建分段(通常是因为缺少 worktreePath),提交的批次没有任何认领,或者决策携带了认领或未指明任何待处理偏差。违反其 status、reason 或 rationale 规则的认领也会产生此错误(见上文“构建批次”)。请修正请求并使用相同的批次 ID。
Agent Teams 监控
  • 队友会显示在 tmux 分屏窗格中
  • {{SUBAGENT_COMPLETION_HOOK}} 会自动运行质量门禁,并发出完成/失败事件
  • 编排器通过 exarchos_view delegation_timeline 监控,以检测瓶颈
  • 有关解散和协调,请参阅 references/agent-teams-saga.md
失败恢复

当任务失败时——子 Agent 报告失败,或结算后任务仍未解决(corrective-capsule):

  1. 从运行时的结果收集原语({{SUBAGENT_RESULT_API}})中读取失败输出,以及结算发现中的消息
  2. 诊断根本原因——不要相信实现者的自我评估(参见 R3 对抗性立场)
  3. 使用下方的修复流程修复任务
  4. 在同一 capsule 上结算新的批次 ID,并认领已修复的任务(步骤 3)。除非流中已显示任务完成,否则结算会验证该任务。此类任务会返回 already-complete,且不会再次运行门禁。已完成的任务无需认领。若要返工已完成的任务,请规划新任务(见下方回滚流程)

在批次结算前报告失败的工作者不会中止该批次。正确做法有两种。先修复任务,并在同一批次中将其认领为已完成。或者,将任务认领为状态 failed 并说明原因,然后立即结算批次。第二种做法会一次性完成其他任务,但修正时会多调用一次 settle。对于尚在等待的任务或没有工作者运行的任务,同样使用状态 blocked 或 skipped。

完整的恢复流程及具体示例,请参见 references/worked-example.md。

修复失败的任务

使用运行时原生的生成原语,派发一个新的修复 Agent,并提供完整的失败上下文和原始任务描述:

{{SPAWN_AGENT_CALL agent="fixer" description="Fix failed task-001" prompt="Your implementation failed. [failure context from test output and the settlement finding]. Apply adversarial verification: do NOT trust your previous self-assessment, re-read actual test output, identify root cause not symptoms. [Original task context, including the capsule's terms]."}}

优化(可选): 在支持原生会话恢复的运行时中(例如工作流状态中包含 agentId 的 Claude Code),你可以恢复原始 Agent,让它保留实现者上下文。上方的新派发方式仍然正确,也是规范的默认做法。

修复会沿着任务之前的分支继续进行,而不是开启新分支。在不支持原生隔离时,将修复 Agent 派发到任务之前的工作树。在支持原生隔离时,在派发前提交任务列出的文件,移除每个被门禁运行留下的文件,并删除之前的工作树,以便修复 Agent 将自己的工作树切换到之前的分支。references/fix-mode.md 介绍了各运行时的操作流程,以及在新分支上进行修复的恢复方法。

修复完成后,在同一 capsule 上的新批次中认领已修复的任务,并使用修复 Agent 的工作树和与之前认领相同的 branch。不要手动运行门禁链:新的 settle 调用会运行它。


第 4 步:合并并转换阶段

  1. 合并每个工作树。 完成结果包含工作树的已结算任务会使工作流进入 merge-pending;通过 serialize_merge 合并这些工作树(见下方“包含工作树的任务”),并按依赖顺序一次处理一个工作树。
  2. 波次后备检查——在波次的所有合并完成后,运行一次针对集成分支最新提交的累积测试套件:
exarchos_orchestrate({
  action: "check_integration_suite",
  featureId: "<featureId>",
  repoRoot: "<integration worktree>",
})
  1. 委派完成门禁(D4,建议性)——在转换到审核前,对整个分支差异进行运行韧性检查:
exarchos_orchestrate({
  action: "check_operational_resilience",
  featureId: "<featureId>",
  repoRoot: ".",
  baseBranch: "main"
})

此项为建议性检查——检查结果会记录在收敛视图中,但不会阻止从委派阶段转换到审核阶段。请在委派摘要中附上检查结果,以便审核阶段关注。

  1. 架构同步——如果有任何任务修改了 API 文件(*Endpoints.cs、Models/*.cs),请运行 npm run sync:schemas

  2. 转换阶段——参见末尾的“转换阶段”部分:运行 exarchos_workflow transition 转到 review。任务已全部完成;无需手动打补丁。


修复模式(--fixes)

处理审查失败,而非初始实现。使用 references/fixer-prompt.md 模板,并采用对抗式验证立场;按问题分派修复任务,然后重新调用审查以重新整合修复内容。

参数: --fixes <state-file-path> — 状态 JSON,其中包含 .reviews.<taskId>.specReview 或 .reviews.<taskId>.qualityReview 中的审查结果。

有关修复模式的详细流程,请参阅 references/fix-mode.md。

已弃用: --pr-fixes 已由 /exarchos:shepherd 取代。PR 反馈工作流请使用 shepherd 技能。


上下文压缩恢复

如果委派期间发生上下文压缩:

  1. 查询工作流状态:使用 fields: ["tasks"] 执行 exarchos_workflow get
  2. 读取每个批次的结算记录:exarchos_event({ action: "query", stream: "<featureId>", filter: { type: "execution.settled" } })。每一行都会列出其 batchId、capsuleVersion、outcome 和 acceptedTasks,以及 corrective-capsule 下的 unresolvedTasks
  3. 检查活跃工作树:执行 ls .worktrees/ 并验证分支状态
  4. 对账:exarchos_workflow reconcile 会重放事件流并修补过时的任务状态
  5. 在确认丢失之前,切勿重新创建分支或重新分派 Agent
工作树状态架构

工作树条目在工作流状态中存储为 worktrees["<wt-id>"]。每个条目都需要包含:

字段类型必填备注
branchstring是Git 分支名称
taskIdstring有条件必填单个任务 ID(用于单任务工作树)
tasksstring[]有条件必填多个任务 ID(用于多任务工作树)
status"active" | "merged" | "removed"是工作树生命周期状态

必须提供 taskId 或 tasks(非空数组)中的至少一项。

单任务示例:

{ "branch": "feat/task-001", "taskId": "task-001", "status": "active" }

多任务示例:

{ "branch": "feat/integration", "tasks": ["task-001", "task-002"], "status": "active" }

阶段转换与守卫

完整的转换表请参阅 @skills/checkpoint/references/phase-transitions.md。

快速参考: delegate → review 转换要求满足守卫 all-tasks-complete——工作流状态中所有 tasks[].status 都必须为 "complete"。

结算后的批次会将它们标记为完成:结算完成叶节点会在事件流和守卫读取的文档中,将每个已接受任务标记为完成。如果转换被拒绝,说明有任务尚未完成:其所属批次有未解决任务,或者该批次被拒绝、搁置或已过时。请读取结算记录,而非任务列表。调用 exarchos_event({ action: "query", stream: "<featureId>", filter: { type: "execution.settled" } }) 会为每一轮结算返回一行,其中包含其 outcome,以及 corrective-capsule 下的 unresolvedTasks。不要手动修改 tasks[].status 来绕过守卫。

携带工作树的任务:自动绕行至 merge-pending

当 task.completed 事件携带工作树关联信息(data.worktree 或 data.worktreePath)时,HSM 会自动经过 feature/merge-pending 转换,然后进入 review。next_actions 投影会显示合并操作(幂等键为 ${streamId}:merge_orchestrate:${taskId}),因此,使用 next_actions 的运行时会自动分派合并。

通过 serialize_merge 落地。 集成分支由多个工作树共享——同一批次中的兄弟工作树合并(或并发操作员)可能会争抢该分支。serialize_merge 是集成合并的唯一途径:它会持有按 integrationRef 划分的乐观单写者租约,然后原样组合 merge_orchestrate,在本地执行 git merge,并记录恢复点 SHA——参见 @skills/merge-orchestrator/SKILL.md。不要分派原始 merge_orchestrate 来合并到集成分支——如果存在有效的外部租约,它会以失败关闭方式退出(MERGE_LEASE_HELD,并指出 serialize_merge)。原始 merge_orchestrate 适用于非集成合并(不会被兄弟工作树触碰的私有/临时分支),或重新提交原始租约、从崩溃中恢复的调用方。

合并终止(completed/rolled-back/aborted)后,HSM 会从 merge-pending 返回 delegate。此时,如果还有下一个携带工作树的任务,delegate 会再次进入 merge-pending;如果所有委派任务均已完成,则会转至 review。

对委派技能本身而言,这次绕行不可见——所有任务均已完成的守卫仍会控制 delegate → review 转换。merge-pending 子状态只是在任务完成与下一次分派决策之间。

任务状态值
状态使用时机
pending任务尚未开始
in_progress任务正在处理中
complete任务已成功完成
failed任务遇到错误(需要修复周期)

这些是工作流状态中 tasks[].status 的取值。认领项(步骤 3)的 status 是另一个字段。认领项报告 failed 并不会将任务设为 failed。

架构发现

使用 exarchos_workflow({ action: "describe", actions: ["update", "init"] }) 查询参数架构,并使用 exarchos_workflow({ action: "describe", playbook: "feature" }) 查询阶段转换、守卫和剧本指南。使用 exarchos_orchestrate({ action: "describe", actions: ["prepare", "settle"] }) 查询控制面的自身架构——包括 prepare 的返回内容以及认领项可携带的内容。


集成分支在批次中途前进时

当子 Agent 工作树的分支偏离集成分支时,用于恢复的运行手册。触发条件是集成合并的祖先关系预检(由 serialize_merge 内部组合的 merge_orchestrate 执行)失败:失败消息会原样链接到这里,并包含手动 git rebase 命令。目前尚未接入自动 rebase——操作员必须手动处理恢复。

症状

merge-orchestrator 报告以下形式的祖先关系失败:

source branch <feature-branch> is not a descendant of <integration-branch>.
Rebase manually with: git rebase <integration-branch> (run from the <feature-branch> worktree).
Runbook: content/delivery/skills/delegate/SKILL.md#when-integration-advances-mid-wave

这表示集成分支已前进(通常是因为较早的工作树合并已落地),而发生失败的工作树仍在处理中。快进合并已不再安全——必须先让工作分支追上集成分支。

出现此问题的原因

每个子 Agent 工作树都从其任务的 baseCommit 开始,也就是 prepare 编译该批任务时集成分支所处的提交(Agent 的 base 步骤)。当编排器依次合并各个同级工作树时,每次合并都会推进集成分支。某个工作树若基于较旧的集成提交创建,轮到它时就会在祖先关系预检中失败。

这是当前单写入者合并约定下的预期行为——预检会有意只在失败时拦截,让操作人员掌控流程。

前提条件 — 固定工作树基点。 原生 isolation: worktree 会从仓库的默认分支(origin/HEAD → main)而非集成分支最新提交创建子 Agent 工作树分支,除非在 .claude/settings.json 中设置 worktree.baseRef: "head"。请保留此固定设置, 让子 Agent 工作树从接近其基点的位置开始。 当请求 nativeIsolation 但缺少此固定设置时,prepare_delegation 会明确报错,并给出以下修复方式:

{ "worktree": { "baseRef": "head" } }

工作树是干净的检出,因此只有已提交的 HEAD 状态会传递过去—— 请在派发前提交设计、计划和研究成果。

固定设置并不能保证基点。Agent 的 base 步骤会在每个运行环境中指定基点:对于实现者 或搭建者,执行 git switch -c <own branch> <baseCommit>;对于修复者,则使用任务之前的分支。 结算的 base-not-held 规则会拒绝 HEAD 未包含 <baseCommit> 的工作树。因此,操作人员无需在派发步骤前手动添加 git reset --hard <integration-tip> 作为 STEP 0。

恢复流程

每个步骤开始前,请确认你位于主工作树(而非失败的子 Agent 工作树),并且 git status 显示工作区干净。

  1. 在执行任何破坏性操作前,记录回滚 SHA:

    git rev-parse <feature-branch> > /tmp/rollback.sha
    

    保留此 SHA,直到确认合并成功。如果出现问题,在功能分支上执行 git reset --hard "$(cat /tmp/rollback.sha)",即可恢复变基前的状态。文件名特意不包含 分支名称,这样像 feature/dr-6 这样的斜杠分隔分支就不会因名称中嵌入 / 字符而破坏路径。

  2. 将功能分支变基到当前集成分支的最新提交:

    cd <feature-worktree-path>
    git fetch origin
    git rebase <integration-branch>
    

    解决出现的任何冲突。这些冲突是真实存在的——它们反映了两个分支之间的实际偏移,并非预检噪声。不要 盲目传入 --strategy-option=theirs,否则会丢弃子 Agent 的工作。

  3. 从主工作树重新运行集成合并——通过 serialize_merge,在单写入者租约下重新执行 merge_orchestrate 的祖先关系预检:

    exarchos_orchestrate({
      action: "serialize_merge",
      featureId: "<featureId>",
      integrationRef: "<integration-branch>",
      sourceBranch: "<feature-branch>",
      strategy: "squash",           // squash | rebase | merge
      taskId: "<taskId>",
      dryRun: false,                // REQUIRED to execute — the action DEFAULTS to dry-run
    })
    

    serialize_merge 默认采用试运行(仅预检,不获取租约):省略 dryRun 时,它会报告合并是否可以执行,但不会修改任何内容。传入 dryRun: false 才会实际获取单写入者租约并执行合并。此操作声明为 共享变更型,因此只读调用方(不具备写入能力的会话)即使在应用变更时也会被拒绝;这种情况下,请从主工作树使用本地 Git 执行合并(执行 git merge --squash <feature-branch>,然后提交),并自行记录等效的合并状态和事件,因为该合并不受序列化租约约束。

    此时预检应该会通过。继续执行编排器的常规合并流程。(只有在非集成合并时,或作为崩溃恢复后的调用方重新提交原始 leaseOperationId 时,才直接重新运行原始的 merge_orchestrate。)

回滚流程

如果变基产生了无法安全解决的冲突,或者变基后合并仍然失败:

  1. 将功能分支重置到捕获的回滚 SHA:

    cd <feature-worktree-path>
    git rebase --abort   # if mid-rebase
    git reset --hard "$(cat /tmp/rollback.sha)"
    
  2. 将返工规划为新任务。 该任务已在工作流中完成:它的完成行启动了此次合并。再次认领会返回 already-complete,并且不会再次运行任何门禁。已完成的工作不会重新打开。将新任务添加到计划中,运行 prepare,并为新任务分派修复者(参见上文的“故障恢复”部分)。不要删除工作树——修复者需要原始分支状态来诊断冲突。

  3. 记录此次事件:发送一个 merge.aborted 事件,其中包含 reason: "ancestry-rebase-conflict" 和失败分支在变基前的 SHA,以便收敛视图记录此次回滚。

为什么暂不自动变基

自动变基尚未接入。目前,编排器会有意在祖先关系预检处停止:在分歧的工作树之间进行不完善的自动变基,可能会在不知情的情况下丢弃子 Agent 的工作;而且,上述恢复流程足够简短,因此由操作人员驱动变基比使用巧妙但脆弱的自动化更可取。


转换

批次处理完成且工作树落地后,立即自动继续(无需用户确认):

  1. 在工作流状态中确认所有 tasks[].status === "complete"——批次处理完成后,它们应保持此状态
  2. 转换:exarchos_workflow({ action: "transition", featureId: "<featureId>", target: "review" })
  3. 调用:{{CHAIN next="review" args="<plan-path>"}}

这不是人工检查点——工作流会自主继续。


附录:原始路径(非功能工作流类型)

prepare 会编译功能工作流。当它因 WORKFLOW_TYPE_UNSUPPORTED 而拒绝处理——例如调试或检修委派——时,需按以下顺序手动执行各任务的治理调用:

  1. 就绪检查 — exarchos_orchestrate({ action: "prepare_delegation", featureId: "<featureId>", planPath: "docs/specs/<the-decomposition-spec>.md", repoRoot: "<absolute path of the integration worktree>", tasks: [...] })。它会先自行公布计划中的任务(task.assigned),再读取就绪状态,因此不会有追加内容先于此步骤。传入 planPath,以提取每个任务的 **Risk Tier:** / **Boundary Touching:** 标记;若 ready: false,则停止此轮。将 repoRoot 设为绝对路径:分支读取、受保护分支检查、祖先关系预检、stash 探测以及相对路径的 planPath 都会以该路径对应的工作树为准。若不传入 repoRoot,它会读取服务所在目录并返回警告。它会返回 implementerPromptTemplate、以 "<riskTier>|<boundaryTouching>" 为键的 verificationNotes 映射,以及 taskClassifications[i].verificationNoteKey——派发前,将任务对应的说明插入模板。它还会返回 baseBranch,即任务分出的集成分支:请记录下来,供第 3 步使用。
  2. 派发并收集 — 按步骤 2 和步骤 3 执行,并以说明替换胶囊中的术语。
  3. 每个已完成的任务,运行任务完成操作手册:exarchos_orchestrate({ action: "runbook", id: "task-completion" }),并按顺序执行返回的步骤。门禁失败时停止。将 <baseRef> 模板变量绑定到第 1 步中记录的 baseBranch:没有此值时,终止探测会因 base-missing 而阻止操作。将 <taskId> 和 <worktreePath> 绑定到对应任务:check_static_analysis 会在该任务的工作树中逐个运行,并使用 taskId 和 repoRoot;task_complete 仅接受同一任务、在 result.worktreePath 指定的工作树上、当前提交中通过的运行结果。若运行时传入 taskId 但未传入 repoRoot,则不会扫描任何内容(repo-root-missing)。如果操作手册不可用,请使用 describe 获取门禁架构:exarchos_orchestrate({ action: "describe", actions: ["check_test_adequacy", "check_static_analysis", "task_complete"] })。其终端步骤会记录完成状态及报告来源:
exarchos_orchestrate({
  action: "task_complete",
  taskId: "<taskId>",
  streamId: "<featureId>",
  result: {
    summary: "<task summary>",
    worktreePath: "<absolute worktree path of the task>",
    implements: ["DR-1", "DR-3"],
    tests: [{ name: "testName", file: "path/to/test.ts" }],
    files: ["path/to/impl.ts", "path/to/test.ts"]
  }
})
  1. 门禁失败时,派发修复者(见上文“修复失败任务”),然后运行 task-fix 操作手册:exarchos_orchestrate({ action: "runbook", id: "task-fix" })。
  2. 合并并转换 — task_complete 已在工作流状态中将每个通过的任务标记为完成,因此不要手动写入 tasks[].status。按步骤 4 执行合并、后备处理和转换。

参考资料

文档用途
references/implementer-prompt.md实现任务的完整提示词模板
references/fixer-prompt.md采用对抗式验证立场的修复 Agent 提示词
references/worked-example.md包含恢复路径(R1)的完整委派追踪
references/rationalization-refutation.md常见的自我合理化说辞及反驳(R2)

| references/agent-teams-saga.md | 包含事件负载的 6 步 Agent 团队历程 |

| references/parallel-strategy.md | 并行分组和模型选择 | | references/testing-patterns.md | Arrange/Act/Assert、命名和模拟约定 | | references/pbt-patterns.md | 基于属性的测试模式 | | references/fix-mode.md | 修复模式的详细流程 | | references/state-management.md | 状态模式和基准标注 | | references/troubleshooting.md | 常见故障模式及解决方法 | | references/adaptive-orchestration.md | 自适应团队组成 | | references/workflow-steps.md | 跨平台逐步委派参考 | | references/worktree-enforcement.md | 工作树隔离规则 |

评论

支持 Markdown