# Issue Triage

> Shallow, text-only triage of a GitHub issue on pytorch or torch-xpu-ops. Classifies the issue and returns a report (markdown table + JSON) for the caller to act on. Read-only; the skill itself does not comment on or label the issue.

- Skill: `intel/issue-triage` (Agent Skill)
- Install (CLI): `npx skillmds@latest add intel/issue-triage`
- Raw SKILL.md: https://api.skillmd.com/api/skills/intel/issue-triage/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Docs & Writing
- Author: intel (https://skillmd.com/u/intel)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/intel/issue-triage

---


# Issue Triage — Shallow Classification & Handling Decision

Text-only triage. Reads the issue title, body, and labels. Does NOT read
source code, does NOT run tests, does NOT open PRs, does NOT modify the
issue in any way (no comments, no labels, no body edits).

Produces a single **report** returned to the caller, containing:

1. A markdown table with the classification fields.
2. A JSON summary with the same fields as structured data.

The caller (a bot job, an orchestrator skill, or a human) decides what to
do with the report: post it as a comment, apply labels, feed it into a
larger pipeline, or just read it.

`Handling` (agent-fixable vs needs-human) is derived from the other
signals — see "Step 5" below. Deep root-cause analysis and any override
of this decision happens later in a downstream skill (out of scope for
this skill).

## Inputs

- A GitHub issue: URL, number, or raw title+body+labels. If given a
  number or URL, fetch it:

  ```bash
  gh issue view "$N" --repo "$OWNER/$REPO" --json title,body,labels
  ```

- Read-only. This skill never writes to the repository — no comments,
  no labels, no file edits. The only side effects are the `gh issue
  view` read above and printing the report to stdout.

## Shell helpers

Recipes below assume one helper is in scope:

```bash
abort() { echo "ABORT: $*" >&2; exit 1; }
```

## Preflight

`gh` must be authenticated with read access to the target repo:

```bash
gh auth status 2>&1 | grep -q "Logged in to github.com" \
  || abort "gh not authenticated; run: gh auth login"
```

No write scope is required — this skill only reads.

## Step 1: Classify issue_type

- **single-bug** — a single failure: test failures, runtime errors,
  assertion errors, incorrect output, crashes.
  Indicators: error tracebacks, failing test names, `RuntimeError`,
  `AssertionError`, "fails with", `### 🐛 Describe the bug`, test logs.

- **batch-bug** — a parent issue tracking *multiple* child failures
  rather than describing one. Two `batch_kind`s:
  - `skip-list` — a "Bug Skip" tracking issue asking whether a list of
    already-skipped tests should still be skipped. Indicators: `Bug
    Skip` in the title/template, `agent_test: skip-list` label, body is
    a checklist of test node ids (often with `~~strike-through~~` for
    entries already resolved), no fresh traceback. Homogeneous — every
    entry is the same kind of skipped test.
  - `heterogeneous` — a parent/umbrella issue whose body lists
    *distinct* sub-bugs, each with its own reproducer, test node id, or
    linked child issue reference (`owner/repo#N`). Indicators:
    `[Umbrella]` / `[Tracking]` in the title, a checklist where each
    item names a *different* test/error, a "Tasks" / "Sub-issues"
    section of `#N` references.

- **nonbug** — feature requests, tasks, performance issues, questions,
  discussions, enhancement proposals, feature gaps. Indicators:
  "Enable", "[Task]", "Consider", "Align", "feature gap",
  "clarification", `enhancement` label, `performance` label, no failing
  tests. A checklist of *work items* (things to build) is `nonbug`; a
  checklist of *failing tests / sub-bugs* is `batch-bug`.

**Labels are authoritative** — if labels say `agent_test: skip-list`,
`issue_type = batch-bug` with `batch_kind = skip-list` regardless of
body content.

## Step 2: Detect `reproduction_missing`

Report `yes` when the issue lacks all of:

- A reproducer command (pytest node id, `python -c ...`, shell command).
- A test node id reference (e.g. `test_foo.py::TestBar::test_baz`).
- A minimal code snippet that triggers the failure.

Report `no` when at least one of the above is present.

Batch-bug issues list child test node ids / sub-bug references in their
body, so they satisfy the second bullet and report `no`.

## Step 3: Estimate `scope`

Based on issue text alone (no source reading):

- **`pytorch`** — issue explicitly points at pytorch code (`torch/`,
  `aten/`, `torch/_inductor/`, `torch/_dynamo/`), a pytorch PR, or a
  framework-level regression.
- **`torch-xpu-ops`** — issue explicitly points at torch-xpu-ops code
  (`src/ATen/native/xpu/`, XPU kernels, SYCL implementations), or a
  ported CUDA test failing on XPU due to a kernel gap.
- **`both`** — issue text names changes needed in BOTH repos (e.g.
  pytorch API addition + XPU implementation of that API).
- **`unclear`** — issue text does not specify. This is the common case
  for most bug reports; a downstream deep-triage skill will decide
  after reading source.

## Step 4: Detect `runtime_dependencies`

Scan the issue body, error log, environment section, and labels for
explicit mentions of external runtime dependencies. Closed set:

| Value | What it means |
|---|---|
| `triton` | Inductor / torch.compile GPU codegen backend. |
| `onednn` | Intel oneDNN library (matmul, conv, etc.). |
| `onemkl` | Intel oneMKL library (BLAS, LAPACK, sparse). |
| `driver` | GPU driver, level-zero, compute-runtime, `libze_intel_gpu.so`. |
| `sycl` | SYCL runtime / DPC++ compiler. |
| `xccl` | XCCL communication library. |

Only report dependencies **explicitly named** in the issue. Do NOT infer
from a stack-trace path alone (e.g. a traceback through
`torch._inductor` does not by itself imply `triton` — the issue must
say so or show a triton-side error).

Empty array `[]` when none are named.

## Step 5: Derive `Handling`

Evaluate in order; first match wins:

1. `issue_type` is `nonbug` → **needs-human**
   (reason: `"not a bug / task issue"`). `batch-bug` does NOT match
   this rule — a batch of sub-bugs is handled by the orchestrator's
   fan-out, per-sub-item; do not force it to needs-human here.
2. `reproduction_missing == yes` → **needs-human**
   (reason: `"no reproducer or test-name reference"`).
3. `runtime_dependencies` is non-empty → **needs-human**
   (reason: `"runtime dependency requires human triage: <list>"`).
4. Issue explicitly requires hardware or a non-public model/dataset the
   agent cannot access → **needs-human**
   (reason: names the missing resource).
5. Otherwise → **agent-fixable**.

`scope=both` and `scope=unclear` do NOT force needs-human — a
downstream deep-triage skill decides the final target repo.

## Step 6: Return the report

Emit both a markdown block and a JSON block to stdout, in that order,
separated by a blank line. The caller reads one, both, or neither.

### 6a. Markdown block

Assemble this exact structure (values from Steps 1–5). This is what a
caller would paste as a comment:

```markdown
<!-- agent:triage -->

## Issue Triage

| Field | Value |
|-------|-------|
| Reproduction missing | yes / no |
| Scope | pytorch / torch-xpu-ops / both / unclear |
| Dependencies | comma-separated list, or (none) |
| Handling | agent-fixable / needs-human |

**Reason:** <one-line, only when handling=needs-human>

*Automated by issue-triage.*
```

Each `Value` cell above lists the allowed choices; emit exactly one of
them. Never leave a literal `|` inside a cell — it splits the cell and
breaks the rendered table.

Include the `<!-- agent:triage -->` marker on the first line so a
downstream caller can locate its own previous comment (if any) and
update it in place. The marker is part of the report; the skill does
not consume it.

Omit the `**Reason:**` line entirely when `handling == agent-fixable`.

### 6b. JSON block

Immediately after the markdown block (with one blank line between),
emit:

```json
{
  "issue_type": "single-bug | batch-bug | nonbug",
  "batch_kind": null,
  "reproduction_missing": true | false,
  "scope": "pytorch | torch-xpu-ops | both | unclear",
  "runtime_dependencies": [],
  "handling": "agent-fixable | needs-human",
  "reason": "",
  "suggested_labels": []
}
```

Field notes:

- `batch_kind` is `"skip-list"` or `"heterogeneous"` when
  `issue_type == "batch-bug"`, and `null` otherwise. The orchestrator
  routes batch fan-out on it (no re-derivation needed downstream).
- `reproduction_missing` is a JSON boolean: `true` for the `yes` shown
  in the table, `false` for `no`.
- `runtime_dependencies` is an array from the closed set in Step 4;
  empty `[]` when none named.
- `reason` is required non-empty when `handling == needs-human`, empty
  string when `handling == agent-fixable`.
- `suggested_labels` lists the labels a caller might apply to the
  issue. Advisory only — the skill does not apply them. Populate per
  the rules below.
- Do NOT invent values not derived from the issue text.

### 6c. Suggested labels

`suggested_labels` is populated as follows:

- If `handling == "needs-human"` → include `agent:needs-human`.
- Empty array otherwise. A missing reproducer needs no label of its
  own: the orchestrator reports it as `SKIPPED(reproduction_missing)`
  and applies `agent:skipped`.

Scope and dependency values live in the JSON structure, not as labels.

## HARD RULES

- **Never modify the issue.** No comments, no labels, no body edits.
  The caller applies changes based on the report.
- **Never read source or run tests.** This skill's contract is
  text-only shallow triage. Deep source-reading analysis belongs to a
  separate downstream skill.
- **Emit exactly one markdown block and one JSON block to stdout,** in
  that order. Nothing else. No prose intro, no closing summary. The
  caller parses stdout; extra text corrupts the parse.

