mcpField
O
objectstack-pm-dispatch

objectstack-pm-dispatch

github.com/objectstack-aiAgent 工作流7647 次安装今天更新
代码仓库

关于 objectstack-pm-dispatch

objectstack-pm-dispatch 是面向项目维护者的多 Agent 交付技能;它从 GitHub 待办中筛选和分派工作,由开发 Agent 实施,再审查结果。项目约定从仓库自身的规范文件读取,状态保存在 GitHub,便于从新会话恢复。

主要功能

  1. 01从 GitHub 待办筛选并分类事项
  2. 02认领事项并分派开发 Agent
  3. 03支持多个仓库与批次配置
  4. 04检查依赖、重复事项和过时前提
  5. 05汇总并审查开发 Agent 报告
  6. 06将流程状态保存在 GitHub

适用场景

  1. 01处理带队列标签的未分派问题
  2. 02按仓库路由跨项目变更
  3. 03按依赖顺序安排多仓库工作
  4. 04在新会话中恢复交付流程

MCP 相关

若 CLI 不可用,可使用 GitHub API 或 MCP 工具执行相同的状态流程。它不定义 MCP 服务端接口。

安装

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

$npx skills add https://github.com/objectstack-ai/objectstack --skill objectstack-pm-dispatch

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

附带文件rules/dev-template.md

详细介绍

PM dispatch — 适用于任何项目的多 Agent 交付循环

此技能会将一个会话变成 PM Agent:它绝不会自己编写代码。 它会从 GitHub 待办列表中选择工作,并将每个问题交给一个开发者 Agent,由其返回结构化报告;随后进行审查并合并结果。

选择 → 认领 → 分派 → 收集 → 审查 → 报告 → 下一批

维护者只需在两个环节介入:每批完成后打印的轮次报告,以及在确实 需要人工决策时创建的问题。

此技能不针对任何特定代码库。所有项目特定内容 ——门禁、发布说明产物、分支命名、审查要求——都会从项目自身的约定文件 (AGENTS.md、CLAUDE.md、CONTRIBUTING.md 等)中读取。当此技能与该文件 不一致时,以项目文件为准。


快速开始

1. 安装

npx skills add objectstack-ai/objectstack/skills --skill objectstack-pm-dispatch

(使用 --all 安装整个 ObjectStack 套件时会包含此技能。)

2. 配置——可选。 不配置时,循环会针对当前 仓库运行:它既是唯一分片,也是待办列表。只有在你有多个仓库、 单独的待办列表仓库,或想要使用不同默认值时,才添加 .claude/pm-dispatch.json。

3. 运行

/pm-dispatch                 # drain the pm:queue backlog, 3 agents at a time
/pm-dispatch batch:5         # wider batch
/pm-dispatch #<n> #<n>       # two named issues, nothing else
/pm-dispatch rounds:1        # one round, then stop and report

第一轮会创建所需的标签(幂等),扫描待办列表,并在该批次完成后打印轮次报告。


配置

循环会从会话启动所在的仓库中读取 .claude/pm-dispatch.json。此文件为可选项。 每个键都有默认值,因此单仓库项目无需任何配置即可运行。

{
  "backlogRepo": "acme/hotcrm",
  "repos": ["acme/hotcrm", "acme/hotcrm-web"],
  "batch": 3,
  "mode": "subagent",
  "conventionsFile": "AGENTS.md",
  "routingLabelPrefix": "repo:"
}
键类型默认值含义
backlogRepo"owner/name"当前仓库作为队列的唯一问题所在仓库。所有调度权限都归它所有。
reposstring[][backlogRepo]工作可能合并到的所有仓库。用于设置标签和验证路由标签。
batchnumber3同时运行的开发者 Agent 数量上限。
mode"subagent" | "cloud""subagent"分派后端——见分派后端。
conventionsFilestringAGENTS.md、CLAUDE.md、CONTRIBUTING.md 中首个存在的文件定义门禁、分支规则、发布说明产物、审查政策和能力扩展立场的文件相对于仓库的路径。每次分派都会注入此路径。
routingLabelPrefixstring"repo:"将问题路由到非默认仓库的标签前缀,例如 repo:hotcrm-web。当 repos 只有一个条目时不起作用。

未知键属于错误,而不是提示。 如果文件中包含此表未列出的键,请停止并说明这一点——不要猜测其含义,也不要默默忽略。悄悄丢弃配置中一半声明内容,正是此循环旨在从各处杜绝的问题。

零配置语义。 不存在配置文件时:当前仓库是待办列表和唯一目标仓库,batch 为 3,分派在当前会话中进行,不应用路由标签,并自动检测约定文件(如果这三个文件都不存在,请在第一轮报告中说明——循环仍会运行,但每次分派都会缺少项目门禁)。


参数

/pm-dispatch [args]——自由格式,所有参数均可选。参数仅在本次运行中覆盖配置 文件。

参数含义默认值
label:<name>待办列表筛选标签;label:all = 所有未分配的开放问题pm:queue
repo:<owner/name>要扫描其待办列表的仓库backlogRepo
batch:<n>同时运行的开发者 Agent 数量上限batch
rounds:<n>运行 N 轮后停止直到队列为空
mode:subagent | mode:cloud分派后端mode
#12 #34 …指定问题列表——完全覆盖标签查询—

状态模型 — 所有状态都保存在 GitHub 中,本地没有任何状态

新会话必须能够从零本地状态恢复循环。只能通过以下信号读取和写入状态:

议题上的信号含义
open + queue 标签 + 未分配可供分派
已设置受派人已认领 / 处理中 — 如果受派人不是你,则属于其他 Agent 或人工处理;绝不要动它
标签 pm:dispatched已由此循环分派(认领评论记录了轮次)
标签 needs-user-decision正等待维护者 — 绝不要分派,也不要自动答复
引用了该议题的 open PR已实现,正在审核
带有 Fixes #n 的已合并 PR已完成 — GitHub 会关闭该议题,仅限同一仓库

一次性标签设置(幂等 — 在每个轮次开始时,为 repos 中的每个条目执行一次):

for R in $REPOS; do
  gh label create pm:queue            -R "$R" -c 0e8a16 -d "Ready for the PM dispatch loop" || true
  gh label create pm:dispatched       -R "$R" -c 1d76db -d "Dispatched to a developer agent by /pm-dispatch" || true
  gh label create needs-user-decision -R "$R" -c d93f0b -d "Blocked on a maintainer decision — do not dispatch" || true
done
# Routing labels exist only on the backlog repository, one per non-default target:
gh label create "repo:hotcrm-web" -R "$BACKLOG_REPO" -c fbca04 -d "Lands in hotcrm-web" || true

CLI 不可用时,请使用 GitHub API/MCP 工具代替 gh — 协议相同。

一个项目看板,不要使用第二个跟踪器。 这些标签就是状态机。从 repos 中的每个条目拉取议题和 PR 的 GitHub Project,可让维护者一览全局。PM 不会在 GitHub 之外保留任何跟踪状态 — 这一不变量让循环可恢复,也确保看板如实反映状态。


轮次循环

0. 待办事项清查 — 分类是持续性职责,而非按需任务

维护者不会预先整理待办事项。每一轮(以及每次空闲检查)都要清查符合以下任一条件的所有议题,并逐一分类:

  1. 没有 pm:* / needs-user-decision 标签,也没有任何分类标签 — 即没有任何项目会视为“已路由”的标签(领域、组件、负责团队)。普通规则。
  2. 存在 pm:queue,但缺少分类标签 — 仅限实际使用分类标签的仓库(见注意事项)。
  3. 存在分类标签,但没有队列状态(pm:queue、pm:dispatched、设置中定义的任何其他 pm:* 状态,或 needs-user-decision)。

条件 2 和 3 只处理 updated_at 超过一两分钟的卡片;条件 1 无需此时间限制。

为什么使用析取条件,而不是单一的“无标签”筛选。 路由状态和队列状态是两个独立维度,而恰好只带其中一个的卡片会同时在两种视图中消失 — 无论是谁生成了它,筛选条件本身都必须涵盖这种情况。

⚠️ 对于以缺少某个标签为条件的析取项,只在该标签确实存在的仓库中应用 — 否则该标签在其他仓库中永远不存在,清查本身就会制造噪声。项目原本排除在清查之外的内容(暂停的工作、跟踪议题)仍应排除;暂停卡片的正常状态正是“已分类,但没有队列状态”。

⏳ 时间下限应依据 updated_at,而不是 created_at:清查过程中逐个写入标签时,卡片会在几秒内处于只带部分标签的状态,只有 updated_at 能涵盖这种情况。

  • 自动加入队列(pm:queue) — 有明确位置或复现步骤的具体缺陷;范围明确的工具或门禁修复;恢复不变量方面的发现;仅涉及测试的固定项。无需询问:添加标签后即可分派。
  • 请维护者确认(needs-user-decision) — 设计卡片、功能或契约形式提案、需要评估意愿并安排顺序的多周计划,以及任何涉及已存数据迁移形式或移除已发布功能的事项。该标签本身就是收件箱入口;只有实际开始处理卡片时,才撰写四轴深度分析。
  • 先修复 — 被 GitHub 清理器截断的正文无法分派。评论说明修复要求,然后继续处理其他事项。
1. 获取候选项

列出符合筛选条件的未关闭 issue,排除已分配或带有 needs-user-decision 标签的 issue。符合条件的父 issue 的未关闭子 issue 也属于候选项——它们继承父 issue 的队列归属,无需单独添加标签。

阅读每个候选项的完整正文及其评论。评论中经常会记录已有一半工作已交付;不读评论就派发,会白白耗掉一次完整的 Agent 运行。

每次派发前检查前提是否过时。 Issue 描述的是提交时的仓库状态,而活跃的默认分支变化很快。 派发前,根据近期历史检查其中提到的文件和子系统:

git log --oneline -20 origin/main -- <paths named in the issue>
gh pr list --state merged --search "<the issue's keywords>" --limit 10

从“这还成立吗?”开始的派发只需几分钟。跳过这一步则会耗掉一次 Agent 运行——有时还会为已经解决的问题提交第二个相冲突的修复。

2. 分类——路由是 PM 的职责,绝不是维护者的职责

维护者只需提供 issue 和 pm:queue(或在聊天中说明任务)。不应要求他们知道更改会落在哪个仓库——这通常正是分析要得出的结论。

  • 根据实际代码确定更改落在哪个仓库:将 issue 与 repos 中每个仓库的实际代码进行对照。自行应用 {routingLabelPrefix}<name>;没有路由标签则使用默认(backlog)仓库。尊重人类已经设置的路由标签,不作更改。

  • 跨仓库工作绝不能一次派发。 拆分为一个父 issue,以及每个仓库各一个子 issue;修复契约(schema、API 结构、共享类型)的子 issue 优先处理。下游子 issue 的正文中须有一行 Blocked-by: <owner/repo>#<n>。Blocked-by 所引用的 issue 尚未关闭或合并时,绝不可派发该 issue——在选取时向 GitHub 核实,不要凭记忆判断。

  • 已有子 issue 的父 issue只需在父 issue上添加队列标签。在分类时展开处理:为每个子 issue 分类并确定路由,保留维护者提出的依赖顺序;如果没有明确说明,推断契约优先的顺序,并自行添加 Blocked-by: 行。父 issue 是协调节点——绝不可派发给开发者;它应保持未关闭状态,作为进度视图,并在最后一个子 issue 关闭后通过总结评论关闭。

  • 在 issue 上留下一条评论作为审计记录,让维护者可以轻松否决:“Triage: lands in hotcrm-web; reason: …”。

  • 路由是技术判断——绝不可升级询问“该选哪个仓库?” 如果读过代码后确实无法判断,说明 issue 的描述不完整:应升级讨论底层产品问题(步骤 8),而不是路由问题。

  • 任何内容派发前,先跨仓库去重。 跟进 issue 正文和时间线中的所有跨仓库引用,并在其他仓库中按关键词搜索未关闭的 issue 和 PR(模块名、错误字符串):

    • 发现重复项已认领/PR 正在处理中 → 不要派发;添加 Blocked-by: <repo>#<n> 和一条评论,待其合并后再检查剩余工作;
    • 发现重复项未关闭且无人认领 → 先协调处理:互相链接,将其中一个设为另一个的子 issue(或将其中一个以重复项为由关闭),确保一项工作只有一个派发条目——然后照常加入队列;
    • 发现重复项已完成 → backlog issue 可能已过时:核实还剩哪些工作;若没有剩余工作,建议关闭;
    • 未发现重复项 → 照常派发。

    backlog 仓库是唯一的调度权威——绝不可让两个队列派发同一项工作。

3. 选择批次

最多挑选 batch 个相互独立的问题:同一批次中的任意两个问题都不应可能涉及相同的包、注册表、汇总文件或架构。两个开发者 Agent 编辑同一个共享文件会引发合并竞态,造成的成本高于串行处理。有疑问时,就串行处理——把第二个问题放到下一轮。

优先选择范围小、说明明确的问题。若你无法用一句话说明某个问题的验收标准,就应考虑升级处理(步骤 8),而不是派发。批次独立性也适用于跨仓库:由 Blocked-by 关联或共享同一父项的两个问题,绝不能放在同一批次中。

4. 认领

先认领,再编写代码,才能避免两个 Agent 处理同一个问题。

跨 GitHub 账号时,受派人已经说明了“是谁”。“受派人不是你 → 已有人认领,绝不要碰”就是完整的跨账号协议。

同一账号内(多个会话共享一个身份),受派人只说明“某个 Agent 已认领”——认领评论才标明身份。对于每个选中的问题,在派发前按顺序执行:

  1. 指派该问题给自己,并添加 pm:dispatched。如果自步骤 1 以来该问题已被指派给其他人,则跳过,并将其从批次中移除。

  2. 认领评论,使用固定格式。会话 ID 和分支名称共同构成身份:后续每项产物(工作树、推送、PR)都依托该分支,而会话行则能区分从同一问题派生出同一分支的两个会话。

    Claim: PM loop round N Session: session_<id> Branch: claude/issue-<n>-<slug> Worktree: <repo>-issue-<n>

  3. **竞态检查。**指派操作具有幂等性,因此两个 Agent 都可能“成功”。重新读取评论;如果存在更早的认领评论,且其中的会话 ID 或分支与自己不同,则你已落败——不要碰对方的任何内容,回复说明你将让出该问题,然后另选一个问题。先发评论者获胜。

回读认领评论——GitHub 的正文清理器会就地删除较短的 <…> 片段,反引号也无法保护它们(实测:带代码格式的 HTML 注释回读时完全消失,而正文其余部分完整,且 API 报告成功)。上述格式由占位符组成,其中的身份行会用于竞态检查以及下文的过期认领回收。

  • 将字面尖括号写成 HTML 实体(&lt; / &gt;),或在 < 后加一个空格。代码格式无法提供保护。
  • 写入任何内容承载关键信息的正文后——例如认领评论、带有报告标记的云模式派发提示词、交接说明——都要回读并确认这些片段仍然存在。写入端需要回读,原因与读取端需要读取两次相同:“API 返回了 200”不等于“存储的内容正确”。

开发者 Agent 应尽早推送其分支——远程分支是工作正在进行的最有力证据,也能缩短“已认领”和“PR 已创建”之间的间隔。

**回收过期认领。**如果认领已超过约 24 小时,承诺的分支不存在于远程,且没有 PR,则视为认领已失效:先发表评论询问,再等候另一个时间窗口;若仍无回应,则移除受派人(注明原因),并将问题放回队列。绝不要回收仍有提交的有效分支所对应的认领。

5. 派发

每个问题派给一个 Agent,在后台并行运行;每个 Agent 的提示词前都要附上开发者 Agent 操作模板。如果你的运行框架支持自定义 Agent 类型,就使用一种;如果不支持,则带有该模板的通用 Agent 效果相同——模板才是约定,Agent 类型不是。

填写所有占位符,并粘贴完整的问题正文,绝不能只粘贴摘要:

Your task is issue {backlog_repo}#{n}. The code lands in {target_repo}
(from the issue's {routingLabelPrefix} routing label; the backlog repo when
unlabeled).

ISSUE TITLE: {title}
ISSUE BODY:
{body}

{on rework rounds only:}
PREVIOUS ATTEMPT REVIEW — fix all of these before returning:
{feedback}

--- OPERATING PROCEDURE (binding) ---
{the developer-agent operating template, verbatim}
--- END OPERATING PROCEDURE ---

Non-negotiables for this dispatch:
- Work in {target_repo}: branch claude/issue-{n}-{slug} off origin/{default_branch},
  in a DEDICATED worktree of that repository.
- Deliver a DRAFT PR in {target_repo}.
分发后端

在两种模式下,报告都会发送两次,先发到 GitHub:Agent 将 JSON 作为评论发布到首行是纯文本标记 dev-report 的 issue 上 (绝不能使用 HTML 注释——清理器会将其删除),读回评论,然后将其作为最终消息返回。评论是记录;最终消息是加速通道。即使 Agent 在发送消息途中被终止,也不会丢失任何内容。

mode:subagent(默认)。 PM 自己会话中的子 Agent;报告也会作为每个 Agent 的最终消息返回。优先使用此模式;它更简单。

mode:cloud。 每个 issue 都会成为一个独立会话,拥有自己的容器和全新的克隆,与 PM 会话的生命周期脱钩。当任务需要超出单个容器所能提供的资源或生命周期,或维护者提出要求时,使用此模式。需要你的运行框架中具备会话创建工具;如果没有,请说明这一点,并退回到 mode:subagent。

独立会话无法向 PM 返回消息,因此分发提示词必须完全独立(从零对话上下文开始);issue 上的报告评论是它唯一的通道。

6. 收集

子 Agent 模式: 等待 Agent 返回。不要轮询,也绝不要捏造尚未返回的 Agent 的结果。如果 Agent 意外终止或返回格式错误的输出,则从其 issue 上的 dev-report 评论中读取;若也没有评论,则将其计为 status: "blocked",并附上其原始输出。

云模式: 没有直接返回通道——通过 GitHub 收集。设置一次签入(约 15 分钟);每次唤醒时,检查已分发 issue 中的报告评论和关联 PR,然后静默地重新设置签入,直到本轮每个分发任务都已报告,或某个分发任务静默超过约 2 小时(将其计为 blocked 并继续)。

绝不要将没有报告视为成功。

每次签入都要写成条件,而不是结论——计划文本会在你无法预见的未来送达。 现在设置的签入,会由一个已失去你的上下文的会话读取;届时的世界也已发生变化——即使计时器已取消,消息仍可能送达。两条规则可以避免过时文本造成危害:

  • 每次签入都以“幂等——行动前重新读取状态”开头,且不要包含任何无需重新读取状态就能执行的指令。计时器触发后,平台端不会替你重新检查其前提;将重新读取状态写入文本,是唯一能让过时指令失效的机制。
  • 陈述条件(“如果 X,则 Y”),绝不要陈述结论(“现在执行 Y”)。 条件在送达时可以重新推导;结论则已经丢弃了得出它时所依据的状态。“⇒ 重新分发”“⇒ 判定其不可靠”都是应避免的形式——写下时正确,送达时却未必正确。即使你认为计时器已取消,这一点也同样适用:取消并不能保证消息不会送达。

静默阈值是收集的边界,不是判定 Agent 已死亡。 上面的约 2 小时表示“本轮停止等待”,而不是“Agent 已不在了”:多等一轮只会多花一轮时间,而判定 Agent 已死亡,则可能导致向仍在运行的工作树重复分发。在断定已分发的 Agent 已死亡前,必须满足以下任一条件:直接查询状态确认其已死亡;主机报告会话已停止;或静默时间超过你在自己的项目中测得的完成时间基线(从分发到首次推送分支或 PR,在若干张可比任务卡上测量)。静默时间尚未超过基线,不构成证据。

7. 审查每份报告

你是指定的审查人。对于每份报告,请以 GitHub 为准,而不是报告自己的说法进行核实:

  • PR 确实存在,处于草稿状态,目标分支是默认分支,且其正文引用了 Fixes #{n}。
  • 获取 PR 的变更文件。检查范围:没有明显与问题无关的内容,并且包含项目约定文件要求的所有产物(发布说明/changeset 条目、重新生成生成文件、迁移说明)。
  • 报告中的测试证据展示了实际执行的命令和通过的输出,而非一句空泛的“测试通过”。
  • 差异中的拒绝类测试——即旨在确认错误输入被拒绝的测试——要断言错误的标识信息(其 code 和 status,或项目错误信封中声明的其他字段),而不能只断言抛出了异常。仅断言抛出异常的测试,在任何已经会抛出普通错误的实现中都会通过,而未修复的实现通常正是如此,因此它看似提供了覆盖,却无法检测出它所指出的缺陷。
  • 差异看起来能够满足问题的验收标准。

每个问题的判定:

  • ACCEPT — 在问题中评论并链接 PR,概述已交付的内容。然后按照项目的合并策略推动其合并:如果有合并队列,则在所有检查通过后将 PR 标记为可审查并加入队列(队列会基于当前默认分支重新构建,这是获准的路径);如果没有合并队列,则仅在远程 CI 全部通过后按顺序合并,并且只有在项目允许 PM 合并的情况下才进行合并。
  • REWORK — 提供具体、逐项列出的反馈;填写反馈区块后,将同一问题重新分派(同一诉求,换一个 Agent)。每个问题最多进行 2 轮返工;第三次失败则升级处理。
  • ESCALATE — 参见第 8 步。
8. 将不确定事项升级给维护者

首先应用升级门槛——大多数看起来需要决策的事情其实并不需要。 只有满足以下至少一项时才升级:

  • 各选项在产品语义或公开契约形态上确实存在分歧,且问题、约定文件、项目记录的决策(ADR)和现有代码规范都无法确定答案;
  • 修复需要采取破坏性或难以撤销的操作——例如存储数据迁移方案、删除已发布的功能、强制操作。

其他所有事情都由 PM 决定:做出决定、分派任务,并给维护者一个否决窗口,而不是许可关卡——在问题评论和本轮报告中说明你做了什么决定以及原因;维护者可以叫停,但你无需等待他们答复。

明确列出的非升级类别——立即处理:

  • 恢复不变量的修复。 如果项目已经声明了某项不变量(一个系列使用同一契约版本、声明的内容 = 强制执行的内容、某个门禁必须实际运行其声称要检查的内容),那么发现该不变量遭到破坏时,修复决定本身就已明确。询问“我可以恢复这个不变量吗?”是一种反模式。
  • 技术任务之间的顺序安排和依赖排序。
  • 验证策略——有风险但已决定的变更需要通过哪些回归检查。这是在界定工作范围,而不是做决定。
  • 开发者 Agent 提出的 needs_decision 经审核后属于以上类别:自行给出决定和理由;不要向上转交。

如果确实达到升级门槛:

  1. 先刷新决策卡的前提——写卡之前刷新,再次升级之前也要刷新。 决策卡中陈述的每项前提(某项进行中的变更尚未合并、某项功能尚不存在、某个文件仍保持当前结构)都是有时效的判断:活跃的主分支每天大约会合并十几次甚至更多,而跨仓库的事实每小时都可能变化。发布决策卡之前,立即重新核实每项前提;再次将旧卡提交给维护者之前也要重新核实,然后改写或撤回任何已不再成立的内容。一张搁置了一夜、未曾更新的卡片,其前提未经核实,而不只是仍在等待。 前提过期比没有卡片更糟:维护者依据一个已不存在的情况作出裁决,而卡片上却没有任何内容表明情况已经变化。
  2. 决策应记录在所属问题中——绝不要新建问题。 在该问题下发布分析评论,添加 needs-user-decision,并将问题移出活动队列。该标签是维护者的收件箱(筛选条件为 label:needs-user-decision);维护者答复后,移除标签,问题便会重新进入队列。仅当决策没有自然归属的问题时,才新建一个单独的问题(标题为 [Decision] <one line saying what must be decided>,并添加相同标签)——也就是说,该决策涉及多个问题,或是在没有对应问题的情况下出现。
  3. 撰写分析时应包含:背景、确切的问题、各个选项、你的建议,以及相关的问题 / PR / 分支——并根据以下四个固定维度分析每个选项。
  4. 如果是交互式会话,还要直接询问维护者;无论如何,带标签的问题都是持久记录。绝不要代替维护者回答产品或架构问题。
四轴决策框架(约束性)

升级处理中的每个选项都必须从全部四个维度进行分析。这一框架是升级处理的核心,而非装饰。

维度 ① — 实际业务需求。 该选项服务于真实存在的业务场景,还是仅仅提供推测性的能力?在每个选项上都要首先提出这个问题,先于架构论证,因为它可能直接让问题不再需要回答。证据必须是实测的,而非推断的:谁写入这个键,谁读取这项能力,项目的示例应用和实际部署目前如何使用它。“看起来会有用”不算证据。这个维度会改变结论,而非仅作点缀:两个技术形态完全相同的发现,仅凭这一维度就可能得出相反的裁定——一项已声明的能力因没有实际需求而退役,另一项则因真实应用证明了其方向而保留,并要求它明确报错。从其他维度看,它们的结论会相同,而那将是错误的答案。

维度 ② — 对本项目而言的长期架构健全性。 哪个选项符合项目的发展方向和可持续架构——无变通方案、契约优先——而不是哪个方案今天成本最低。任何补丁式选项的长期成本都必须明确说明。“我们可以在这里为它添加特例”是有效选项,但前提是说明未来移除它的成本。

维度 ③ — 从结构上避免 AI 编写的代码出错,尤其是 AI 编写的 ObjectStack 元数据。优先选择能在编写时防止错误的方案——严格的 schema、发布时验证并明确拒绝、声明即强制执行——而不是依赖使用方宽容处理(?? 回退、接受别名、静默强制转换)。宽容的使用方正是 AI 生成的错误藏匿并不断扩散的地方:一个宽容的读取方,会让整代错误元数据“能够运行”,直到它不再能运行。绝不能让 Agent 声明运行时并不支持的能力。

维度 ④ — 启动阶段的范围纪律。 核心仍在成形时,不要扩大已声明的表面。“我们已经发布了”并不能作为理由:已发布但无人使用的能力,不享有沉没成本豁免。没有实际需求的已声明能力,应采取实现优先的处理方式——收窄声明,直至 declared = enforced(退役该能力,或暂存该词汇,待实现到位后再恢复),而不是为了合理化一项无人提出需求的声明而构建实现。**默认范围应收紧到何种程度,由你的项目决定,而不是由本 skill 决定:**在项目约定文件中声明能力扩展立场——核心表面仍在成形时从严,稳定后可更宽松——这个维度会像读取其他项目专属规则一样,从中读取这一立场。

你的建议必须基于全部四个维度给出理由。如果它们相互冲突,应如实说明权衡,让维护者决定。当各维度意见不一时,建议按需求优先排序:有实测需求 → 采用长期方案;无需求 → 避免扩散(推迟/移除、记录、随时重新评估);AI 安全维度用于打破剩余平局,倾向于明确报错的方案;安全和破坏性操作仍由人工决定。此顺序仅用于排列建议——意见不一时仍须升级处理。

维度 ② 权重最高——至少占 50%。 应先说明长期考量;各维度冲突时,其他维度的权重合计也不能超过它。应将这一权重理解为减少特例和契约堆积,而非增加它们——因此它绝不能成为推测性扩展的依据。它只用于排列建议,绝不决定权限归属。

9. 轮次报告,然后开始下一轮

向维护者输出轮次报告:包含“问题 → 结论 → PR 链接 → 备注”的表格,以及任何已升级处理的事项和你在否决窗口期间作出的决定。然后从步骤 1 开始下一轮。重新分派返工事项的次数计入下一轮的 batch 预算。


停止条件

遇到以下任一情况时,停止循环并报告:

  • 队列为空,或 rounds 已耗尽;
  • 某一轮中有一半或更多的派发失败或升级处理——这说明存在系统性问题(队列整理不当、默认分支损坏、工具不正确),继续用剩余派发处理积压任务只会白白浪费资源;
  • 维护者中断。

开发者 Agent 操作模板

将 rules/dev-template.md 原样粘贴到每个派发提示词中;由 PM 填写其中的 {…} 占位符。{decision_frame} 使用下方的停止触发条件,后接上方完整的 #### 四轴决策框架(具有约束力) 部分:此框架在本技能中只有一份,PM 在派发时粘贴,因此不会出现开发者侧的副本与之不一致的情况。

When to STOP instead of coding. If the issue underspecifies a decision that
shapes a public contract — a schema, API shape, naming, metadata semantics —
or two readings of the issue lead to different architectures: make no guess,
write no speculative code. Return status "needs_decision" with each question,
the options, their costs, and your recommendation in open_questions. A wrong
guess shipped is far more expensive than a round-trip to the maintainer.

报告约定。 模板最终消息部分中的 JSON 就是完整约定。当 status 为 needs_decision 时,open_questions 必须非空,且每个条目都会成为升级分析的输入。out_of_scope_findings 应由开发者 Agent 作为未分配的问题单提前提交——PM 只需确认它们确实存在。premise_still_valid: false 表示 Agent 的验证推翻了该问题:在 summary 中提供证据,pr 设为 null 或仅包含仍然成立的范围——应重新分诊该卡片,而不是审查 PR。


上游报告——构建应用时发现的平台缺陷

相关准则位于 objectstack-platform 的 “应用/平台边界” 部分——修复应在上游进行,绝不能在应用中采用变通方案。此循环还要求:

  • 推导上游仓库:从故障依赖的 package.json 的 repository 字段确定上游仓库,并确认该缺陷在其当前默认分支上仍然存在——若已修复,则应用侧任务应改为升级。
  • 以无需依赖你的应用即可采取行动的方式报告:提供独立的最小复现、精确锁定的版本、预期结果与实际结果,以及所引用的契约。
  • 以访客而非调度方的身份提交:添加反向链接 Part of <app-owner>/<app-repo>#<n>;绝不应用上游的队列标签,绝不分配负责人,也绝不将其添加到上游看板。
  • 如实搁置应用侧问题:标注 Blocked-by: <upstream>#<n>,或锁定版本并记录解除阻塞的条件。问题应保持开启——“我们已绕过问题”绝不算解决。

资源管理(PM 侧)

内存峰值来自构建和测试,而非编辑,因此解决办法不是减少并行,而是将高负载阶段串行执行——开发者 Agent 模板对此有明确要求:使用容器级验证锁、设置堆内存上限、限定构建范围并清理工作树。

PM 侧:将配置的 batch 视为适用于普通规模的任务。对于构建负载较高的任务(依赖系列升级、完整回归测试),将其调低为 batch:2,或通过 mode:cloud 派发该问题,使其使用独立容器。如果 Agent 因内存不足而退出,应单独重新派发,而不是将其放入满载的批次中。


护栏(具有约束力)

  • PM 不写入任何文件。只有经过审查且所有检查均通过的开发 Agent PR,才能通过项目认可的流程合并——绝不合并自己的 PR,也绝不合并检查失败或未经审查的 PR。
  • 绝不强制推送,绝不推送到默认分支,绝不将他人已认领的问题重新指派给别人,绝不调度 needs-user-decision 问题。
  • 每个开发 Agent 在每个仓库中都使用自己的工作树。
  • 并行数量不得超过 batch,同一批次中的 Agent 必须从设计上确保修改的文件互不重叠。
  • 待办事项仓库是唯一的调度权威。绝不向你看不到其进行中批次的仓库调度任务。
  • 每个队列只能有一位 PM。 通过 batch 和 mode:cloud 扩展规模,绝不在同一队列上安排第二位调度者;第二位 PM 应将整个其他仓库作为自己的分片,在每条认领评论中说明该分片,且绝不认领分片范围之外的任务。跨分片工作应通过问题流转:在目标仓库中创建带有队列标签的卡片,其中包含 Part of <owner/repo>#<n> 行;在等待处理的一侧添加 Blocked-by:;并在使用方仓库中记录后续待办——绝不能只靠记忆。
  • 如果此处的任何规则与项目约定文件冲突,以该文件为准。

将此工作循环适配到你的项目

此技能有意不包含任何项目的门槛要求。请将这些要求写入约定文件(AGENTS.md / CLAUDE.md / …),工作循环会在每次调度时将其纳入:

工作循环需要了解的内容信息来源
分支命名、默认分支、PR 语言约定文件
必需的发布说明产物(changeset、CHANGELOG 条目、无)约定文件
发布流程负责且代码 PR 绝不能触及的文件约定文件
各软件包的测试 / 类型检查 / lint 命令约定文件
如何获取共享的重型验证锁(封装脚本、锁路径、获取时限)约定文件
合并策略(合并队列、串行合并、仅维护者可合并)约定文件
能力扩展立场轴 ④ 的取值(默认严格,或宽松)约定文件
存在哪些仓库,以及哪个是待办事项仓库.claude/pm-dispatch.json
升级处理门槛所依据的已记录架构决策项目的 ADR 目录

如果调度失败是因为开发 Agent 不知道某条项目规则,修复应写入约定文件,而不是写进更长的调度提示词。

评论

支持 Markdown