关于 aep-dispatch
aep-dispatch 是一项交互式 Agent 技能,可将产品故事送入功能开发流程。它同步工作区状态、处理依赖并为可执行故事评分,随后组装 OpenSpec 上下文并交接给设计或启动步骤。
主要功能
- 01从工作区信号同步故事状态
- 02处理依赖并判断就绪状态
- 03为就绪故事评分排序
- 04创建含上下文包的 OpenSpec 变更
- 05将故事交接至设计或启动步骤
适用场景
- 01选择下一项待开发的产品故事
- 02在 WIP 限制内分派就绪故事
- 03为 Agent 准备实现上下文
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ memorysaver/ agentic-engineering-patterns --skill aep-dispatch安装后在 Claude Code 中输入/aep-dispatch确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/.aep-generatedcontext-assembly.mdfile-resolution.mdscoring.mdworkflow-mode.mdyaml-guardrails.md详细介绍
Dispatch
连接产品上下文(控制平面)与功能生命周期(执行平面)。同步工作区状态、评估 Story、选择下一步构建内容、组装上下文,并转交给 /aep-design 或 /aep-launch。
适用场景:
/aep-envision → /aep-map → /aep-model (UI-facing) → /aep-scaffold
→ [ /aep-dispatch → /aep-design → /aep-launch → /aep-build → /aep-wrap ]
▲ you are here
→ /aep-reflect → loop
会话: Main,交互式
输入: 来自 product/index.yaml(拆分模式)或 product-context.yaml(v1 模式)的产品定义;来自 product-context.yaml 的运行状态
输出: 预先组装好上下文的 OpenSpec 变更、已更新的 Story 状态,以及转交给 /aep-design 或 /aep-launch
用于自主编排: 请改用
/aep-autopilot。Autopilot 通过/loop,以基于 tick 的状态机运行完整的 dispatch-launch-monitor-review-wrap-dispatch 循环。Dispatch 仍是单次交互式工具。在 Claude Code 下实现免操作批处理: 使用“with workflow”分派一个波次,将整个波次构建为一个动态工作流(Step 5 → Dynamic Workflow)。
开始之前
探查产品上下文所处的模式:
ls product/index.yaml 2>/dev/null && echo "SPLIT MODE" || echo "V1 MODE"
cat product-context.yaml
模式语义以 references/file-resolution.md 中的定义为准。Dispatch 从 product/index.yaml(拆分模式)或 product-context.yaml(v1 模式)读取产品定义;始终从 product-context.yaml 读取/写入运行状态(Story、拓扑、架构、成本、变更日志)。
如果 product-context.yaml 不存在,请先运行 /aep-envision,然后运行 /aep-map。如果 stories 部分为空,请运行 /aep-map 来拆解产品。
Dispatch 协议
每次 dispatch 运行都遵循相同的 7 步协议。每一步都是幂等的——如果状态没有变化,连续运行两次 /aep-dispatch 会产生相同结果。Story 状态(pending / ready / blocked / in_progress / in_review / completed / failed / deferred)遵循 product-context 架构定义。
① SYNC signals → bring YAML up to date with workspace reality
② CASCADE states → compute all pending→ready, pending→blocked transitions
③ SCORE stories → rank the ready queue by dispatch_score
④ PRESENT queue → show user the scored dispatch queue
⑤ DISPATCH → lock stories (status→in_progress), create OpenSpec changes
⑥ MONITOR → agents work, main session watches signals
⑦ COMPLETE → /aep-wrap updates YAML, atomic cascade, re-invoke dispatch
Step 1:信号同步
在计算任何内容之前,先将工作区信号同步到 YAML 中——过时的 YAML 会将已完成的 Story 显示为 in_progress,并在下游 Story 实际已就绪时仍将其保留为 pending。
对于状态为 in_progress 或 in_review 的每个 Story,读取
.feature-workspaces/<story.assigned_to>/.dev-workflow/signals/status.json,并将记录复制
到该 Story 中:signal.story_status → story.status;当状态为 completed 时,还需复制
completed_at / pr_url / cost_usd;当状态为 in_review 时,复制 pr_url;当状态为
failed 时,将 failure_log 追加到 story.failure_logs。如果 Story 的信号文件不存在,则保持
原样。信号结构以 /aep-launch → references/signals-spec.md 中的定义为准。
后置条件: 每个状态为 in_progress/in_review 的 Story,其 YAML 状态都与信号文件一致。
Step 2:级联状态转换
同步完所有信号后,一次性计算所有状态转换:
For each story with status: pending:
If any story in dependencies[] has status: failed:
Transition → blocked
Elif any story in dependencies[] has status: deferred:
Transition → blocked (dependency deferred)
Elif all stories in dependencies[] have status: completed:
Transition → ready
For each story with status: blocked:
If the blocking dependency is now completed:
Transition → pending (will be re-evaluated in this same pass)
这是依赖门控:只有当某个 Story 的所有依赖均为 completed 时,它才会变为 ready,因此依赖未满足的 Story 永远不会被分派。
恢复转换(由用户发起,按需处理):
failed → pending— 用户修复规格后重置deferred → pending— 用户取消对 Story 的延期
所有更新完成后,验证 YAML:
npx js-yaml product-context.yaml > /dev/null && echo "YAML OK"
如果验证失败,请在继续之前修复 YAML(常见修复方法见 references/yaml-guardrails.md)。
在计算分数之前,将同步并级联后的状态提交到 YAML,并递增 dispatch_epoch。
后置条件: npx js-yaml 以 0 退出,且级联后的状态已提交。
Step 3:评估 Story
确定活动层
For each layer (0, 1, 2, ...):
If any story in this layer has status not in [completed, deferred]:
This is the active layer. Stop.
层级门控检查: 如果活动层 > 0,请验证 layer_gates[active_layer - 1].status == passed。如果不满足,则阻止继续并建议运行层级门控。状态为 scripted_passed 的门控(Tier-1 机制正常,但旅程 dogfood / 覆盖率部分尚未完成)不会解锁下一层——请报告为“机制正常,dogfood 待完成”,以便用户了解剩余部分。只有 /aep-wrap 的两阶段切换会将门控推进到 passed。
筛选就绪队列
仅调度活动层中处于 ready 状态且与进行中的工作没有文件级冲突的故事:
For each ready story:
For each in_progress story:
If files_affected intersection is non-empty:
Mark as conflicted — cannot dispatch until the in_progress story completes
计算评分
对于每个剩余的就绪故事,根据 references/scoring.md 计算 readiness_score 和 dispatch_score,并将两者写入故事 YAML:
readiness_score(0–1)= 规格完整度;用于确定步骤 7 的路由。dispatch_score=(业务价值 + 解锁潜力 + 关键路径紧迫性 + 复用价值)/(复杂度成本 + 模糊性惩罚 + 接口风险);用于对队列排序。
分组变更(共享同一 change_group 的 compile_mode: grouped_change)作为一个单元评分和调度——参见 references/scoring.md → Grouped Change Dispatch。
后置条件: 每个就绪故事的 YAML 中都写入了 readiness_score 和 dispatch_score。
步骤 4:展示调度队列
展示按顺序排列的队列及其上下文。突出显示排名第一的故事并说明原因(最高评分 = 关键路径 + 高价值 + 解锁最多)。每个故事占一行,并附上冲突 / 阻塞 / 进行中部分:
Dispatch Queue (Layer 0 — 4 ready, 2 in_progress, WIP 3/5)
1. ★ PROJ-003 "Setup auth middleware" score: 14.5
[high] S | Module: auth | Wave 1 | Critical path | Shared enabler
Unblocks: PROJ-005, PROJ-007, PROJ-008
→ Readiness: 0.9 — skip to /aep-launch
Conflicted (waiting): • PROJ-006 — files overlap with in_progress PROJ-002
Blocked (deps unmet): • PROJ-008 — waiting on PROJ-003 (auth middleware)
In progress: • PROJ-001 (tab: feat-api-scaffold) — Phase 4, 60%
步骤 5:调度
调度模式
- 交互模式(默认) — 用户一次选择一个故事。适合早期层,或用于熟悉系统。
- 波次批处理(
--batch wave) — 一次调度当前波次中的所有就绪故事(不超过 WIP 限制),通过/aep-launch创建 N 个工作区。 - 动态工作流(
--batch wave+ “...with workflow”) — 当宿主是带有 Workflow 工具的 Claude Code 且用户要求使用工作流时,通过工作流模式调度批次(一个动态工作流,每个锁定的故事对应一个 Agent),而不是创建 N 个/aep-launch工作进程。阅读references/workflow-mode.md:其中包含机器组装的 STEP-0 简报要求(用于避免基准过时风险),以及绕过/aep-launch时调度流程必须发布的模式声明。
WIP 限制
max_wip = topology.routing.concurrency_limit (default: 5)
current_wip = count of stories with status: in_progress
available_slots = max_wip - current_wip
最多调度 available_slots 个故事——此上限适用于所有模式,包括动态工作流。available_slots 用于保护集成 / 合并瓶颈(通常是人工 PR 审查,而非 Agent 速度):根据利特尔法则,Lead Time = WIP / Throughput,因此超出容量调度只会造成拥堵,而不会提升速度。
门控条件: 当 available_slots > 0 时继续调度;为零时,WIP 限制就是答案。
调度锁
对每个选定的故事,按原子方式进行调度:
1. Re-read story.status from YAML (not from cache)
2. If status != ready → SKIP (already dispatched by another run)
3. Write to YAML:
status: in_progress
assigned_to: <workspace-name>
openspec_change: <story-id>
started_at: <ISO 8601 now>
dispatched_at_epoch: <current dispatch_epoch>
4. Commit YAML immediately (this IS the lock)
5. THEN create OpenSpec change and workspace
提交发生在创建工作区之前,因此第二次运行是安全的:运行 1 写入 in_progress 并提交;运行 2 读取到 in_progress 后跳过。
机械顺序不变量 [lock-before-workspace]。 扩展项目规模的调度流程会将此顺序置于类型化门控之后——该门控通过名称拒绝
[story-not-ready]/[dependencies-completed]。参见aep-autopilotreferences/deterministic-orchestration.md。
步骤 6:创建包含上下文包的 OpenSpec 变更
对于每个已分派的故事,创建 OpenSpec 变更 openspec/changes/<story-id>/,包含 proposal.md、design.md、specs/<module>.md、tasks.md 和 .context/ 包(stable-prefix.md、dependencies.md、retrieval.md)。即使故事的规格已经很完善,也始终创建 OpenSpec 变更——Agent 读取的是 .context/ 目录。
按照 references/context-assembly.md 组装交接包,并根据拓扑中的角色令牌预算进行精简。该包附带故事的暂定验证等级(推导方式见 context-assembly.md);最终生效的重新推导由构建阶段负责——/aep-build 在第 5 阶段开始时根据实际差异重新推导,且等级只会上调。
**组装阶段阻止分派的关卡:**经过校准的故事(设置了 calibration_type,或包含 .5 对齐层——概念定义以 /aep-map 中的 references/alignment-layers.md 为准)要求 calibration/<type>.yaml 存在,否则转至 /aep-calibrate。面向 UI 的故事(object_model_refs、calibration_type 属于 {visual-design, ux-flow},或属于 ui 类型模块)要求存在涵盖该故事且状态为 approved 的 Object Map,否则转至 /aep-model。两个关卡的详细说明见 references/context-assembly.md;如果任一关卡未通过,请勿分派。
**后置条件:**每个已分派故事的 openspec/changes/<story-id>/.context/ 均已存在。
交接前提交并推送
在移交给 /aep-launch 之前,将所有分派产物(YAML 更新、OpenSpec 变更、变更日志)推送到远程:仅保留在本地的分派提交会在工作区 PR 合并到集成分支并执行变基时丢失。
追加到 changelog 部分:
- date: <today>
type: dispatch
author: human
summary: "Dispatched PROJ-003 (auth middleware), PROJ-004 (user model) — Layer 0, Wave 1"
sections_changed: [stories]
然后按照 /aep-git-ref 中的 “Control-Plane Commits” 执行提交和推送:git add product-context.yaml openspec/changes/,提交(feat: dispatch <ids> — Layer N Wave M),然后推送到 $BASE(按照 /aep-git-ref 中的 “Resolving $BASE” 解析 $BASE)。
**后置条件:**分派提交已存在于 origin/$BASE 上——若推送失败(远程冲突),请在启动工作区之前解决冲突。
步骤 7:移交
**启动模式通常在
/aep-launch确定,而非在此处确定。**默认 路径中的分派与执行器无关——它会将规格完善的变更移交给/aep-launch,由其检测宿主环境,并通过aep-executor选择模式。 **唯一例外是选择加入的 Dynamic Workflow(步骤 5):**该路径从分派阶段起就以 workflow 模式运行,绕过/aep-launch,因此在此情况下由分派本身负责 模式选择和公告。
根据步骤 3 中计算的 readiness_score 区间进行路由。区间定义以 references/scoring.md § Routing Thresholds 为准;本节仅规定交互操作:
- dispatch-ready → 跳转至
/aep-launch - borderline → 向用户提供
/aep-launch与/aep-design之间的选择 - under-specified → 转至
/aep-design
Full-auto / auto-design 路由(准备度中等或偏低)
边界或规格不足的故事如何路由,取决于两个 topology.routing 标志——full_auto 主开关(默认 false)和更细粒度的 auto_design(默认 false)。full_auto 的优先级高于 auto_design:
full_auto: true 表示 auto_design: true。
full_auto: true或auto_design: true→ 使用非交互式 gen/eval 设计解析器处理故事(由设计 Agent 在没有人工参与的情况下完善规格,然后路由至/aep-launch),而不是升级到交互式/aep-design。不设置策略暂停点。full_auto: false且auto_design: false(默认) → 路由至交互式/aep-design,由人工在启动前完善设计。战略性的“要构建什么”关卡仍由人工把控。
单故事交接示例:
Story PROJ-003 dispatched (score: 14.5, critical path, shared enabler).
OpenSpec change: openspec/changes/PROJ-003/ Context: .../.context/
Recommendation: Readiness 0.9 — well-specified → /aep-launch
/aep-launch ← start building immediately
/aep-design ← refine the spec first
批量交接
对于批量分派,通过 /aep-launch 创建所有工作区:
Batch dispatched: PROJ-003 (score 23.0), PROJ-004 (score 12.0)
/aep-launch PROJ-003 → tab: auth-middleware
/aep-launch PROJ-004 → tab: user-model
边缘情况
- 没有可开始的故事: 所有待处理故事的依赖都尚未满足。检查是否有卡住的
in_progress故事(attempt_count较高、started_at较早)。建议检查工作区进度或运行/aep-reflect。 - 当前层中的所有故事均已完成: 触发层级门禁测试。若测试通过,则推进到下一层并重新运行调度。
- 所有层中的所有故事均已完成: 产品已完成。建议运行
/aep-reflect进行最终审核。 - 层级门禁测试失败: 根据失败情况创建修复故事,将其添加到当前层,然后重新运行调度——门禁通过前,该层将保持开放状态。
- 已达到 WIP 限制: 没有可用名额。显示正在进行的事项,并建议等待或审核 PR 以释放名额。