| name | issue-triage |
| description | Build and run a system for handling incoming issues. Use when an issue backlog has become unmanageable, when setting up issue templates or a label taxonomy, when deciding what to close, when configuring stale bots or automation, or when the user asks "how do I deal with all these issues". Covers issue forms, a minimal label set, triage rotation, converting issues to discussions, writing closing messages that don't burn people, duplicate handling, and turning recurring issues into documentation or code changes. |
Issue Triage
An untriaged backlog is not a to-do list — it is a public record of requests you are
ignoring. Every issue is either actionable, waiting on someone, or should be closed.
There is no fourth state, and "open forever" is the one that quietly costs you
contributors.
Issue forms beat templates
.yml forms produce structured, complete reports. Markdown templates get deleted by
the reporter and produce "it doesn't work".
name: Bug report
description: Something isn't working
labels: ["bug", "needs-triage"]
body:
- type: markdown
attributes:
value: |
Thanks for the report. Please check [existing issues](../issues?q=is%3Aissue) first.
- type: input
id: version
attributes: { label: Version, placeholder: "4.2.0" }
validations: { required: true }
- type: textarea
id: repro
attributes:
label: Reproduction
description: Minimal steps or a link to a minimal repo. This is the field that determines whether we can help.
validations: { required: true }
- type: textarea
id: expected
attributes: { label: Expected vs actual }
validations: { required: true }
- type: input
id: env
attributes: { label: OS and runtime, placeholder: "macOS 15.3, Node 22.11" }
Also add .github/ISSUE_TEMPLATE/config.yml to route non-bugs away from the tracker:
blank_issues_enabled: false
contact_links:
- name: Question or help
url: https://github.com/OWNER/REPO/discussions/categories/q-a
about: Ask in Discussions — questions here will be converted.
- name: Security vulnerability
url: https://github.com/OWNER/REPO/security/advisories/new
about: Report privately. Do not open a public issue.
Keep forms short. Every required field costs you some fraction of reports, and a bug
you never hear about is worse than one reported imperfectly. Three fields that matter
beat nine that produce abandonment.
A label set you will actually maintain
Most projects have 40 labels and use six. Start minimal and add only on demonstrated need.
| Group | Labels | Purpose |
|---|
| Type | bug feature docs question chore | What kind of work |
| State | needs-triage needs-repro needs-decision blocked | Whose turn it is |
| Priority | p0-critical p1 p2 | Only if you honor it |
| Contributor | good first issue help wanted | Discoverability — GitHub surfaces these |
| Resolution | wontfix duplicate stale | Why it closed |
Rules: every open issue carries exactly one state label, so a query tells you
whose turn it is. Only use priority labels if you triage by them — a p0 sitting for
six months is a lie in public.
good first issue is the highest-value label in the set, and only if the issues under
it are real: a specific, self-contained task with a pointer to the relevant file and
an expected approach. A good first issue that turns out to require architectural
context is a broken promise to a newcomer (see contributor-experience).
The triage pass
Do this on a schedule — 20 minutes, twice a week, beats a four-hour purge once a
quarter. For each needs-triage issue:
- Duplicate? Link to the original and close. Comment on the original so the
reporter is subscribed to the real thread.
- A question? Convert to a Discussion (GitHub does this natively, preserving
the thread and the author).
- Bug without a reproduction? Label
needs-repro, ask for specifics. If nothing
arrives in 30 days, close with an explicit invitation to reopen.
- Reproducible bug? Label, add to a milestone if you will fix it, or
help wanted
if you will not.
- Feature request? Decide: accept (milestone), decline (close, with the reason),
or defer (
needs-decision and say when you will decide). Deciding slowly is the
expensive option — the reporter and any would-be implementer are both blocked.
- Already fixed on main? Say which release will contain it, and close.
gh issue list --label needs-triage --limit 50
gh issue list --search "is:open no:label" --limit 50
gh issue list --search "is:open updated:<2025-08-01" --limit 50
gh issue list --search "is:open label:\"good first issue\" no:assignee"
Automation worth having
- Auto-label from the form (
labels: in the form frontmatter).
- Comment on first-time contributors (
actions/first-interaction) — a warm, short
greeting with a link to CONTRIBUTING.md.
- Auto-close
needs-repro after 30 days of silence, with a message that clearly
invites reopening.
- Duplicate detection on similar titles — as a suggestion for the triager, not an
auto-close.
Automation not worth having:
- A stale bot on everything. Closing valid bugs because nobody had time is a
message to your users: your report was noise. It also destroys the search value of
your tracker. If you must run one, exclude
bug, security, help wanted, and
anything with a reproduction, and set the window to months not weeks.
- Auto-closing PRs. Never. See
code-review.
- Templates so strict that reporting a typo requires a version number and an OS.
Closing messages that don't burn people
Closing is a normal, healthy operation. How you do it determines whether that person
files a second issue.
# Duplicate
Thanks — this is the same underlying issue as #412, so I'll close here and keep the
discussion there. I've linked your reproduction, which is more complete than the
original; it'll be useful when we fix it.
# Out of scope
Thanks for the suggestion. I'm going to pass on this one: it would mean owning
<X>, and keeping this project focused on <Y> is a deliberate constraint (noted in
the README under Scope). A plugin could do this using the `onParse` hook — happy to
help if you build one.
# Can't reproduce
I haven't been able to reproduce this on <versions tried> — steps I took: <...>.
Closing for now, but please reopen with a minimal repo or the exact input and I'll
take another look. Not a dismissal; I just don't have enough to work with yet.
# Won't fix, deliberate behavior
This is intentional: <reason>. I can see why it's surprising, so I've opened #520 to
document it. You can get the behavior you want with <workaround>.
Common structure: thank, give a specific reason, take responsibility for anything
that was your project's fault, offer a next step. Never close silently, and never
close with just a label.
Backlog bankruptcy
If the backlog is past a few hundred stale issues and triage feels impossible, a
declared reset is legitimate — but do it honestly, once:
- Announce it in a pinned issue: what you are doing and why.
- Close everything untouched for over a year with a clear message: this is a capacity
decision, not a judgment on the report, and reopening is one comment away.
- Set the criteria you will maintain going forward, and publish them.
- Then actually maintain them. A second bankruptcy declaration means the process
is the problem, not the backlog.
The real point of triage
Triage is not queue management; it is detecting patterns. Five issues about the
same confusing flag is not five issues — it is one design or documentation bug.
- Three reports of the same misunderstanding → a docs page (
docs-architecture)
- Repeated confusion about an API → the API is wrong (
api-design)
- The same error message misread repeatedly → rewrite the error message
- Frequent "how do I..." → a how-to guide, and a link from the error output
Every issue you prevent is worth ten you close.
Anti-patterns
- No triage. A backlog nobody reads is a signal that the project is unmaintained.
- Stale-botting valid bugs.
- Closing without a reason.
p0 labels on issues that sit for months.
- 40 labels, 6 in use.
- Answering the same question 20 times instead of writing the page once.
- Letting a feature request sit undecided for a year. Say no faster; it is kinder.
- Arguing with an angry reporter. Answer the technical content, ignore the tone,
and enforce the Code of Conduct if it crosses a line (see
governance-and-sustainability).
good first issue on something that needs architecture context.