Triage GitHub issues using an evidence pack — evaluates issues and produces a structured report with verdicts, confidence levels, and recommended actions
Evaluate GitHub issues using a pre-assembled evidence pack and produce a structured triage report.
/triage <number> [number...] # Single issue(s)
/triage recent [--since 7d] # Recent batch
/triage audit [--older-than 180d] [--batch-size 50] [--type bug] # Historical batch
/triage <any mode> --skip-trust # Skip reporter claim verification for team-member issues
Run the CLI to ensure data is fresh. Forward all arguments after the command name.
Single-issue mode: When invoked with issue numbers, use the single command:
node --experimental-strip-types ./scripts/issues/triage.mts single <number> [number...]
Batch modes: Forward the command and arguments directly:
node --experimental-strip-types ./scripts/issues/triage.mts <recent|audit> [args]
The script prints the absolute path to the evidence pack JSON on stdout. Read that file.
Parse the pack JSON. It contains:
meta — run metadata (workflow, query params, schema version)teamMembers — list of GitHub org member loginsissues — array of enriched issues with computed evidence fieldsFor each issue in pack.issues, evaluate in order:
Is the body empty, incoherent, or unrelated to GitLens?
Critical rule: Organization-level members (isTeamMember: true) can NEVER be marked spam. Team-member issues often have minimal descriptions and must not be flagged. For contributors (authorAssociation: "CONTRIBUTOR") apply lenient standards. For outsiders (authorAssociation: "NONE"), apply standard spam criteria.
Does issue.type match the actual nature of the report? Do the labels correctly categorize it? Note any relabeling needed. Use label descriptions from the evidence pack to understand what each label means.
Does the issue have a milestone, assignee, or triage-specific label indicating it has been processed? If so, classify as Valid - Already Triaged.
Is the issue a bug report lacking environment details (VS Code version, extension version, OS, reproduction steps)? Is it a feature request with no description of the desired behavior? Classify as Request More Info if evidence is insufficient to evaluate further.
Verify reporter claims against the codebase before assigning any verdict above Low confidence. Skip this step for team-member issues when --skip-trust is passed.
Identify testable claims — scan the issue body for references to specific settings (gitlens.*), commands, UI elements, error messages, described behavior, or code paths. These are the reporter's assertions about what exists and what happened.
Spot-check 1–3 claims using Grep or Glob:
package.json or src/config.ts?contributions.json?Record each checked claim as one of:
Confidence gate: If no claims can be verified (all unverifiable or no testable claims present), cap the verdict confidence at Low regardless of other evidence strength. Disputed claims should further lower confidence or shift the verdict toward Request More Info or Close - Invalid depending on severity.
For each entry in duplicateCandidates:
Close - Duplicate candidate pending Stage 2 confirmationsimilarityBasis to judge how strong the duplicate signal isApply only to issues not yet resolved to a high-confidence verdict in Stage 1.
Does the requested feature already exist in the extension? Check against CHANGELOG entries (changelogEntry field), known feature areas, or codebase evidence if needed. If the feature already exists, classify as Close - Already Exists with a note explaining the existing feature and how to access it.
Is there evidence the behavior described still exists? Cross-reference with changelogEntry. If a changelog entry exists for this issue, it is strong evidence of a fix — but must be corroborated by at least one other source:
Do NOT classify as Close - Fixed on changelog evidence alone.
To classify an issue as Close - Fixed, you MUST have at least two independent evidence sources:
changelogEntry is non-null)linkedPrs)If only one source is present, downgrade to Request More Info or Valid - Needs Triage.
Is the issue caused by a VS Code API limitation, a platform OS issue, or a third-party extension conflict? Note this as evidence for Close - Invalid with an explicit reason.
Does the issue meet ALL THREE stale criteria:
staleInactivityDays (365 days) — check lastActivityAtOnly then classify as Close - Stale. Check supersessionIndicators for evidence of supersession.
Codebase-level staleness signals: If the issue references specific UI elements, settings, commands, or code paths, check whether they still exist in the codebase. If the referenced functionality has been removed, substantially redesigned, or renamed, that is strong evidence for staleness. Use Grep or Glob to quickly verify existence of referenced features.
Separate from Close - Stale, identify issues that are old and inactive but where the code path still exists and the issue may still be valid. Classify as Request More Info when ALL of:
lastActivityAtreactions.thumbsUp is 0-1)Close - Stale)The Request More Info comment should ask the reporter to verify the issue still occurs on the current version and provide updated environment details. This triggers the needs-more-info label via /update-issues, which activates existing automation that auto-closes if no response within a set timeframe.
Before assigning ANY verdict:
Low, downgrade to Request More Info or Valid - Needs TriageValid - Needs Triage with a note of your impressionrequiresHumanApproval: true for ALL close recommendations (Close - Fixed, Close - Duplicate, Close - Not a Bug, Close - Already Exists, Close - Invalid, Close - Stale)Close - Fixed| Verdict | Required Evidence |
|---|---|
| Close - Fixed | 2+ of: changelog entry, merged linked PR, maintainer comment, code investigation |
| Close - Duplicate | Identified canonical issue number + both issues describe same behavior |
| Close - Not a Bug | Evidence the reported behavior is expected, user error, or environment-specific (not a defect) |
| Close - Already Exists | Codebase or CHANGELOG evidence the requested feature already ships |
| Close - Invalid | Clear evidence of third-party cause, spam, or misunderstanding |
| Close - Stale | No activity for 365+ days + feature still exists or addressed elsewhere |
| Request More Info | Specific description of what information is missing |
| Retype - Bug | Evidence issue describes a defect, not a feature request |
| Retype - Feature Request | Evidence issue describes desired new behavior, not a defect |
| Valid - Needs Triage | Insufficient evidence for any other verdict |
| Valid - Already Triaged | Has milestone, assignee, or triage labels |
Construct issue URLs as https://github.com/<pack.meta.repo>/issues/<number> and link every issue reference in both the markdown report and JSON output.
Produce two files in .work/triage/reports/:
For reactive mode: YYYY-MM-DD-TRIAGE-REPORT.md
For audit mode: YYYY-MM-DD-AUDIT-REPORT-batch-N.md
For single mode: YYYY-MM-DD-TRIAGE-REPORT.md
Single-issue brevity rule: When evaluating only 1 issue, omit any verdict-group sections that have no issues (e.g., skip "Issues to Close Now" entirely if there are none). Only include sections that contain at least one issue, plus the Quality Metadata section. This keeps the report focused and scannable. For batch triage (2+ issues), include all sections — the grouping serves as a useful overview even when some groups are empty.
Use this structure:
# [Triage / Audit] Report — YYYY-MM-DD [Batch N]
Run ID: <runId>
Generated: <timestamp>
Workflow: reactive | audit
Query: <query params summary>
Issues evaluated: N
Issues requiring human approval: N
---
## Issues to Close Now
> All items in this section require human review before action is taken.
### [#NNNN — Title](https://github.com/<owner>/<repo>/issues/NNNN)
- **Author**: @username (team) | @username
- **Verdict**: Close - Fixed | Close - Duplicate | Close - Not a Bug | Close - Already Exists | Close - Invalid | Close - Stale
- **Confidence**: High | Medium | Low
- **Type**: <issue type> | **Labels**: <label list>
- **Claims**: <checked claims with status: confirmed/disputed/unverifiable — omit if verification was skipped>
- **Evidence**: <concise evidence summary>
- **Recommended action**: <specific action to take>
- **Requires human approval**: Yes
---
## Issues Needing a Maintainer Comment
### [#NNNN — Title](https://github.com/<owner>/<repo>/issues/NNNN)
- **Author**: @username (team) | @username
- **Verdict**: Request More Info
- **Confidence**: High | Medium | Low
- **Claims**: <checked claims with status — omit if verification was skipped>
- **Evidence**: <what is known>
- **Recommended action**: <specific comment to post>
---
## Issues Needing Retyping
### [#NNNN — Title](https://github.com/<owner>/<repo>/issues/NNNN)
- **Author**: @username (team) | @username
- **Verdict**: Retype - Bug | Retype - Feature Request
- **Confidence**: High | Medium | Low
- **Claims**: <checked claims with status — omit if verification was skipped>
- **Evidence**: <why the current type is wrong>
- **Current type**: <current>
- **Recommended type**: <new type>
---
## Issues to Enter Investigation Queue
### [#NNNN — Title](https://github.com/<owner>/<repo>/issues/NNNN)
- **Author**: @username (team) | @username
- **Verdict**: Valid - Needs Triage
- **Confidence**: Medium | Low
- **Type**: <issue type> | **Labels**: <current labels> | **Recommended labels**: <area labels to add based on feature area identified during evaluation, e.g. area-graph, area-ai, area-integrations — or "none" if current labels are sufficient>
- **Claims**: <1-2 sentence summary per checked claim with status: confirmed/disputed/unverifiable — omit if verification was skipped>
- **Evidence**: <what is known and what needs investigation — keep to 2-4 bullet points>
---
## Issues Already Triaged (No Immediate Action)
- [#NNNN — Title](https://github.com/<owner>/<repo>/issues/NNNN) — <reason it's already triaged>
---
## Quality Metadata
- Low-confidence verdicts: N (X%)
- Human approval required: N
- Issues skipped (Stage 1 resolved): N
- Issues escalated to Stage 2: N
File: YYYY-MM-DD-DECISIONS[-batch-N].json
{
"reportId": "<uuid>",
"runId": "<uuid from pack>",
"schemaVersion": "1.0",
"generatedAt": "<ISO timestamp>",
"workflow": "reactive | audit | single",
"verdicts": [
{
"issueNumber": 1234,
"verdict": "<VerdictClass>",
"confidence": "High | Medium | Low",
"evidenceChecklistStatus": {
"changelogReference": true,
"linkedPrOrCommit": true,
"maintainerTimelineComment": false,
"investigationEvidence": false
},
"claimsVerification": [
{
"claim": "setting gitlens.foo exists",
"status": "confirmed | disputed | unverifiable",
"detail": "optional — what was found or why it couldn't be checked"
}
],
"recommendedLabels": [],
"recommendedActions": ["close"],
"requiresHumanApproval": true,
"evidenceSummary": "...",
"canonicalDuplicateNumber": null,
"canonicalDuplicateStatus": null
}
]
}
Generate a UUID for reportId. Use the runId from the evidence pack's meta.runId.
Field guidance:
evidenceChecklistStatus — Used for the Two-Source Rule (Stage 2, step 9). These fields track formal evidence sources for close decisions, NOT claim verification from Stage 1. investigationEvidence should only be true if a formal /investigate report exists or you performed a Stage 2 code investigation that confirms/refutes the bug status. Claim verification (Stage 1, step 5) does not count as investigation evidence.recommendedLabels — Always include recommended area labels (e.g., area-graph, area-ai, area-cli, area-integrations) based on the feature area identified during evaluation. Include type corrections (e.g., bug, enhancement) and status labels (e.g., triaged). Check the evidence pack's label descriptions for available area labels.Write both files and confirm their paths to the user.
This skill can be used standalone or as part of the issue workflow pipeline:
/triage recent → /investigate --from-report → /prioritize --from-report → /update-issues
/triage 5096 → /investigate 5096 → /prioritize 5096 → /update-issues
Downstream skills consume the decisions JSON produced by this skill.