issue-handler
Skill121 starsChanged 5 months agoApache-2.0View on GitHub
Use when asked to fix a GitHub issue end-to-end, run the agent pipeline on an issue, or process an `agent:active` / batch tracking issue. Orchestrates the full pipeline: `issue-triage` → `fix-reproduce` → `fix-root-cause` → `fix-implement` → `fix-verify` → report. Handles single-bug issues and batch-bug issues (a parent tracking multiple sub-bugs — skip-list or heterogeneous — fanned out one fix branch per sub-bug). On re-run, prioritizes new human feedback and skips work that is still valid.
- Installs packages
2 other projects use a version of this.
Adopted by
Most recently taken up by
- tencentmusic/juggtheir own version, first seen Oct 9, 2026
- yangwhale/CloseCrabtheir own version, first seen Aug 18, 2026
Other versions2 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 2
- tencentmusic/jugg★ 583same name
- yangwhale/CloseCrab★ 5same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository28 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- .github/copilot-instructions.mdCopilot instructions
- asm-source-mappingSkill
- at-dispatch-v2Skill
- auto-labelSkill
- extract-asm-onednnSkill
- extract-asm-syclkernel-aotSkill
- extract-asm-syclkernel-jitSkill
- extract-asm-tritonSkill
- extract-xpu-kernel-asmSkill
- fix-implementSkill
- fix-reproduceSkill
- fix-root-causeSkill
- fix-verifySkill
- issue-triageSkill
- label-issueSkill
- oob-perf-analysisSkill
- pr-reviewSkill
- release-branchingSkill
- skill-writerSkill
- ut-checkSkill
- ut-issue-authoringSkill
- ut-refactor-reviewSkill
- xpu-alignmentSkill
- xpu-build-pytorchSkill
- xpu-ci-health-checkSkill
- xpu-ops-pr-creationSkill
- xpu-release-notesSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
25 rules. About 0 are common, 10 are distinctive, and 15 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈10
Distinctive · estimate
This author's own choices. Worth a look.
15
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 22
Every agent-produced diff is a proposal.
- Distinctive: line 106
Interactive (default): ask the user when blocked.
- Very specific: line 109
Pipeline (explicit): no human to interrupt — advance the issue's agent:status marker, update stage labels, let leaf skills leave their <!-- …
- Distinctive: line 183
highest priority signal: Read every such comment verbatim and
- Distinctive: line 194
No human pointed anything out since the last agent comment, so re-doing the whole pipeline would just repeat identical work.
- Distinctive: line 198
Run Stage 1 (triage) and Stage 2 (reproduce) as normal.
- Very specific: line 226
Call issue-triage on the issue body + comments.
- Very specific: line 248
Only for the single-bug path (issue_type=single-bug).
- Distinctive: line 288
No child GitHub issues are created.
- Very specific: line 338
When the list is long (skip-list issues routinely have dozens), front-load the one real wheel install so the per-entry …
- Distinctive: line 358
Do not guess which entries share a fix:
- Very specific: line 410
Root-cause, then branch: Run Stage 3 (fix-root-cause) first — it returns target_repo, which decides *which* checkout the fix (and thus the …
- Very specific: line 421
Create the isolated fix branch on target_repo_dir off its base so the diff is pushable on its own (Branch naming):
- Very specific: line 437
On
fix-verifyPASSED: do NOT push or open a PR. Update the sub-item's fix_result-${slug}.json in place (written at verdict=PENDING_VERIFY … - Very specific: line 502
After the loop, go to Stage 6 Report with the aggregate outcome (IMPLEMENTING(fix_verified) if any sub-item was fixed.
- Very specific: line 588
Call fix-root-cause with the failure description and the refined_command from Stage 2.
- Very specific: line 614
Call fix-implement with triage_result, pytorch_dir, target_repo_dir (derived from target_repo), and allow_skip:
- Distinctive: line 626
If the caller states the flag, the caller wins.
- Distinctive: line 633
Do NOT wait for Stage 5 to persist — if verify then crashes or the context runs out, the committed branch would otherwise be an orphan the …
- Very specific: line 662
Call fix-verify with refined_command (from Stage 2), target_repo_dir, and changed_files (from Stage 4).
- Distinctive: line 705
Always include in the summary:
- Very specific: line 718
If the outcome is IMPLEMENTING(fix_verified), the fix is committed on its fix branch (Branch naming) and recorded in fix_result.json.
- Very specific: line 756
Every run. The sign-off is outside </details> — it is the comment's footer, not part of the summary:
- Very specific: line 804
When the job ends, the fix workflow appends the <!-- agent:review --> block itself — the verdict menu a reviewer copies into a new comment.
- Distinctive: line 824
Do not loop on:
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Issue Handler — End-to-End Orchestrator
This is the high-level scenario skill for handling a single GitHub issue. It does not do the detailed work itself; it sequences the leaf skills into one iterative pipeline and reports the result. Each stage's mechanics live in its own skill — read and follow that skill when you reach its stage.
Every agent-produced diff is a proposal. This skill commits the
staged fix onto a dedicated local branch agent/fix-issue-<N> (single
bug) or agent/fix-issue-<N>-<seq>-<slug> (per batch sub-item) and
records it in a fix_result*.json. When the bug is owned by an upstream
issue — a mirrored pytorch/pytorch#<M> DISABLED test, or a command
pointing at an upstream issue — the branch is named after that
number instead: agent/fix-pytorch-issue-<M>[-<slug>] (see
Branch naming). It never
pushes, tags, or opens a PR — the invoking workflow reads each
fix_result*.json, exports base_sha..branch as a patch, and a human
applies it. The leaves themselves only stage (they never commit).
Contents
- Pipeline overview
- Inputs
- Execution modes
- Branch naming
- Stage 0: Re-run gate
- Stage 1: Triage
- Stage 2: Reproduce
- Stage 1u: Batch-issue fan-out (skip-list + heterogeneous)
- Stage 3: Root cause
- Stage 4: Implement
- Stage 5: Verify
- Stage 6: Report
- Iterative loop bounds
- Issue-body status contract
Pipeline overview
Single-bug path (default for issue_type=single-bug):
triage → reproduce → root-cause → implement → verify → report
↑ |
└─── loop up to 3 times ───┘Batch path (issue_type=batch-bug, either batch_kind) — fan out the
single-bug pipeline per sub-item, each on its own fix branch:
triage → [preflight: install nightly wheel once]
→ for each sub-item:
reset + reproduce
├─ NOT_REPRODUCED → heterogeneous: ALREADY_FIXED · skip-list: STALE_SKIP (+follow-up)
└─ REPRODUCED → branch per [Branch naming](#branch-naming)
→ root-cause → implement → verify
(any failure marks the sub-item and continues the batch)
→ fan-out reportskip-list vs heterogeneous differ only in how a NOT_REPRODUCED
sub-item is labeled; the loop is identical.
| Stage | Leaf skill | Purpose |
| 1. Triage | issue-triage | Text-only classification: single-bug / batch-bug (+ batch_kind) / nonbug, scope, runtime_dependencies, preliminary verdict |
| 2. Reproduce | fix-reproduce | Verify the failure still reproduces against the nightly wheel (stage=nightly) |
| 3. Root cause | fix-root-cause | Deep source analysis, target_repo, domain, IMPLEMENTING/NEEDS_HUMAN |
| 4. Implement | fix-implement | Edit code, stage the diff (never commit) |
| 5. Verify | fix-verify | Run the refined command against source build, PASSED/FAILED/CANNOT_VERIFY |
| 6. Report | this skill | Summarize outcome to the user (or into the issue in pipeline mode) |
Inputs
- A GitHub issue on
intel/torch-xpu-opsorpytorch/pytorch(URL, number, or raw body). pytorch_dir— path to a local pytorch checkout, resolved as described infix-reproducePrepare. If absent, this skill letsfix-reproduce/fix-root-causeclone it into$XPU_OPS_ROOT/agent_space_xpu/pytorch/.- Mode (see below).
Execution modes
The pipeline runs in one of two modes — interactive (default) or pipeline — which changes how every stage reports results and whether it writes to the GitHub issue. Decide the mode at the start and pass it to every leaf. See references/execution-modes.md for the full contract.
- Interactive (default): ask the user when blocked; report conversationally; do not touch the issue body / labels / comments unless the user asks.
- Pipeline (explicit): no human to interrupt — advance the
issue's
agent:statusmarker, update stage labels, let leaf skills leave their<!-- agent:<name> -->comments, and stop when the pipeline settles on a terminal verdict.
Branch naming
One rule for both paths: the branch is named after the issue that owns the bug, so a human reading a branch or a patch directory knows which issue a PR closes.
| The bug is filed as | Branch |
an intel/torch-xpu-ops issue #N | agent/fix-issue-<N> (batch sub-item: agent/fix-issue-<N>-<seq>-<slug>) |
an upstream pytorch/pytorch#<M> (mirrored DISABLED test, or a command naming an upstream issue) | agent/fix-pytorch-issue-<M> (batch sub-item: agent/fix-pytorch-issue-<M>-<slug>) |
The upstream form applies whenever the sub-item's own identity is an
upstream issue — the common case on the CI DISABLED tracking issue,
where #N is only a queue and #M is the bug. #M is already unique
and stable, so the upstream form carries no seq. When one fix covers
several sub-items, the branch is named after the sub-item that was fixed;
the rest are recorded in covers.
M is the upstream issue the sub-item resolves to: the
pytorch/pytorch#<M> reference on its checklist line, its linked child
reference, or the upstream issue named in the invoking comment. If a
sub-item has no upstream number, use the agent/fix-issue-<N>-… form.
A fix spanning both repos (two units)
carries this same name in both checkouts — one bug, one name; do not
suffix the branch with the repo. The repo shows up in the patch directory
instead, which the export step names <branch minus agent/>-<target_repo>:
agent/fix-pytorch-issue-197521 in each repo lands in
fix-pytorch-issue-197521-pytorch and
fix-pytorch-issue-197521-torch-xpu-ops. Two fix_result records naming
the same branch and the same target_repo are a naming bug, and the
export step fails there rather than overwrite one half (format-patch
restarts at 0001 in every directory).
Stage 0 — Re-run gate (first-run vs re-run)
Pipeline mode only; skip in interactive mode (a human is already
driving, so just run the full pipeline). An agent:active issue is
frequently re-triggered — a maintainer leaves feedback, or the bot is
re-invoked with no new information. This gate decides, before spending
a build, whether this is a fresh run, a human-feedback re-run
(highest priority), or a bare re-run (skip work that already ran and
is still valid).
Step 0.1: Detect prior agent activity
Find the most recent agent comment and its timestamp:
last_agent_ts=$(gh issue view "$N" --repo "$OWNER/$REPO" --json comments \
--jq '[.comments[] | select(.body | test("<!-- agent:"))] | last | .createdAt // ""')Empty last_agent_ts → first run. Skip the rest of Stage 0 and go
to Stage 1 normally.
Step 0.2: Detect new human feedback
A comment is human feedback when it is authored by a non-bot account
and created after last_agent_ts. (The bot account is the one that
authored the <!-- agent:* --> comments; exclude it by login.)
new_human=$(gh issue view "$N" --repo "$OWNER/$REPO" --json comments \
--jq --arg ts "$last_agent_ts" --arg bot "$BOT_LOGIN" \
'[.comments[] | select(.author.login != $bot and .createdAt > $ts)] | length')new_human > 0→ human-feedback re-run. Human feedback is the highest priority signal. Read every such comment verbatim and prepend it to the failure description you hand to Stage 3 (fix-root-causetakes a free-form failure description; a leading "Maintainer feedback since last run: ..." block steers the re-analysis without any new leaf input). Run the full pipeline from Stage 1; do not take any of the skip fast-paths below. A human saying "still wrong" or "change X" overrides any cached verdict.new_human == 0→ bare re-run. Continue to Step 0.3.
Step 0.3: Bare re-run — skip what is still valid
No human pointed anything out since the last agent comment, so re-doing the whole pipeline would just repeat identical work. Re-run only the cheap front of the pipeline and compare against last time:
- Run Stage 1 (triage) and Stage 2 (reproduce) as normal.
- Compare the reproduce result to the previous run. The previous
refined_command+ verdict are recoverable from the last<!-- agent:root-cause -->comment'sanalyzed_shacontext, or re-derived by reading the prior<!-- agent:reproduce -->/ sweep comment. "Identical" means same verdict and samerefined_command.- Reproduce differs (now passes, or a different command reproduces) → the situation changed on its own; resume the full pipeline from Stage 3 (root-cause) with the new reproduce result. Do not reuse the cached root-cause.
- Reproduce identical → nothing observable changed. Hand off to
Stage 3, which runs
fix-root-cause's own<!-- agent:root-cause -->analyzed_shafast-path: iftarget_repoHEAD sha equals the recordedanalyzed_sha, that leaf re-emits the prior verdict verbatim and this orchestrator stops (the earlier outcome — fix already staged, orNEEDS_HUMAN— still stands; there is nothing new to do). If the sha moved,fix-root-causere-analyzes and the pipeline continues from Stage 3 as usual.
This never skips Stage 1/Stage 2 — they are cheap (text + nightly wheel) and are the only way to notice the failure went away. It only avoids the expensive Stage 3-5 rebuild+fix when both the observable failure and the analyzed code are unchanged.
Stage 1 — Triage (issue-triage)
Call issue-triage on the issue body + comments. It emits
issue_type (single-bug / batch-bug / nonbug), batch_kind
(skip-list / heterogeneous / null), reproduction_missing
(yes / no), scope, runtime_dependencies, and a preliminary
handling (agent-fixable / needs-human).
Branch on issue_type (triage already made the batch-vs-nonbug call;
no re-detection here):
nonbug→ stop the fix pipeline; skip to Stage 6 Report withSKIPPED(reason=nonbug).single-bugwithreproduction_missing=yes→ stop; Stage 6 Report withNEEDS_HUMAN(reason=reproduction_missing).issue-triage's own comment already asks the reporter for a reproducer.single-bugwithreproduction_missing=no→ continue to Stage 2.batch-bug→ Stage 1u, passing throughbatch_kind(the loop uses it only to label aNOT_REPRODUCEDsub-item).
Stage 2 — Reproduce (fix-reproduce)
Only for the single-bug path (issue_type=single-bug). Call
fix-reproduce with:
reproducer_command— extracted byissue-triagefrom the issue body.stage=nightly— reproduce against the nightly wheel.ci_repo— inferred from repo (torch-xpu-opsfor issues on intel/torch-xpu-ops,pytorchfor pytorch/pytorch), or the value the bot passes explicitly.
Branch on its verdict:
REPRODUCED→ continue to Stage 3. Record therefined_commandandbasefor downstream stages.NOT_REPRODUCED→ the issue is stale; Stage 6 Report withSKIPPED(reason=no_longer_reproduces).NO_REPRODUCER→ Stage 6 Report withNEEDS_HUMAN(reason=no_reproducer).CANNOT_VERIFY→ Stage 6 Report withNEEDS_HUMAN(reason=cannot_verify)and theblockerfield.
Stage 1u — Batch-issue fan-out
One loop for every parent issue that tracks multiple children. The parent lists several sub-items; run the single-bug pipeline on each independently, each on its own fix branch, and report every outcome back on the parent. "Fix what you can" — a sub-item that can't be fixed is marked and the batch continues.
Entered for issue_type=batch-bug. issue-triage already set
batch_kind; the two kinds share the entire loop and differ only in how
a NOT_REPRODUCED sub-item is labeled (see step 2 below):
heterogeneous— the parent body lists distinct sub-bugs. ANOT_REPRODUCEDentry means that bug is ALREADY_FIXED (no longer reproduces); nothing to do.skip-list— aBug Skipissue listing homogeneous already-skipped tests. ANOT_REPRODUCEDentry means the test now passes, so its skip decorator is now stale and should be removed (follow-up).
No child GitHub issues are created. Each sub-item is a checklist entry on the parent; its fix lives on a dedicated branch so a human can open one PR per fixed sub-item.
Extract sub-items
Parse the parent body into a list of sub-items. Each is either:
- an inline sub-bug — a checklist line naming a test node id or
reproducer (skip-list entries are always this form; normalize a bare
Class::methodto a node id,fix-reproduce's Prepare step resolves the file), or - a linked child reference
owner/repo#N— fetch that issue and use its body as the sub-item's failure description. Only followintel/torch-xpu-opsandpytorch/pytorchreferences; ignore any other repo (untrusted, perfix-root-cause).
A sub-item may also arrive as a plain node id from the caller (a nightly
report, an email, a log excerpt): normalize Class::method to a node id,
drop blank lines, headers and comments, and collapse exact duplicates.
Split infra failures out before the loop. A runner crash, a docker
pull timeout, a full disk or a missing device is not a test failure and
will not reproduce. Record these as NEEDS_HUMAN(infra) and report
them; they never enter the loop.
Give each sub-item three identifiers used for branch naming:
seq— 1-based position in the body checklist order. Readable and maps a branch back to its body line. Not the stable identity (editing or reordering the body changes it).slug— the stable identity, derived from the sub-item's test node id: take the leaf method name, strip device suffixes (_cpu/_xpu/_cuda/_meta) and any dtype suffix, lowercase, keep[a-z0-9._-], truncate to 40 chars. If two sub-items produce the same slug, append-2,-3, … in body order so every slug is unique within the issue.upstream— thepytorch/pytorch#<M>number this sub-item is filed as, from its checklist line or its linked child reference; empty when there is none.
Name the branch per Branch naming: an upstream
sub-item gets agent/fix-pytorch-issue-<M>-<slug>, otherwise
agent/fix-issue-<N>-<seq>-<slug> (N = parent issue number). On a
re-run, match a sub-item to its prior branch by slug — look for an
existing agent/fix-*-<slug> branch; if found, that is the same
sub-item (rename it if its seq moved, never create a duplicate). Skip
headers, prose, and empty lines.
Preflight (many entries): install nightly wheel once
When the list is long (skip-list issues routinely have dozens),
front-load the one real wheel install so the per-entry
fix-reproduce(stage=nightly) calls each find the env already current
and return fast. fix-reproduce always issues pip install --pre
--upgrade (it refuses to trust a stale wheel); running it once here
does the real work. There is no skip_wheel_install flag — this is
purely an ordering optimization:
pip3 install --pre --upgrade torch torchvision torchaudio \
--index-url https://download.pytorch.org/whl/nightly/xpu
python -c "import torch; print('nightly:', torch.__version__)"One fix may cover several sub-items
Entries in a batch are often the same bug in the same class. Fixing each one separately runs root-cause and a source build (1-3 h) per entry and produces the same patch several times.
Do not guess which entries share a fix:
- Order the
REPRODUCEDentries so likely relatives sit together (same test class or file, same error). Ordering only; it decides nothing. - Fix the first entry.
- Re-run the other entries in that group against the staged fix. The
build is already done, so this costs one test run each.
fix-verifyalready produces a before/after table; extend it to the group. - Entries that now pass go in the fix's
coverslist and are not fixed again. Entries that still fail take their own turn from step 2.
One fix gets one branch and one fix_result.json, naming in covers
every entry it also fixed.
Per-sub-item loop
Capture the two base SHAs once, then for each sub-item reset both checkouts per the shared reset-between-entries recipe — a prior sub-item's staged diff must not bleed into the next.
For each sub-item:
- Reset both checkouts to the base SHAs (shared recipe).
Reproduce (
fix-reproduce). It detaches the pytorch tree to its base (origin/mainor theci_commitfallback) and returns thatbaseplus arefined_command.stagefollows the issue, likeallow_skip:- CI break (
pytorch-ci-failure, or a mirrored DISABLED test) →stage=auto. Many CI failures only reproduce on a source build.stage=nightlyreturnsNOT_REPRODUCEDas soon as the nightly wheel passes and does not fall through, which records unfixed work as already fixed. - Everything else →
stage=nightly.
Branch on the verdict:
REPRODUCED→ continue to step 3; keep itsbaseandrefined_command.NOT_REPRODUCED→ nothing to fix; record it and go to the next sub-item. The label depends onbatch_kind:heterogeneous→ ALREADY_FIXED: the reported bug no longer reproduces on latest nightly (upstream fixed it, or it was flaky). No action needed.skip-list→ STALE_SKIP: the test now passes, so its skip decorator is obsolete. Record a follow-up to remove the decorator — the orchestrator does not delete it here (see "Stale skips" below).
NO_REPRODUCER→ INVALID_ENTRY (renamed/removed test, or malformed). Record, continue.CANNOT_VERIFY→ UNVERIFIED (environmental). Record, continue.
- CI break (
Root-cause, then branch. Run Stage 3 (
fix-root-cause) first — it returnstarget_repo, which decides which checkout the fix (and thus the branch) lives in:target_repo=pytorch→target_repo_dir = pytorch_dir, base is the reproducebaseon the pytorch tree.target_repo=torch-xpu-ops→target_repo_dir = pytorch_dir/third_party/torch-xpu-ops, base isxpu_ops_base(the submodule's pinned commit from the shared recipe).fix-implement/fix-verifyhandle thexpu.txtpin rewrite internally; the orchestrator only creates the branch.
Create the isolated fix branch on
target_repo_diroff its base so the diff is pushable on its own (Branch naming):# upstream sub-item: branch="agent/fix-pytorch-issue-${M}-${slug}" branch="agent/fix-issue-${N}-${seq}-${slug}" git -C "$target_repo_dir" checkout -B "$branch" "$base"Then run Stage 4 → 5 (same contract and 3-attempt bound as the single-bug path).
fix-implementexpects exactly this: a fresh branch the orchestrator just created, clean worktree.- On any leaf
NEEDS_HUMAN/CANNOT_VERIFY/FAILED(or attempts exhausted): mark this sub-item blocked with the reason, record it, and continue to the next sub-item — never abort the whole batch on one hard sub-item. - On
fix-verifyPASSED: do NOT push or open a PR. Update the sub-item'sfix_result-${slug}.jsonin place (written atverdict=PENDING_VERIFYwhen the branch was committed) toverdict=PASSEDwithfix_repo_dir,branch,base_sha(the sub-item's base from step 3),changed_files, so the workflow can exportbase_sha..branchper sub-item. As in the single-bug path, commit the branch and write thePENDING_VERIFYrecord as soon asfix-implementreturnsREADY, not only on PASSED, so a crash mid-sub-item leaves a recoverable record instead of an orphan branch.
Stale skips (batch_kind=skip-list only)
A STALE_SKIP sub-item's skip decorator can be removed, but this
orchestrator does not delete it. Deleting a skip is itself a code
change that needs its own verify + PR; folding it into this sweep would
mix "the skip is obsolete" with "and here's the removal diff" and
obscure the batch outcome. Instead, surface every STALE_SKIP in the
report as an explicit follow-up (candidate for a human, or a separately
invoked fix-implement run to remove the decorator). The report is the
hand-off; nothing is auto-removed.
Fan-out report
Post one summary comment on the parent (or surface to the user in interactive mode), and mirror it into the parent's checklist:
<!-- agent:batch-fanout -->
## Batch fan-out results
Base: <torch nightly version or base sha>
| Sub-item | Outcome | Branch / Reason |
|---|---|---|
| test_bar_xpu_float32 | FIXED | agent/fix-issue-4321-1-test_bar |
| test_baz | NEEDS_HUMAN | needs a oneDNN change (`dependency component: oneDNN`) |
| test_qux | NEEDS_HUMAN | attempts_exhausted |
| test_new | ALREADY_FIXED | no longer reproduces on latest nightly |
| test_old | STALE_SKIP | follow-up: remove skip decorator |
| test_dup | COVERED | by test_bar's fix, agent/fix-issue-4321-1-test_bar |
| test_hard | SKIPPED | skip added, tracking issue intel/torch-xpu-ops#1234 |
| test_gone | INVALID_ENTRY | does not collect |
- **FIXED:** N sub-items — one branch each, ready for a human to open
a PR.
- **NEEDS_HUMAN:** M sub-items — see per-sub-item reason.
- **ALREADY_FIXED:** J sub-items (heterogeneous only) — no longer
reproduce; the reported bug is resolved, no action needed.
- **STALE_SKIP:** K sub-items (skip-list only) — the test now passes;
follow up to remove the obsolete skip decorator.
- **INVALID_ENTRY / UNVERIFIED:** P sub-items — malformed/renamed, or
environmental during reproduce.
*Automated by issue-handler.*Omit category rows that have no members (a heterogeneous batch has
ALREADY_FIXED but never STALE_SKIP, and vice versa). The
<!-- agent:batch-fanout --> marker lets a
re-run locate and update this same comment in place. On a re-run
(Stage 0), only re-process sub-items that are not already FIXED on a
live branch, unless human feedback (Stage 0.2) reopens a specific one.
After the loop, go to Stage 6 Report with the aggregate outcome
(IMPLEMENTING(fix_verified) if any sub-item was fixed;
NEEDS_HUMAN only if every actionable sub-item needed a human —
STALE_SKIP follow-ups do not by themselves force NEEDS_HUMAN).
Machine-readable outputs
Written on both paths: the single-bug Stage 4/5 writes
fix_result.json, and a batch fan-out writes batch_summary.json plus
one fix_result-<slug>.json per fixed sub-item. The
<!-- agent:batch-fanout --> comment is for humans; these files let the
invoking bot workflow export patches and drive re-verification without
re-parsing a comment.
They live under $AGENT_SPACE (the gitignored scratch dir). In pipeline
mode the bot workflow always sets it. In interactive mode it is usually
unset, which would resolve to /fix_result.json — so fall back to
<repo>/agent_space_xpu/ (the same gitignored dir AGENTS.md defines) and
report the path you used:
agent_space="${AGENT_SPACE:-$(git -C "$target_repo_dir" rev-parse --show-toplevel)/agent_space_xpu}"
mkdir -p "$agent_space"batch_summary.json— one file listing every sub-item:{ "issue": 4321, "kind": "batch-bug", "batch_kind": "heterogeneous", "sub_items": [ { "seq": 1, "slug": "test_bar", "outcome": "FIXED", "branch": "agent/fix-issue-4321-1-test_bar", "target_repo": "torch-xpu-ops", "fix_result": "fix_result-test_bar.json", "companion": "fix_result-test_bar-pytorch.json", "summary": "one-line what/why" }, { "seq": 2, "slug": "test_baz", "outcome": "NEEDS_HUMAN", "branch": null, "reason": "other", "reason_detail": "needs a oneDNN change (dependency component: oneDNN)" }, { "seq": 3, "slug": "test_new", "outcome": "ALREADY_FIXED", "branch": null, "reason": "no longer reproduces on latest nightly" } ] }fix_result-<slug>.json— for eachFIXEDsub-item, the same schema the single-bug Stage 5 writes asfix_result.json. It MUST include the keys the workflow's schema gate and patch-export read:verdict—PASSED/FAILED/CANNOT_VERIFY/PENDING_VERIFY. Written incrementally: Stage 4 writesPENDING_VERIFYwhen it commits the branch, Stage 5 updates it to the terminal verdict. OnlyPASSEDis exported as a normal patch; a non-PASSED verdict that still names a reachablebranch+base_shais salvaged as anunverified/patch so the committed work is not lost with the runner. Keepbranchandbase_shaaccurate even on a non-PASSED record.target_repo—torch-xpu-ops|pytorch,fix_repo_dir— absolute path of the git repo holding the fix commit,branch— per Branch naming,base_sha— the commit the fix branch was started from,changed_files— list of the files the fix touched,depends_on— the fix_result file that must land BEFORE this one, or absent. It is the only record of the order (see below). plusneeds_build,refined_command,notes. Suffixed by slug so each sub-item can be exported / re-verified independently.
A fix spanning both repos (fix-root-cause returned a
companion_repo) is two units:
- one branch per repo, named after the issue as usual,
- one fix_result per repo, the companion's being the primary's name plus
-<target_repo>(fix_result-grid_sample-pytorch.json), depends_onon the companion, naming the primary's file,- one verdict for both, and
notessaying the pair was verified together, batch_summary's sub-item points at the unit that fixes the test.
The patch-export step iterates every fix_result*.json and emits one
patch series per unit from base_sha..branch (the branches are not
pushed); batch_summary.json enriches it (target_repo, summary line).
A unit that reports a verified fix but yields no patch fails the step.
Stage 3 — Root cause (fix-root-cause)
Called on the single-bug path, and once per sub-item from Stage 1u.
Call fix-root-cause with the failure description and the
refined_command from Stage 2.
Branch on its verdict:
IMPLEMENTING(reason=ok)→ recordtarget_repo,domain,analyzed_sha,root_cause,fix_strategy, then create the fix branch before Stage 4 —target_repois what decides which checkout it lives in, andfix-implementexpects a fresh branch with a clean worktree ($baseis Stage 2's reproduce base; the batch path already did this in its own step 3, with its own branch name):# upstream-filed bug: branch="agent/fix-pytorch-issue-${M}" branch="agent/fix-issue-${N}" git -C "$target_repo_dir" checkout -B "$branch" "$base"NEEDS_HUMAN→ Stage 6 Report, carrying the leaf's one-linereason_detailas the justification — that is what a maintainer reads. Every reason lands on the same terminal status (NEEDS_HUMAN/agent:needs-human), so do not shop for a code: the two worth branching on areno_registered_domain(do not retry, see Retry policy) andinvalid_reproduction(re-run Stage 2 first).
Stage 4 — Implement (fix-implement)
Call fix-implement with triage_result, pytorch_dir,
target_repo_dir (derived from target_repo), and allow_skip:
allow_skip follows the issue:
- CI break — the issue carries the
pytorch-ci-failurelabel, or mirrors a DISABLED test from pytorch/pytorch.allow_skip=true. Fix it in place where you can, in pytorch or here. Skip only when the fix needs a dependency, information you do not have, or feature-sized work;fix-implementthen files a tracking issue for the real fix. - Everything else —
allow_skip=false. Never add a skip decorator.
If the caller states the flag, the caller wins.
Branch on the verdict:
READY(reason=ok)→ commit the staged fix onto the branch created in Stage 3, and write the incrementalfix_result.json, then continue to Stage 5. Do NOT wait for Stage 5 to persist — if verify then crashes or the context runs out, the committed branch would otherwise be an orphan the Export step flags as a lost fix. Committing here keeps the branch and the hand-off record in lock-step:git -C "$target_repo_dir" commit -m "fix: <one-line summary> (#${N})"Then write
fix_result.json(see "Machine-readable outputs" for the path and its interactive-mode fallback) with the fields known so far andverdict=PENDING_VERIFY:target_repo,fix_repo_dir,branch,base_sha,changed_files,analyzed_sha,root_cause,notes. The branch is local and dies with the runner, so this record is what lets the workflow salvage the commit as anunverified/patch if verification never finishes — without it, a crash after this point loses the work outright.With a
companion_repo, do this twice,target_repofirst: callfix-implementagain withtarget_repo_dirset to the companion checkout, branch off that repo's HEAD, commit, and write its record per "Machine-readable outputs".NEEDS_HUMAN→ Stage 6 Report, carrying the leaf'sreason_detailas the justification. The label isagent:needs-humanwhatever thereason(skip_outside_target_repo/skip_guard_rejected/no_fix_possible/ etc.).
Stage 5 — Verify (fix-verify)
Call fix-verify with refined_command (from Stage 2),
target_repo_dir, and changed_files (from Stage 4). fix-verify
unconditionally produces the FAIL->PASS before/after table and runs
spin fixlint on a passing result — no flags to pass.
A two-repo fix is verified once, as a pair — one tree, one build. Both records take that verdict.
Branch on the verdict:
PASSED(reason=ok)→ the fix is verified. The branch andfix_result.jsonalready exist from Stage 4; update the record in place — setverdict=PASSEDand addneeds_build, the before/after result, and any finalnotes— then go to Stage 6 withIMPLEMENTING(fix_verified).fix-verifyleaves itsspin fixlintfixes staged: amend them into the Stage 4 commit (git commit --amend --no-edit) so they reach the exported patch — never a second commit. The workflow exportsbase_sha..branchas the patch. Never push or open a PR.FAILED→ loop back to Stage 4 with the failure output as additional context (see "Iterative loop bounds"). On a retry the branch already carries the previous attempt's commit, so amend it (git commit --amend --no-editafter staging the new edits) rather than creating a second commit or a new branch —base_sha..branchmust stay a single reviewable fix, and Stage 5's clean-worktree assertion requires nothing left uncommitted. If attempts are exhausted, updatefix_result.jsontoverdict=FAILEDwith the last failure innotesso the record explains the branch, then Stage 6 ReportNEEDS_HUMAN(reason=attempts_exhausted).CANNOT_VERIFY→ updatefix_result.jsontoverdict=CANNOT_VERIFYwith the blocker innotes, then Stage 6 ReportNEEDS_HUMAN(reason=<verify's reason>). Do not loop on CANNOT_VERIFY — the environment problem will not fix itself.
Stage 6 — Report
At the end, summarize the outcome. In interactive mode present
this to the user in plain language. In pipeline mode advance
the issue's agent:status to the terminal stage
(DONE / NEEDS_HUMAN / SKIPPED) and update the checklist per
execution-modes.md; a batch fan-out
run also posts the <!-- agent:batch-fanout --> summary.
Always include in the summary:
- Issue: link/number and one-line title.
- Path:
single-bug/batch(withbatch_kind). - Outcome:
IMPLEMENTING(fix_verified)/NEEDS_HUMAN(<reason>)/SKIPPED(<reason>). - Root cause (from Stage 3, if reached).
- Files changed (from Stage 4, if reached).
- Verification (from Stage 5, if reached).
- For a batch: per-sub-item outcome + branch name (FIXED) or reason
(NEEDS_HUMAN / ALREADY_FIXED / INVALID_ENTRY / UNVERIFIED), plus any
STALE_SKIPfollow-ups whenbatch_kind=skip-list.
If the outcome is IMPLEMENTING(fix_verified), the fix is committed on
its fix branch (Branch naming) and recorded in
fix_result.json. The invoking workflow reads that, exports
base_sha..branch as a patch
artifact, and a human applies it. Do not push or open the PR from this
skill.
batch-fanout and summary block templates
Both are this skill's own blocks, so write them collapsed as shown —
there is no ## heading to strip, unlike the leaf blocks this skill
wraps.
Batch runs only:
<!-- agent:batch-fanout -->
<details>
<summary><b>Batch fan-out results</b></summary>
Base: `torch-xpu-ops@<short_sha>`, pytorch `origin/main@<short_sha>`
(reproduce base: nightly `<wheel version>`)
| Sub-item | Outcome | Branch / Reason |
|---|---|---|
| 4. `test_foo_xpu_float8_e4m3fn` | FIXED | `agent/fix-pytorch-issue-197334-test_foo` |
| 5. `test_foo_xpu_float8_e5m2` | COVERED | by sub-item 4's fix, same branch |
- **FIXED:** <n> sub-items — <what a human should do with the branches>
- **COVERED:** <n> sub-items — <why no separate branch>
- **NEEDS_HUMAN / STALE_SKIP / INVALID_ENTRY / UNVERIFIED:** none.
*Automated by issue-handler.*
</details>Every run. The sign-off is outside </details> — it is the comment's
footer, not part of the summary:
<!-- agent:summary -->
<details>
<summary><b>Summary</b></summary>
<2-4 sentences: the one bug behind the sub-items, the fix in one clause,
and what verification showed. No bullets.>
- **Branch:** `agent/fix-issue-<N>[-<seq>-<slug>]`, or
`agent/fix-pytorch-issue-<M>[-<slug>]` for an upstream-filed bug
- **Base:** `<full 40-char sha>`
- **Changed files:** `path/to/file.cpp`
- **Nothing was pushed.** The patch is exported as a workflow artifact for
a human to review and apply.
</details>
_Generated by [fix job](<run url>)._A two-repo fix needs the order spelled out, or whoever opens the PRs gets it wrong and breaks CI. At the top of the Summary body:
> [!IMPORTANT]
> **Two PRs, in this order.**
> 1. `<lands-first repo>` — patch dir `<branch>-<repo>`.
> 2. `<companion repo>` — patch dir `<branch>-<repo>`, after <what it waits
> on, e.g. the `xpu.txt` pin bump carrying step 1>.
>
> **No closing keyword in either PR** (`Fixes` / `Closes` / `Resolves`):
> merging one would close the issue with the other half still out. Reference
> the issue plainly; a human closes it once both have landed.and one line outside </details>, above the _Generated by_ footer,
since that block renders collapsed:
**Two patches, and the order matters — see Summary.**Review request block
When the job ends, the fix workflow appends the <!-- agent:review -->
block itself — the verdict menu a reviewer copies into a new comment.
Do not write it yourself, and do not restate it here: the template
lives in bot.yml and a second copy only drifts from it.
Iterative loop bounds
The pipeline is not strictly linear. Loop when a later stage invalidates an earlier assumption:
- Stage 5
FAILED→ return to Stage 4 (refine the fix). - Stage 4's Step 3.5 skip-guard rejects → the leaf itself re-runs
once; a second rejection returns
NEEDS_HUMANand the orchestrator does not retry.
Bound: maximum 3 fix attempts (Stage 4 → Stage 5 → Stage 4 …).
This matches the legacy pipeline's max_agent_attempts. When you
stop without success, report NEEDS_HUMAN(reason=attempts_exhausted)
with the last fix-verify failure output in reason_detail.
Do not loop on:
CANNOT_VERIFYat any stage (environment problem, not fix problem).NEEDS_HUMANfrom any leaf (contract: the leaf already decided it needs a human).- Stage 3
no_registered_domain(domain registry is a fixed set, looping won't unstick it).
Issue-body status contract
Pipeline mode only. In interactive mode, do not touch the issue body/markers/labels unless the user asks — report to the user instead.
This orchestrator owns advancing the overall <!-- agent:status:X -->
marker through:
DISCOVERED → TRIAGING → REPRODUCING → TRIAGED → IMPLEMENTING →
VERIFYING → DONEwith terminal alternates NEEDS_HUMAN and SKIPPED. Stage-by-stage
mapping to labels is in
references/execution-modes.md; each
leaf skill owns its own <!-- agent:<name> --> comment/log slot,
this orchestrator owns the overall agent:status marker + the
Action Items checklist.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

