9ccaa2aa chore(repo): add the triage-issues skill
A repo-facing workflow for triaging nrwl/nx issues: apply the labels that
make an issue count as triaged, ask for a reproduction when one is
missing, run it when one exists, and propose a priority and an owner.
Every mutation is staged through .claude/tools/triage for a human to
approve; the skill never writes to GitHub itself.
The definition of "triaged" is not a convention here. Any open issue with
no `scope:` label increments untriagedIssueCount in
scripts/issues-scraper/scrape-issues.ts, which issue-notifier.yml posts to
Slack weekly, so the queue query mirrors that scraper exactly.
Things the skill encodes because they are easy to get wrong:
- A `blocked:` label is an eviction timer, not a note. schedule-stale.yml
gives 7 days to `stale` and 21 more to closed. Removing one when the
reporter answers is a triage duty, since the bot only strips `stale`.
- `stale` and `outdated` are bot-owned and must never be set by hand.
- closedByPullRequestsReferences finds a PR already in flight, including
on open issues. Scraping /timeline for cross-referenced events does not.
- The scope table is built from how maintainers actually label, not from
the label descriptions: `scope: bundlers` reads "webpack, rollup" but
covers vite, esbuild, rspack and rsbuild too.
- A `Steps to Reproduce` section containing only `1.` is the bug form's
seeded default, not a reproduction. No labels at all means the issue was
filed outside the form, so none of its required fields are guaranteed.
- Before proposing `community`, check the fix is contributable. The repo
does ship graph UI source under graph/, but those packages import the
published closed-source @nx/graph, so "it's a graph bug" decides nothing.
references/labels.md holds the scope map and close reasons;
references/replies.md holds comment templates. 9ccaa2aa chore(repo): add the triage-issues skill
A repo-facing workflow for triaging nrwl/nx issues: apply the labels that
make an issue count as triaged, ask for a reproduction when one is
missing, run it when one exists, and propose a priority and an owner.
Every mutation is staged through .claude/tools/triage for a human to
approve; the skill never writes to GitHub itself.
The definition of "triaged" is not a convention here. Any open issue with
no `scope:` label increments untriagedIssueCount in
scripts/issues-scraper/scrape-issues.ts, which issue-notifier.yml posts to
Slack weekly, so the queue query mirrors that scraper exactly.
Things the skill encodes because they are easy to get wrong:
- A `blocked:` label is an eviction timer, not a note. schedule-stale.yml
gives 7 days to `stale` and 21 more to closed. Removing one when the
reporter answers is a triage duty, since the bot only strips `stale`.
- `stale` and `outdated` are bot-owned and must never be set by hand.
- closedByPullRequestsReferences finds a PR already in flight, including
on open issues. Scraping /timeline for cross-referenced events does not.
- The scope table is built from how maintainers actually label, not from
the label descriptions: `scope: bundlers` reads "webpack, rollup" but
covers vite, esbuild, rspack and rsbuild too.
- A `Steps to Reproduce` section containing only `1.` is the bug form's
seeded default, not a reproduction. No labels at all means the issue was
filed outside the form, so none of its required fields are guaranteed.
- Before proposing `community`, check the fix is contributable. The repo
does ship graph UI source under graph/, but those packages import the
published closed-source @nx/graph, so "it's a graph bug" decides nothing.
references/labels.md holds the scope map and close reasons;
references/replies.md holds comment templates.