
batch-bug-shepherd
✓ Official★ 3,123by microsoft · part of microsoft/apm
Use this skill to drive a batch of suspected bugs in microsoft/apm from raw issue list to mergeable PR queue. Fan out one triage subagent per issue (LEGIT / UNCLEAR / FIXED-AT-HEAD), gate every legit bug against PRINCIPLES.md via an apm-ceo strategic-alignment pass, cross-reference legit issues against open PRs, then open a fix PR (TDD + mutation-break gate) for greenfield bugs. Drive every PR -- community in-flight and own fix alike -- to mergeable by composing the shepherd-driver skill: one dr
This is the playbook your agent receives when the skill activates — you don't need to read it to use the skill, but it's here to audit before installing.
batch-bug-shepherd - Outer-loop bug-queue orchestrator
This skill is an A10 ORCHESTRATOR-SAGA over fan-out waves (triage,
strategic-alignment, PR-cross-reference, fix, drive-to-merge,
conflict-resolution) with a persisted ground-truth table between
phases. It COMPOSES the
shepherd-driver skill as the per-PR
drive-to-merge engine -- it does NOT re-implement the review +
fold + push + CI loop. shepherd-driver transitively COMPOSES
apm-review-panel; this skill inherits
that edge and never reaches into panel internals directly. It also
COMPOSES the apm-ceo persona (host-repo agent at
.apm/agents/apm-ceo.agent.md) for the strategic-alignment gate,
which checks every LEGIT bug against PRINCIPLES.md before allowing
fix / drive work to proceed. Per-PR shepherding is delegated to
shepherd-driver; per-issue verification, strategic alignment,
PR-in-flight branching, greenfield fix dispatch, post-wave
mergeability re-probe, and the cross-session table are owned here.
The skill is ADVISORY at the panel layer and EXECUTIVE at the
orchestrator layer: it WILL push commits, open PRs, post comments,
close superseded PRs. Every consequential write goes through a
deterministic CLI (gh, git, uv run ruff) wrapped in plan +
execute + verify (A9 SUPERVISED EXECUTION).
Architecture invariants
These 17 rules bind every wave. The one-line essence is below; the
FULL binding text (rationale, edge cases, inherited-from-driver
detail) lives in references/invariants.md. Load
references/invariants.md before planning Phase 0 -- the summaries
here are dispatch anchors, not the complete contract.
- Fan-out, not serial. Triage / alignment / fix / drive run as parallel child threads; single-loop is an anti-pattern.
- Verify before fix. No fix dispatched until the bug reproduces
on HEAD (
LEGIT);UNCLEAR-> human,FIXED-AT-HEAD-> close. - PR-in-flight detection is mandatory.
gh pr listevery legit issue before any fix; duplicating community work is the worst failure mode this skill defends against. - Drive, do not split shepherd from complete. ONE shepherd-driver subagent owns the whole per-PR loop; no separate panel + completion waves.
- Mutation-break gate. A regression trap is real only if deleting the production guard makes the test FAIL.
- Superseding-PR fallback (inherited). On contributor-fork push
failure the driver opens an authorship-preserving PR under
microsoft/apmand returnssuperseded. - Single-writer interlock. One idempotent panel comment + one driver advisory per PR; the orchestrator never posts to a PR.
- ASCII only. Printable ASCII in every artifact (cp1252 safety).
- Lint contract is the push gate (inherited).
ruff check+ruff format --checksilent before anygit push. - Ground-truth table is the single source of truth. One plan.md table, rewritten on every return, re-read at each wave start (B4 PLAN MEMENTO + B8 ATTENTION ANCHOR).
- Cross-session message reports only on green. Failures stay in the subagent session until resolved or escalated to a human.
- Operator visibility is a contract. Progress mermaid + live
table at every boundary; dispatch table before every fan-out
(
assets/progress-diagram.md). - Mergeability is post-wave truth. Re-probe
mergeStateStatusbefore claiming ready; Phase 5 resolves conflicts with--force-with-lease(bare--forceprohibited). - Two-comment-per-PR cap. Driver advisory + resolution confirmation only; the in-loop panel comment is idempotent and does not add to the count. No third comment, ever.
- Bias toward folding (inherited). The driver folds in-scope follow-ups into the PR; only genuinely separable work becomes a tracking issue.
- Strategic-alignment gate before drive. Phase 1.5 runs one
apm-ceosubagent per LEGIT row; demoted rows skip Phase 2-5; the gate fails open toaligned, aborts only if the persona /PRINCIPLES.mdis missing. - Worktree isolation. Every fix and drive child runs in its OWN
git worktree (one per issue/PR); never fan out mutating children
against a shared
REPO_ROOT(they would race on.git/indexand the checked-out branch). Triage is read-only and may share one.
Composition with shepherd-driver
shepherd-driver is the per-PR drive-to-merge engine. This skill
spawns ONE shepherd-driver subagent per PR (both in-flight community
PRs and own greenfield fix PRs) using the spawn body
../shepherd-driver/assets/shepherd-driver-prompt.md. The driver owns
the whole convergence loop -- Copilot classification, apm-review-panel,
fold-vs-defer, push, CI watch, with its own caps -- and
returns a completion_return matching
../shepherd-driver/assets/completion-schema.json
(ready-to-merge | advisory-with-deferred | superseded |
blocked).
The cross-PR conflict-resolution / mergeability phase is ALSO
shepherd-driver's: Phase 5 delegates to
../shepherd-driver/assets/conflict-resolution-prompt.md with the
step-by-step gate in
../shepherd-driver/references/mergeability-gate.md.
shepherd-driver is a same-repo LOCAL SIBLING declared in apm.yml
(dependencies.apm: [../shepherd-driver]). PROBE for it before the
drive wave -- a tool call, not an assertion from recall (A9 SUPERVISED
EXECUTION):
test -f ../shepherd-driver/assets/shepherd-driver-prompt.md \
&& test -f ../shepherd-driver/assets/completion-schema.json \
&& echo "shepherd-driver present" \
|| echo "MISSING shepherd-driver - stop and ask the operator"On a probe MISS, STOP and ask the operator to restore the sibling; do
NOT re-implement the loop inline (avoids HAND-ROLLED HALLUCINATION and
PHANTOM DEPENDENCY). The driver transitively composes
apm-review-panel and probes for it at its own preflight, returning
status: blocked on a miss. The orchestrator NEVER reaches into
shepherd-driver or apm-review-panel internals.
Phases
Work through the phases in order. Reload the ground-truth table at each phase boundary. Do not skip the cross-reference phase.
At every phase boundary (and once at the run start, once at the
end), render the progress mermaid diagram + the live ground-truth
table to chat per assets/progress-diagram.md. Before every
fan-out wave, also render the dispatch table mapping subagent_id to
target. These are not optional -- they are the operator's only
real-time window into a multi-wave parallel saga.
Phase 0 - scope resolution
Input is either (a) an explicit issue list (e.g. #123 #456 #789) or
(b) the sweep-all flag, which expands to:
gh issue list --label bug --state open --json number,title,labels,body- plus
gh issue list --state open --search "is:open no:label"filtered by suspicion keywords (error,crash,broken,regression,unexpected,traceback,does not work,cannot,fails).
Initialize the ground-truth table (assets/ground-truth-table.md)
with one row per candidate. Print a brief plan to the user:
candidate count, expected wave shape, and the disciplines that will
be enforced (mutation-break, ASCII, lint). Ask for confirmation only
if sweep-all produced more than 20 candidates -- otherwise proceed.
Then render the progress mermaid diagram for the first time per
assets/progress-diagram.md -- every phase pending, with the
candidate count N substituted into the P0 and P1 labels. Print
the live (empty) ground-truth table below it. This is the
operator's anchor frame for the run.
Phase 1 - triage fan-out (WAVE 1)
Re-render the progress diagram with P1 styled active. Print the
dispatch table mapping each triage-<issue> subagent_id to its
target issue BEFORE issuing the parallel spawns.
Spawn one child thread per candidate using assets/triage-prompt.md.
Each subagent:
- Reproduces the bug on HEAD via the smallest possible repro.
- Returns a verdict JSON matching
assets/verdict-schema.json(triageverdict shape).
Schema-validate every return (S4). On malformed, re-spawn that
subagent ONCE with a clarifying note. On second malformed, mark the
row UNCLEAR -- subagent malformed and continue.
Update the table. Move on only when every row has a triage verdict.
Phase 1.5 - strategic-alignment gate (WAVE 1.5)
Re-render with P15 active (substitute L LEGIT count). If
L = 0, render P1.5 as skipped and pass through.
Load references/strategic-alignment-gate.md when entering this
phase -- it holds the binding procedure (external-dep probes,
fail-open semantics, deferred-PR strategic-rejection subagent).
Probe .apm/agents/apm-ceo.agent.md and PRINCIPLES.md. Either
missing -> ABORT. Print the dispatch table for the
ceo-align-<issue> subagents, then spawn L parallel threads with
assets/strategic-alignment-prompt.md. Returns are
strategic_alignment_return JSON (verdict in aligned |
aligned-with-reservations | out-of-scope | wrong-direction).
Schema-validate per retry-once; on second malformed, route as
aligned with gate_note (fail-open).
Update strategic_verdict + strategic_rationale columns.
Demoted rows flip to status triaged-deferred and are SKIPPED by
Phase 2/3/4/5. aligned-with-reservations rows stay in saga;
downstream phases MUST surface the reservations.
Phase 2 - PR-in-flight cross-reference
Re-render the progress diagram with P1 done and P2 active.
Substitute L (LEGIT row count) into the P2 label.
Skip every row with status triaged-deferred (Phase 1.5 demoted).
Run a LIGHTWEIGHT gh pr list probe against demoted rows only to
feed the deferred-PR strategic-rejection comment procedure in
references/strategic-alignment-gate.md; this read-only probe
does not route demoted rows back into Phase 2.
For every LEGIT row (status triaged), run gh pr list --search "<issue-ref-or-keywords>" --state open --json number,title,headRefName,headRepository,headRepositoryOwner,author,maintainerCanModify.
Also inspect each linked PR on the issue itself. Two outcomes per row:
pr_in_flight = false-> route to FIX in Phase 3 (greenfield).pr_in_flight = true-> capture and store, for the Phase 4 driver spawn, every input shepherd-driver requires:PR_NUMBER(number),AUTHOR(author.login),HEAD_REPO(headRepositoryOwner.login+ "/" +headRepository.name),HEAD_BRANCH(headRefName),MAINTAINER_CAN_MODIFY(maintainerCanModify), andORIGIN = community. Route to DRIVE in Phase 4.
Store these driver-input fields in the row (table columns
head_repo, head_branch, maintainer_can_modify). They are the
crash-survivable evidence the Phase 4 spawn reads -- never re-derived
from recall. Update the table. This phase MUST complete before any
Phase 3 or Phase 4 spawn.
Phase 3 - greenfield fix fan-out (WAVE 2)
Re-render the progress diagram with P0..P2 done and P3 active.
Substitute m (greenfield count) into the P3 label. If m = 0,
render P3 as skipped (dashed border) and pass straight to Phase 4.
This wave is FIX-ONLY. In-flight community PRs do NOT pass through
here -- they go directly to the Phase 4 drive wave. Filter out any row
with status triaged-deferred (strategically demoted by Phase 1.5).
Print the fix-<issue> dispatch table (subagent_id -> issue number)
BEFORE spawning. For each LEGIT && !pr_in_flight row, provision one
git worktree (git worktree add <path> origin/main), record its slug
in the row's worktree column, and spawn a child thread with
assets/fix-prompt.md passing that worktree path as REPO_ROOT (per
the Worktree-isolation invariant). The fix subagent:
- Writes failing tests FIRST (TDD).
- Implements the minimum fix.
- Runs the mutation-break gate (delete the new guard, confirm tests FAIL).
- Runs the lint contract.
- Opens a PR under
microsoft/apmreferencing the issue. - Returns
{kind, issue, pr, branch}.
On each return, store the Phase 4 driver inputs for the new PR:
PR_NUMBER (pr), AUTHOR = the maintainer's own gh handle (these are
own PRs), HEAD_REPO = microsoft/apm (same-repo head),
HEAD_BRANCH (branch), MAINTAINER_CAN_MODIFY = true, and
ORIGIN = own-fix. Write head_repo, head_branch,
maintainer_can_modify into the row. Hold until every spawn returns.
Phase 4 - drive-to-merge fan-out (WAVE 3)
PROBE for shepherd-driver (see "Composition with shepherd-driver"). On a probe MISS, STOP and ask the operator; do NOT inline the loop.
Re-render with P4 active. Let D be the count of PRs to drive --
EVERY PR in the table that is not triaged-deferred: the in-flight
community PRs (ORIGIN = community, from Phase 2) PLUS the own fix PRs
(ORIGIN = own-fix, from Phase 3). Substitute D into the P4 label;
if D = 0, render P4 as skipped.
Print the drive-<pr> dispatch table (subagent_id -> PR number), then
spawn ONE shepherd-driver subagent per PR using
../shepherd-driver/assets/shepherd-driver-prompt.md. Each driver
runs in its OWN worktree (Worktree-isolation invariant): own-fix rows
REUSE the worktree their Phase 3 fix child recorded; community rows
get a fresh git worktree add + gh pr checkout, recorded in
worktree. Pass the inputs the prompt declares, reading each from the
row (never recall); REPO_ROOT is the row's worktree path. For rows
with strategic_verdict = aligned-with-reservations, ALSO pass
PANEL_PRIOR = {"reservations": [<the strategic reservations as {summary} objects>]} so the driver surfaces them in the panel run and
the PR advisory comment.
If D is large, batch the spawns (e.g. groups of 3) to bound
nested-panel fan-out rather than launching all drivers at once.
Each driver owns the full convergence loop end-to-end and returns a
completion_return matching
../shepherd-driver/assets/completion-schema.json (status enum per
the Composition section). Schema-validate every return (retry-once; on
second malformed, mark the row blocked and continue). Write
head_sha, mergeable, merge_state_status, and ci_status from
the return into the table, and remove the status/shepherding label
from the driven issue (assignment stays). The orchestrator owns only
schema-validation, table update, and label cleanup -- it does NOT post
to any PR.
Phase 5 - mergeability gate (WAVE 4)
Re-render with WAVE4 active. Substitute R (ready-PR count)
and C (CONFLICTING-PR count) into the P5a / P5b labels. If
R = 0, skip Phase 5 entirely; if C = 0, render P5b as
skipped.
Load ../shepherd-driver/references/mergeability-gate.md when
entering this phase -- it holds the binding step-by-step (probe CLI
flags, retry policy, four-way partition, trust-but-verify re-probe).
The contract summary:
- 5a (read-only): probe every Phase-4 ready PR via S7
DETERMINISTIC TOOL BRIDGE (
gh pr view --jsonwith the S7 mergeability fields -- full flag list inmergeability-gate.md). Skiptriaged-deferredrows. Partition CLEAN / UNSTABLE / HAS_HOOKS (verified-ready) from BEHIND / DIRTY / CONFLICTING (route to 5b). BLOCKED is not a conflict. - 5b (fan-out, one subagent per CONFLICTING PR): print dispatch
table, spawn
resolve-conflicts-<pr>subagents using../shepherd-driver/assets/conflict-resolution-prompt.md. Each owns its PR end-to-end: rebase, faithful conflict merge, lint silent, push with--force-with-lease(NEVER bare--force), re-probe, post the single resolution-confirmation comment. Returns areconflict_resolution_returnmatching../shepherd-driver/assets/completion-schema.json. - 5c (read-only): trust-but-verify re-probe; partition into the
schema's four
conflict_resolution_returnstatuses; update the table.
Phase 6 - final report
Re-render with every phase done (or blocked where the
human-escalation queue is non-empty). Render
assets/final-report-template.md: per-issue verdict, PR link,
post-gate status (the template's status set), and subagent session
refs. Phase-1.5-demoted rows land in the template's "Recommend close
as out-of-scope" partition, each citing the principle that fired.
Use clickable GitHub links (issue + pull URLs under
github.com/microsoft/apm) and @<author> profile links, not plain
issue numbers.
After the report renders, tear down ONLY the worktrees this run
created (git worktree remove each slug in the worktree column);
leave branches on origin for the open PRs.
Bundled assets
This skill bundles ONLY the assets unique to its triage-and-batch
orchestration. Everything PR-drive related is owned by the composed
shepherd-driver sibling, loaded from ../shepherd-driver/, not
duplicated here.
assets/verdict-schema.json-- JSON schema for the TWO BBS-owned subagent return shapes (triage_return,strategic_alignment_return). Schema-validate every return (S4).assets/ground-truth-table.md-- canonical table template (issue | verdict | pr | pr_in_flight | author | head_repo | head_branch | maintainer_can_modify | worktree | status | strategic_verdict | strategic_rationale | notes).assets/triage-prompt.md-- WAVE 1 spawn body.assets/strategic-alignment-prompt.md-- WAVE 1.5 spawn body (loadsapm-ceopersona + PRINCIPLES.md).assets/fix-prompt.md-- WAVE 2 greenfield-fix spawn body.assets/final-report-template.md-- user-facing report shape.assets/progress-diagram.md-- mermaid progress diagram, color contract, dispatch-table render rules (Phase 1, 1.5, 3, 4, 5b).references/strategic-alignment-gate.md-- Phase 1.5 step-by-step (external-dep probes, fail-open semantics, deferred-PR strategic-rejection subagent). Load WHEN ENTERING PHASE 1.5.references/invariants.md-- full binding text of the 17 architecture invariants. Load BEFORE PLANNING PHASE 0.
Composed from shepherd-driver (loaded by relative path, NOT bundled):
shepherd-driver-prompt.md (Phase 4 drive),
conflict-resolution-prompt.md (Phase 5b),
completion-schema.json (driver + resolution returns),
references/mergeability-gate.md (Phase 5 gate) -- all under
../shepherd-driver/.
Operating contract for the orchestrator thread
The orchestrator loop, beyond the invariant anchors above:
- Before each phase: re-read
plan.mdground-truth table. After each subagent return: schema-validate, update the table, write it back. - Delegate every PR-side write to the responsible subagent; the orchestrator never posts to a PR and never flips merge state.
- Render the progress mermaid + live table at every phase boundary,
and the dispatch table before every fan-out
(
assets/progress-diagram.md).
Out of scope
- Authoring panel personas (lives in
apm-review-panel). - Computing coverage percentages (lives in test-coverage-expert persona, invoked via apm-review-panel).
- Single-PR review without a batch (use
apm-review-paneldirectly). - Driving a single PR to merge without a batch (use
shepherd-driverdirectly). - Auto-merge or auto-label. The orchestrator does not flip merge state; the maintainer ships.
npx skills add https://github.com/microsoft/apm --skill batch-bug-shepherdRun this in your project — your agent picks the skill up automatically.
No common issues documented yet. If you hit a problem, the repository's GitHub Issues page is the best place to look.
Licensed under MIT— you can use, modify, and redistribute it under that license's terms.
View the full license file on GitHub →