mcpField
D
dispatch-agent

dispatch-agent

github.com/davidleeAgent 工作流284 次安装3 天前更新
代码仓库

关于 dispatch-agent

dispatch-agent 是面向 Claude arm 的技能,用于启动隔离的 dispatch worker,并指导其受控提交、导入、验证和清理流程。它适合运行 Doctrine dispatch 工作流的协调者。

主要功能

  1. 01在指定基线上创建 worker 分支
  2. 02执行生成前与 worker 安全检查
  3. 03指导 worker 通过 worker_commit 自行提交
  4. 04导入、验证、结束阶段并回收分支
  5. 05说明实时 worktree 备用流程

适用场景

  1. 01为文件互不重叠的任务启动并行 worker
  2. 02将 worker 已提交的更改合入协调树
  3. 03主路径不可用时恢复 worker 未提交的更改

MCP 相关

该技能要求 worker 通过 worker_commit MCP 工具提交,并指导协调者使用 dispatch_import、dispatch_conclude_phase 和 dispatch_reap MCP 工具。

安装

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

$npx skills add https://github.com/davidlee/doctrine --skill dispatch-agent

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

详细介绍

Dispatch — claude arm

通过 Agent 工具生成工作者。与 harness 完全相同的漏斗和驱动循环位于 /dispatch router 中——此技能是生成模板,以及此分支的落地机制。

生成前 — 启用基础版本,切换到生成目录

工作者的工作树由 doctrine 的 WorktreeCreate hook (doctrine worktree create-fork)创建,而不是由 harness 原生创建。该 hook 通过位置判断是否为 dispatch 工作者:仅当 Agent 载荷的 cwd 是启用目录 <coord>/.doctrine/state/dispatch/spawn/ 时,生成的才是 dispatch 工作者。它分出的基础版本是显式指定的——该目录中的 base 文件——绝不会使用 cwd HEAD。cwd 是判断条件,不是基础版本来源。

启用有双重作用:该 hook 还会为工作者配置其 DispatchRecord——注册信息 worker_commit 会据此解析工作者的不透明 agent id。未启用的生成会作为正常工作树直接通过,不会创建记录,因此其 worker_commit 会拒绝 unknown-agent,也就完全无法落地分支提交。

基础版本清洁检查(在 arm-spawn 之前)。 在启用/生成之前,以及在分出分支前于 main 上,确认基础版本已通过证明检查——doctrine check prove(非变更型 fmt-check + lint)。基础版本出现 RED 属于 BASE 缺陷(由操作员格式化并提交/准备工作树),绝不能并入工作者的变更,绝不能自动修复。这与漏斗中记录的生成前检查相同;每批运行一次即可。

每次生成(或并行批次)之前:

  1. doctrine dispatch arm-spawn --base <B> --slice <N> --phase PHASE-NN——写入 <coord>/.doctrine/state/dispatch/spawn/base = <B> 以及两个分支绑定槽位,并打印生成目录的绝对路径。支持幂等操作:在 B′ 重新启用会重写全部三个值。两个绑定部分都必须提供——只提供一半不会绑定任何内容,且会在启用时被拒绝(half-arm:);两部分都不提供则会被接受,但会发出警告,并导致分支的 worker_commit 在交接时以 unprovable-fork 拒绝——整个工作者轮次都将白费。
  2. cd 进入该生成目录。这是启用信号——只有载荷 cwd 位于生成目录时,hook 才会在 B 处分支。
  3. 发出 Agent 生成请求(见下文)。文件互不重叠的并行批次:启用一次,然后从生成目录发出 N 个生成请求——它们读取相同的 B;每个 hook 根据各自的 name 推导自己的 branch/dir。
  4. 生成请求发出后,cd 返回协调根目录——按位置解除启用。从协调根目录发出的正常 isolation:worktree 生成请求会直接通过(会配置,但不会分支为工作者);只有从生成目录内部发出的生成请求才是 dispatch 工作者。遗留的 base 文件不会产生影响——触发条件是 cwd 的位置,而非文件是否存在。

**串行驱动:**每个阶段都重新启用——在 B 处启用,切换进入目录,生成,再切换返回;漏斗提交会推进协调 HEAD;下一阶段在 B′ 处启用。基础版本是显式指定的,因此启用与创建之间协调 HEAD 的漂移无关。默认 cwd 是协调根目录;只有发出工作者生成请求时才切换到生成目录。

**位置前提(ISS-031):**协调工作树(因此也包括其启用目录)必须位于项目根目录内——约定使用 .dispatch/SL-<n>(dispatch setup --dir .dispatch/SL-<n>)。在 cwd 受限的隔离环境中(以 /workspace/<repo> 为根的 bubblewrap),切换到外部同级目录后,下一次 Bash 调用会静默地返回项目根目录。若 --dir 解析到根目录之外,dispatch setup 会在 claude arm 上拒绝执行。请在单独的 Bash 调用中执行不带其他命令的 cd <spawn-dir> ; pwd,确认位置无误后再继续。

Spawn

基础防护 — 必须先运行,然后才能进行任何读取、编辑或提交。如果任何检查失败,立即停止且不写入任何内容:

  1. git status --porcelain → 必须为空(工作树干净)
  2. git rev-parse --git-dir vs --git-common-dir → 必须不同(隔离的链接工作树,而非主工作树)
  3. git merge-base --is-ancestor HEAD → 必须退出 0(HEAD 是从基线 派生的)
  4. grep prerequisite seams: → 必须存在 任何检查失败时:立即停止,不得创作或提交任何内容,并报告 "base-guard-failed: "。

检查 #2 是编排器的 not-isolated 防护带在工作器内的镜像 — 如果工作器的 git-dir 等于 git-common-dir,就不是隔离的工作树。

subagent_type: dispatch-worker
isolation: worktree
prompt: <pre-distilled worker prompt, including the base-guard block above>

提示词 MUST instruct the self-commit:最后调用 worker_commit MCP 工具,并提供工作器自己的工作树名称(绝不能是路径) 以及提交消息,然后在结构化交接中报告返回的 oid(fork_tip)。在隔离环境中,原始 git commit 会失败(.git 只读) — worker_commit 是工作器唯一的提交途径。遇到 Refused 结果时,工作器必须原样报告原因并停止;绝不能绕过 forbidden-zone/commit-gate-red 拒绝后重试。

Spawn 后的流程 — 工作器自行提交,编排器落地

主要路径(B):工作器的增量会作为一个已提交的非合并提交 C (C^ == B)出现在它自己的 dispatch/<agent> 分支上,由受门控的 worker_commit 工具在服务器端落地(防护带是安全边界:非空增量 → forbidden-zone 范围检查 → HEAD == B → check commit 门控)。因此,该增量是 分支持久的 — 它会在工作树之外保留,恢复/修复时会从已提交的最新提交继续。

排序由 oracle 负责,不是你。 doctrine dispatch next --slice <N> 会指定当前应执行的一个操作;路由器会说明循环流程。以下内容是此路径上各项指令的 具体操作方式,不是一套固定执行顺序。

到达(在流程能够看到增量之前)。

  • **页脚。**读取 Agent 返回页脚中的 worktreePath:。 没有页脚/没有 worktreePath: ⇒ 未创建隔离树(钩子中止或 回退到主工作树)⇒ 中止,不要进入流程。重新分派,或者如果钩子持续失败, 切换到子进程路径。
  • **身份。**从 worktreePath 推导(规范数据,已实时验证): name = basename(worktreePath),branch = dispatch/<name>。不要读取 页脚的 worktreeBranch 字段 — 对于钩子创建的树,它是 undefined。
  • 验证工作器。doctrine worktree verify-worker --base <B> --dir <worktreePath> --branch <branch> 任何拒绝均须中止:no-worker-head / not-isolated / unstamped / wrong-base / branch-mismatch。它接受提交后的 HEAD(测试 merge-base --is-ancestor B HEAD,即后代 — 而非 HEAD == B);--branch 将目录与分支绑定,使两条防护带验证同一个工作器状态。

import — dispatch_import{slice, name: <branch>}(MCP;next 会生成 此调用)。按切片在服务器端解析 coord 树,运行 classify_import 范围防护带,作为硬性合成前门控(拒绝 .doctrine//.claude/, 拒绝未声明范围 — 遇到拒绝时不会落地任何内容),通过 merge-tree 合成 coord-tip ⊕ worker-tip(仅操作对象数据库,不涉及工作树),并落地一个非合并提交, 保留工作器的作者信息。导入和提交合并为一步 — 没有单独的编排器提交步骤。任何 Refused{reason} ⇒ 报告并停止 (merge-conflict、head-moved、undeclared-scope 等绝不会自动解决)。 该增量已通过提交门控(worker_commit 已运行门控),因此此路径无需单独运行导入后的证明。

verify — doctrine dispatch verify --slice <N> --phase PHASE-NN(CLI)。 在协调工作树中运行阶段套件,并落地通过/失败证据; 失败证据会使下一项指令变为 triage-verify-failure。 conclude — dispatch_conclude_phase{slice, phase, code_start, code_end} (MCP;next 会根据漏斗行将其完整参数化)。一次调用,两个层级:将被 git 忽略的阶段表切换为 completed,并写入已提交的 (code_start, code_end) 边界行(按阶段执行 UPSERT,不依赖工作树)。此切换会同时作用于 coord 表(下一阶段就绪状态的权威来源)和 PRIMARY 表(树的 prepare-review 完整性门槛从中读取已完成阶段集合)——无需手动再执行 slice phase --status completed -p <primary>。coord→primary 镜像由单一写入器 set_phase_status(ISS-212)实现,因此并非 conclude 专属:在 dispatch/<slice> 工作树仍存在时,coord 树中任何 completed 切换都会向下镜像,无论是通过此工具还是原始的 slice phase --status 完成。重试时具有幂等性;唯一的故障结果是表已切换但边界尚未提交,重试即可重新组合。

reap — dispatch_reap{slice, name: <branch>}(MCP)。运行 patch-id 已落地判定器(git cherry):若分叉的补丁不在 coord 历史记录中,则拒绝操作;否则移除已落地分叉的工作树和分支。只能通过此判定器执行 reap——绝不要对尚未导入的树直接运行 git worktree remove --force(这会删除未落地增量的唯一副本;工具的拒绝机制正是原始 remove 所缺少的保护)。

回退方案(A)——导入活动工作树

主路径无法运行时的应急方案:MCP 服务已关闭,或 Worker 从未完成配置(worker_commit → unknown-agent),因此不存在分叉提交。Worker 尚未提交的增量仍位于工作树中,并会在 Agent 返回后继续保留(没有 WorktreeRemove 钩子——运行框架不会自动执行 reap)。这不是绕过流程:若因 forbidden-zone / commit-gate-red / undeclared-scope 被拒绝,说明 Worker 增量存在缺陷——应修正或停止,绝不可绕过检查直接导入。

  1. 按上述方式执行 verify-worker(此模式下 HEAD == B——没有提交)。
  2. doctrine worktree import --base <B> --from-worktree <worktreePath> --slice <N> — 收集当前已跟踪和未跟踪的增量,运行相同的 classify_import 防护流程,将其应用到 B 但不提交,然后在进程内运行拒绝并停止的证明门槛(未格式化或 lint 未通过的增量会以暂存状态停止,绝不会自动修复)。
  3. 自行在协调分支上创建一个提交,然后记录边界: doctrine dispatch record-boundary --slice <N> --phase PHASE-NN --code-start <B> --code-end <B+1>。
  4. 只有在增量已落地后才执行 reap——在此路径下,协调提交落地之前,工作树是唯一副本;移除操作必须用 && 串接在提交之后。

这也是 pi/子进程分支唯一可用的模式——受 bwrap 限制的 Worker 完全无法提交(/dispatch-subprocess)。绝不要要求或期待 claude 分支自行提交。

Worker 隔离(SL-182)

claude worker 受两个已安装的 PreToolUse 钩子约束(插件 hooks.json → doctrine worktree pretooluse):Bash 会被不透明地重写为嵌套的 bwrap 沙箱(工作树可读写,其他所有内容只读);工作树外的 Edit|Write 会被拒绝。编排器(没有 agent_id)不受限制。 隔离由构造保证——不依赖 worker 配合设置标志。worker_commit 是刻意设置的、用途单一的绕过通道:不受隔离的服务 代表 worker 提交,而该工具的防护机制——而非隔离墙——构成了此处的安全边界。

  • 不会热重载。 插件 hooks/ 的更改仅在会话开始时加载 (docs/claude/plugins-reference.md:394)。运行 doctrine install(或编辑任何钩子)后,使用 /reload-plugins(更轻量)或重启会话来加载更改——否则生效的仍是旧钩子(或没有钩子)。
  • 安装时默认拒绝。 安装的命令是已解析的绝对 可执行文件路径,并带有 || exit 2 保护,因此二进制文件缺失或过时会拒绝执行,而不是不受隔离地运行工具(PreToolUse 在其他情况下会默认放行——只有退出码 2 才会阻止)。
  • 逃生通道。 有问题的 Bash 包装器可能会让你无法使用 Bash,但 Edit/Write 不受 Bash 限制:使用 Edit 禁用有问题的钩子,然后运行 /reload-plugins。

危险信号

绝不可: 未先运行 arm-spawn 并 cd 进入 spawn 目录就启动(从 coord 根目录启动只会无害地透传,绝不会成为派发 worker——且其 worker_commit 会拒绝 unknown-agent);读取页脚的 worktreeBranch(对于钩子创建的树,该值未定义——应改为推导 branch = dispatch/basename(worktreePath));将未返回 worktreePath: 页脚的 worker 导入漏斗;存在 fork 提交时导入活动树(差异就是该提交——通过 dispatch_import 落地);使用回退方案 (A) 绕过 worker_commit/dispatch_import 的拒绝(拒绝意味着存在缺陷或应停止,绝不是绕行);对尚未落地的树直接运行 git worktree remove --force(通过 dispatch_reap 的 patch-id 判定器回收);声称在 pi arm 上自行提交;将 dispatch setup --dir 指向根目录外的同级目录(ISS-031);使用 subagent_type 不是 dispatch-worker 的方式启动;在这里运行 fork 或 bwrap(应使用 /dispatch-subprocess);声称可以并行落地(v1 每个 base 只落地一个);凭记忆手动串联落地命令,或手动从 git 状态推断漏斗状态(应询问 doctrine dispatch next --slice <N>)。 务必: 运行 arm-spawn --base B --slice N --phase PHASE-NN(两个绑定部分都要提供,不能只提供一个),然后在启动前 cd 进入 spawn 目录,启动后 cd 回 coord 根目录;将 subagent_type 固定为 dispatch-worker;在提炼后的 worker 提示词中加入 base-guard 区块和 worker_commit 自行提交指令;从 worktreePath 推导 branch;落地前运行 verify-worker;只做 dispatch next 指示的一件事,然后再次询问;返回路由器遵循驱动节奏。

评论

支持 Markdown