Skip to content

Commit ff98f67

Browse files
os-zhuangclaude
andauthored
feat(agents): pm-dispatch triage — PM routes issues; parent label queues its sub-issue tree (#4546)
* feat(agents): pm-dispatch triage step — routing is the PM's job The maintainer only files the task and adds pm:queue; the PM analyzes where the change lands, applies repo:* labels itself, does cross-repo splits, and leaves a one-comment audit trail so routing can be vetoed cheaply. 'Which repo?' is never escalated — only underlying product questions are. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012C2cd7tL8QDoZ2QKN3djJ5 * feat(agents): pm:queue on the parent alone queues its whole sub-issue tree A maintainer-built parent+sub-issue structure needs only the parent labeled: sub-issues become candidates automatically, the PM triages and routes each, keeps expressed dependency order and infers contract-first Blocked-by lines where absent. The parent is a coordination node — never dispatched, closed by the PM with a summary when the last sub-issue closes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012C2cd7tL8QDoZ2QKN3djJ5 * chore: add empty changeset (internal .claude tooling releases nothing) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012C2cd7tL8QDoZ2QKN3djJ5 --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 4638aaa commit ff98f67

2 files changed

Lines changed: 55 additions & 15 deletions

File tree

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
---
3+
4+
Internal agent tooling only (`.claude/` pm-dispatch triage + sub-issue queueing rules) — releases nothing.

.claude/skills/pm-dispatch/SKILL.md

Lines changed: 51 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,9 @@ The product spans three repos with a fixed dependency direction:
7777

7878
**1. One main backlog.** Feature-level issues live in `objectstack`,
7979
whatever repo the code lands in. A `repo:objectui` / `repo:cloud` label
80-
routes the dev agent's working repo; no routing label = backend. The dev
80+
routes the dev agent's working repo; no routing label = backend. **The PM
81+
applies these labels itself at triage (round loop step 2)** — the maintainer
82+
just files the task and is never expected to pre-route it. The dev
8183
still branches/pushes/PRs **in the target repo** (its own worktree there —
8284
one worktree per repo, as always). Repo-local trivia may still be filed in
8385
the sibling repos directly; to drain such a local queue, run
@@ -111,27 +113,61 @@ the loop resumable and the board honest.
111113
### 1. Fetch candidates
112114

113115
List open issues matching the filter, excluding anything assigned or labeled
114-
`needs-user-decision`. Read each candidate's full body — batch selection
115-
(step 2) and the dispatch prompt both need it.
116-
117-
### 2. Select the batch
116+
`needs-user-decision`. **Open sub-issues of a matching parent are candidates
117+
too** — they inherit the parent's queue membership and need no label of their
118+
own. Read each candidate's full body — triage, batch selection (steps 2–3)
119+
and the dispatch prompt all need it.
120+
121+
### 2. Triage — routing is the PM's job, never the maintainer's
122+
123+
The maintainer's only input is the issue itself plus `pm:queue` (or naming
124+
the task in chat). They are **not** expected to know which repo a change
125+
lands in — that answer usually *is* the analysis. For each candidate whose
126+
routing isn't already decided:
127+
128+
- **Determine where the change lands** by reading the issue against the
129+
actual code of the three repos. Apply `repo:objectui` / `repo:cloud`
130+
yourself; leave unlabeled for backend. A routing label a human already
131+
set is respected as-is.
132+
- **Cross-repo?** Do the split yourself per "Multi-repo coordination" rule
133+
2: file the parent + per-repo sub-issues, contract-first order,
134+
`Blocked-by:` lines, routing labels on each sub-issue.
135+
- **Parent issue that already has sub-issues** (the maintainer built the
136+
structure themself): the queue label on the **parent alone** is enough —
137+
sub-issues of a queued parent are candidates automatically, with no label
138+
of their own. The PM expands the parent at triage: triage/route each
139+
sub-issue individually, keep any dependency ordering the maintainer
140+
expressed (`Blocked-by:` lines or native blocked-by relations), and where
141+
none is expressed **infer the contract-first order and write the
142+
`Blocked-by:` lines yourself** (audit-trail comment as usual). The parent
143+
itself is a coordination node — **never dispatched to a dev**; it stays
144+
open as the progress view and the PM closes it with a summary comment when
145+
the last sub-issue closes.
146+
- **Leave a one-comment audit trail** on the issue (Chinese), so the
147+
maintainer can veto cheaply: 「分诊:落地 objectui;理由:…」.
148+
- Routing is a **technical judgment — never escalate "which repo?" to the
149+
maintainer.** If after reading the code you genuinely cannot tell where a
150+
change lands, the issue is underspecified: escalate the *underlying
151+
product question* (step 8), not the routing.
152+
153+
### 3. Select the batch
118154

119155
Pick up to `batch` issues that are **mutually independent**: no two issues in
120156
one batch may plausibly touch the same package, registry/barrel file, or spec
121157
schema. Two dev agents editing the same shared file produce a merge race that
122158
costs more than serializing. When in doubt, serialize — put the second issue in
123159
the next round. Prefer small, well-specified issues; an issue with no acceptance
124-
criteria you can state in one sentence is a candidate for escalation (step 7),
160+
criteria you can state in one sentence is a candidate for escalation (step 8),
125161
not dispatch.
126162

127-
### 3. Claim
163+
### 4. Claim
128164

129165
For each selected issue, **before dispatching** (repo rule: claim before code):
130166
assign it to yourself (`@me`) and add labels + a comment in Chinese, e.g.
131167
「已由 PM 循环派发给开发 agent(第 N 轮)。」Skip — and drop from the batch —
132168
any issue that acquired an assignee since step 1.
133169

134-
### 4. Dispatch
170+
### 5. Dispatch
135171

136172
One `Agent` call per issue, `subagent_type: "os-dev"` (fall back to
137173
`general-purpose` with the same prompt if the custom agent isn't loaded), run
@@ -187,9 +223,9 @@ to `mode:subagent`). Per issue:
187223
report as a comment on the issue** (prefixed `<!-- os-dev-report -->`)
188224
instead of returning it, in addition to opening the draft PR.
189225
2. `fire_trigger` to launch it, then `delete_trigger` once the report has
190-
been collected (step 5) so poke-only triggers don't accumulate.
226+
been collected (step 6) so poke-only triggers don't accumulate.
191227

192-
### 5. Collect
228+
### 6. Collect
193229

194230
**Subagent mode:** wait for the background task notifications — do not poll,
195231
do not fabricate a pending agent's result. A dev that dies or returns
@@ -202,7 +238,7 @@ silently until every dispatch of the round has reported or a dispatch has
202238
been silent for over ~2 h (count it as `blocked` and move on). Never treat
203239
the absence of a report as success.
204240

205-
### 6. Review each report
241+
### 7. Review each report
206242

207243
You are the reviewer of record. For each report, verify against GitHub — not
208244
against the report's own claims:
@@ -225,9 +261,9 @@ Verdict per issue:
225261
- **REWORK** — concrete, itemized feedback; re-dispatch the same issue with
226262
the feedback block filled (same claim, new dev agent). **Max 2 rework
227263
rounds** per issue; a third failure escalates instead.
228-
- **ESCALATE** — see step 7.
264+
- **ESCALATE** — see step 8.
229265

230-
### 7. Escalate uncertainties to the maintainer
266+
### 8. Escalate uncertainties to the maintainer
231267

232268
Whenever a dev returns `needs_decision`, an issue is too vague to dispatch, or
233269
rework has failed twice:
@@ -252,7 +288,7 @@ rework has failed twice:
252288
the filed issue remains the durable record either way. **Never** answer a
253289
product/architecture question on the maintainer's behalf.
254290

255-
### 8. Round report, then next round
291+
### 9. Round report, then next round
256292

257293
Print a round report to the maintainer **in Chinese**: a table of
258294
issue → verdict → PR link → notes, plus anything escalated. Then start the
@@ -277,7 +313,7 @@ Stop the loop and report when any of these hits:
277313
- Every dev agent works in its **own worktree per repo** (enforced by
278314
`guard-main-checkout.sh`; the os-dev definition repeats it).
279315
- Parallelism is capped by `batch`. Dev agents for one batch must be
280-
file-disjoint by construction (step 2).
316+
file-disjoint by construction (step 3).
281317
- When any rule here conflicts with AGENTS.md, **AGENTS.md wins**.
282318

283319
## Report contract (what os-dev returns)

0 commit comments

Comments
 (0)