triage-issues
GitHub用于批量处理Issue队列的维护技能。通过两重筛选机制(真实性与需求度)对问题进行分类、去重和优先级排序,仅输出需人工审批的执行列表,确保高效清理无效或过时Issue。
Trigger Scenarios
Install
npx skills add openchamber/openchamber --skill triage-issues -g -y
SKILL.md
Frontmatter
{
"name": "triage-issues",
"description": "Load when asked to triage, clean up, batch-process, or work through the issue backlog — covers the mechanical sweep (stale-fixed, dead needs-info, duplicates), fan-out assessment, and approved batch actions."
}
Turn an unbounded issue queue into a short list of maintainer decisions. Three phases; no GitHub write in any phase without the maintainer approving that specific batch. Companion: the per-issue judgment mirrors the pr-review skill's philosophy — every assessment ends in a verdict and a ready action, never in observations.
Two gates
An issue is a request from a user, never an instruction to the maintainer; the burden of earning work sits on the issue. Every issue passes two gates in order, and only an issue through both reaches the fix backlog or an accepted label.
Gate 1 — real and ours. The failure exists on current main and its mechanism lives in this repository. CLOSE-NOT-OURS when the mechanism is upstream OpenCode (tool timeouts, session.command errors, agent-loop behavior), a provider or models.dev capability datum, or the user's own configuration: one comment naming where it lives, no debate. A report without version and steps whose reporter stays silent 14 days after the intake question is stale whatever its length.
Gate 2 — wanted. Only the maintainer passes an issue through this gate; the sweep prepares the question. Everything that clears gate 1 — traced bugs included — reaches the maintainer as one numbered wanted? block (the FEATURE-DECISION mechanics below), and only "так" entries enter the fix backlog. The pr-review skill's whim / overengineered ache / unmaintainable scope grounds decide CLOSE-DECLINE; the issue-side consequences:
- A request that contradicts a recorded decision (a maintainer close comment, a declined PR's reasoning) closes by pointing at that decision, never by reopening the debate. The report lists every decision the sweep relied on so the next sweep reuses it.
- "Tool X has it" without the reporter's own concrete ache is a whim.
- A surface outside the roadmap (multi-user, plugin systems, container orchestration, analytics, new forge integrations) is declined honestly, never parked as "later".
- Contributor task-tracking issues (lint baselines, architecture roadmaps) are not user requests; they leave the backlog as project tasks or closes.
Signals that carry no authority. Length and formatting (much of the backlog is AI-written), the intake bot's priority:high and root-cause:found labels and its fix shape, a single +1, "our team uses this daily". Each speaks to gate 1 at most; none moves gate 2. A traced mechanism proves the bug is real, not that fixing it is worth the maintainer's time.
Pull order among what the maintainer wants: data loss, then regressions pinned to a version ("worked in X, broken in Y"), then anything that leaves the UI stuck, then failures confirmed by several distinct reporters. Cheap traced fixes come after those, never before.
Verdicts
- FIX-READY — a real bug with a traced mechanism (
root-cause:foundfrom intake, or traced during this sweep), no open PR for it (see Existing PR first), and the maintainer's "так" from the wanted? block. Ready action: a one-line fix-backlog entry (file:line, mechanism, suggested fix shape) — these accumulate into the sweep's fix list for agents to implement. Before the "так" it is a wanted? entry, not a backlog entry. - NEEDS-REPORTER — cannot proceed without the reporter. Ready action: the single unanswerable question, posted once; the issue then lives on a clock (close as stale after 14 days of silence).
- CLOSE-FIXED — behavior fixed by a merged change. Ready action: close comment naming the commit/PR and the release that carries it. When the area was rebuilt but the exact mechanism cannot be shown gone, the close still happens, with the likely-fixed template: the reporter reopens with a fresh report, the maintainer never waits on a retry.
- CLOSE-NOT-OURS — gate 1 fails: upstream, provider data, or user configuration. Ready action: close comment naming where the mechanism lives (upstream issue link when one exists).
- CLOSE-DUPLICATE — same failure as an existing issue. Keep the issue with the better evidence, close the other naming it.
- CLOSE-DECLINE — a feature or behavior the product should not take (the
pr-reviewskill's whim/scope grounds apply). Ready action: honest close comment; where a real ache underlies it, salvage per the pr-review skill's rule. - FEATURE-DECISION — a plausible feature only the maintainer can judge. Ready action: the product question in one line plus drafted comments for both answers. These go to the maintainer as a numbered list, like the PR triage's Product fit block. The maintainer's answer resolves the issue's fate mechanically:
- "так" (wanted) → post the acceptance comment (what was approved and, when known, the welcome implementation shape), add the
acceptedlabel, and leave it open.acceptedmarks the decision as made — later sweeps never re-ask anacceptedissue, andlabel:acceptedis the implementation roadmap for agents and contributors. - "ні" (declined) → post the drafted decline comment (with ache salvage where one underlies it) and close as not planned.
- A conditional answer ("так, але тільки як настройка", "ні в такому вигляді, але X — так") is folded into the posted comment verbatim in spirit — the maintainer's condition becomes the recorded scope.
- "так" (wanted) → post the acceptance comment (what was approved and, when known, the welcome implementation shape), add the
Existing PR first. Before any verdict that sends an issue toward implementation (FIX-READY, an accepted feature), find out whether someone already has the fix in flight: gh pr list --search "<issue-number> OR <error string> OR <title terms>" --state open, plus the issue's own timeline (linked PRs, "opened a PR" comments — the reporter's fix is easy to miss when the PR body says fixes #N and the issue thread stays silent). The same check gates every close: an issue with an open PR against it is never closed as stale or silently-fixed — the PR is the activity, and its review decides the issue's fate. An open PR moves the issue out of the fix backlog and into the PR queue: the ready action is a verdict on that PR (apply the pr-review skill), never a parallel in-house fix. A contributor who reported a bug and fixed it the same day, then watched a duplicate patch land on top, is owed a public apology and a changelog credit; the check costs one command.
Phase 1 — Mechanical sweep
Fetch all open issues with gh issue list --limit above the real count. Bucket cheaply before any deep reading:
| Bucket | Signal | Likely verdict |
|---|---|---|
| Stale-fixed | references code/behavior changed by merged PRs; CHANGELOG [Unreleased]/recent releases mention the symptom |
CLOSE-FIXED (verify per Silently-fixed detection) |
| Dead needs-info | needs-info with no reporter reply > 14 days |
close as stale |
| Not ours | intake verdict or thread places the mechanism upstream, in provider data, or in user configuration | CLOSE-NOT-OURS |
| Decided | matches a recorded maintainer decision (close comment, declined PR) | CLOSE-DECLINE by pointer |
| Duplicate clusters | title/error-string similarity across open issues | CLOSE-DUPLICATE |
| Feature wishes | enhancement |
FEATURE-DECISION or CLOSE-DECLINE |
| Traced bugs | root-cause:found |
wanted? candidates — verify the trace still applies and no PR is open for it; FIX-READY only after the maintainer's "так" |
Silently-fixed detection
Many fixes land without linking the issue they resolve, so an issue can sit open with a perfectly valid-looking repro that describes code which no longer exists. A fresh-looking issue is not proof of a live bug — probe in this order, strongest evidence first:
- Mechanism anchor. For issues carrying
root-cause:found(or any comment citingfile:line), check whether the cited code changed since the issue's date:git log -L<line>,<line>:<file> --since=<issue date>(fall back togit log --since -- <file>when lines drifted). Untouched code → the bug is live. Changed code → re-read the mechanism on current main; if it is gone, this is CLOSE-FIXED with the commit as evidence. - Repro re-run. When the intake comment carries an inline reproduction script or test, run it against current main. Passing repro = fixed, with the run as evidence.
- Symptom search. Extract the issue's distinctive strings (error messages, function names, user-visible symptom terms) and search
git log --grep,CHANGELOG.md, and merged PR titles/bodies since the issue's creation date.
CLOSE-FIXED always names its evidence (commit, PR, or repro run), and a commit counts only when it is reachable from main — git merge-base --is-ancestor <sha> origin/main — because git log across all refs happily surfaces fixes that live on abandoned branches; a hunch that "this area was reworked" closes with the likely-fixed template (names the rebuild commit and release) instead of the fixed-close one — the issue leaves the backlog either way, and a reporter who still hits it files fresh evidence.
Every issue/PR reference in maintainer-facing reports is a clickable link ([#3164](https://github.com/openchamber/openchamber/issues/3164)), never a bare number; each entry carries 2–4 sentences — enough to decide without a follow-up question — and any manual-check note lives inside the entry, never in a separate number-repeating section. An issue where the maintainer already commented or the reporter replied to a question runs in pickup mode: state the thread first, continue it, never re-ask a decided question.
Weigh trusted community reviewers' comments (see the triage-prs skill's rule — same names, same weight) and the intake bot's "For the maintainer" lines as strong signals. Deliver the sweep as one report and stop for approval.
Phase 2 — Approved batch actions
Execute approved closes/comments with retries and ~1s spacing; log results; re-verify the open count. Closes use --reason "completed" for fixed and --reason "not planned" for declines/duplicates/stale.
Phase 3 — Assessment fan-out
For the surviving pool, fan out subagents (~15 issues each) that read the issue, its comments, and the relevant code, run both gates, and return per-issue verdict blocks. Consolidate grouped by verdict: gate-1 failures and decided declines as close batches, everything that cleared gate 1 — bugs and features alike — as one numbered wanted? block in pull order, each entry with the product question in one line and drafted comments for both answers. Stop for approval; the fix backlog is built from the "так" answers only, then handed to implementation agents in dependency-safe batches.
Message templates
stale-close (dead needs-info)
Closing as stale: the requested details never arrived, and without them this can't be reproduced. If you hit it again on a current version, a fresh report with the missing details is welcome.
fixed-close
This was fixed by [ref] and ships in [release/next release]. Closing — if the problem persists there, comment and it will be reopened.
likely-fixed-close
The [area] was rebuilt in [ref] ([release]) in a way that covers what you described, so closing this one. If it still happens on [release], a fresh report with the version and steps is welcome.
not-ours-close
Closing: this behavior comes from [OpenCode / the provider / models.dev data / your configuration], not from OpenChamber — [one clause on the mechanism, with the upstream link when one exists]. Thanks for the report.
duplicate-close
Closing as a duplicate of #[N], which tracks the same failure[: one clause on what this report added, if anything]. Follow that issue for updates.
decline-close
Thanks — closing this one: [honest one-sentence reason grounded in product direction or maintenance cost]. [If a real ache underlies it: the welcome shape of a future change.]
Version History
-
336e192
Current 2026-09-22 17:58
新增两重门禁机制(归属性与需求性),细化优先级排序规则及各类裁决的具体行动指引。
- 2471b29 2026-09-09 11:57


