SuperAPI AI Directory

issue-triage

General & other

View repository

Updated 10-15 19:54

About this skill

Issue Triage

When to use

Skill Usage Output
/issue-triage Sort, analyze, comment on issues Action tables + deep analysis + posted comments
/repo-recap General recap to share with the team Markdown summary (PRs + issues + releases)

Triggers :

  • Manually: /issue-triage or /issue-triage all or /issue-triage 42 57
  • Proactively: when >10 open issues without triage, or stale issue >30d detected

Language

  • Check the argument passed to the skill
  • If en or english → tables and summary in English
  • If fr, french, or no argument → French (default)
  • Note: GitHub comments (Phase 3) ALWAYS remain in English (international audience)

3-phase workflow: automatic audit → opt-in deep analysis → comments with mandatory validation.

Preconditions

git rev-parse --is-inside-work-tree
gh auth status

If one fails, stop and explain what is missing.


Phase 1 — Audit (always executed)

Data Gathering (commands in parallel)

# Identité du repo
gh repo view --json nameWithOwner -q .nameWithOwner

# Issues ouvertes avec métadonnées complètes
gh issue list --state open --limit 100 \
  --json number,title,author,createdAt,updatedAt,labels,assignees,body,comments

# PRs ouvertes (pour cross-référence)
gh pr list --state open --limit 50 --json number,title,body

# Issues fermées récemment (pour détection doublons)
gh issue list --state closed --limit 20 \
  --json number,title,labels,closedAt

# Collaborateurs (pour protéger les issues des mainteneurs)
gh api "repos/{owner}/{repo}/collaborators" --jq '.[].login'

Collaborators fallback : if gh api .../collaborators fails (403/404):

gh pr list --state merged --limit 10 --json author --jq '.[].author.login' | sort -u

If still ambiguous, ask the user via AskUserQuestion.

Note : author is an object {login: "..."} — always extract .author.login.

Analysis — 6 dimensions

1. Categorization (existing labels > title/body inference):

  • Bug : keywords crash, error, fail, broken, regression, wrong, unexpected
  • Feature : add, implement, support, new, feat:
  • Enhancement : improve, optimize, better, enhance, refactor
  • Question/Support : how, why, help, unclear, docs, documentation
  • Duplicate Candidate : see dimension 3 below

2. Cross-ref PRs :

  • Scan body of each open PR for fixes #N, closes #N, resolves #N (case-insensitive, regex)
  • Build a map: issue_number -> [PR numbers]
  • An issue linked to a merged PR → recommend closing

3. Duplicate detection :

  • Normalize titles: lowercase, strip prefixes (bug:, feat:, [bug], [feature], etc.)
  • Jaccard on title words : if score > 60% between two issues → duplicate candidate
  • Keywords body overlap > 50% → signal reinforcement
  • Also compare with recent closed issues (last 20)
  • A false positive can be confirmed/discarded in Phase 2

4. Risk classification :

  • Red : keywords CVE, vulnerability, injection, auth bypass, security, exploit, unsafe, credentials, leak, RCE, XSS
  • Yellow : breaking change, migration, deprecation, remove API, breaking, incompatible
  • Green : everything else

5. Staleness :

  • 30d without activity (updatedAt) → Stale

  • 90d without activity → Very Stale

  • Calculate from the current date

6. Action recommendations :

  • Accept & Prioritize : clear, reproducible issue, in scope
  • Label needed : issue without label
  • Comment needed : missing info, insufficient body
  • Linked to PR : an open PR references this issue
  • Duplicate candidate : duplicate candidate identified (specify with #N)
  • Close candidate : stale + no recent activity, or out of scope (never if author is a collaborator)
  • PR merged → close : linked PR is merged, issue still open

Output — 5 tables

## Issues ouvertes ({count})

### Critiques (risque rouge)
| # | Titre | Auteur | Âge | Labels | Action |
| - | ----- | ------ | --- | ------ | ------ |

### Liées à une PR
| # | Titre | Auteur | PR(s) liée(s) | Status PR | Action |
| - | ----- | ------ | ------------- | --------- | ------ |

### Actives
| # | Titre | Auteur | Catégorie | Âge | Labels | Action |
| - | ----- | ------ | --------- | --- | ------ | ------ |

### Doublons candidats
| # | Titre | Doublon de | Similarité | Action |
| - | ----- | ---------- | ---------- | ------ |

### Stale
| # | Titre | Auteur | Dernière activité | Action |
| - | ----- | ------ | ----------------- | ------ |

### Résumé
- Total : {N} issues ouvertes
- Critiques : {N} (risque sécurité ou breaking)
- Liées à PR : {N}
- Doublons candidats : {N}
- Stale (>30j) : {N} | Very Stale (>90j) : {N}
- Sans labels : {N}
- Quick wins (à fermer ou labeler rapidement) : {liste}

0 issues → display Aucune issue ouverte. and finish.

Note : Âge = days since createdAt, format {N}j. If >30d, display in bold.

Automatic copy

After displaying the triage table, copy to clipboard:

pbcopy <<'EOF'
{tableau de triage complet}
EOF

Confirm: Tableau copié dans le presse-papier. (FR) / Triage table copied to clipboard. (EN)


Phase 2 — Deep Analysis (opt-in)

Issue selection

If argument passed :

  • "all" → all open issues
  • Numbers ("42 57") → only these issues
  • No argument → suggest via AskUserQuestion

If no argument, display:

question: "Quelles issues voulez-vous analyser en profondeur ?"
header: "Deep Analysis"
multiSelect: true
options:
  - label: "Toutes ({N} issues)"
    description: "Analyse approfondie de toutes les issues avec agents en parallèle"
  - label: "Critiques uniquement"
    description: "Focus sur les {M} issues à risque rouge/jaune"
  - label: "Doublons candidats"
    description: "Confirmer ou écarter les {K} doublons détectés"
  - label: "Stale uniquement"
    description: "Décision close/keep sur les {J} issues stale"
  - label: "Passer"
    description: "Terminer ici — juste l'audit"

If "Skip" → end of workflow.

Analysis execution

For each selected issue, launch an agent via Task tool in parallel :

subagent_type: general-purpose
model: sonnet
prompt: |
  Analyze GitHub issue #{num}: "{title}" by @{author}

  **Metadata**: Created {createdAt}, last updated {updatedAt}, labels: {labels}

  **Body**:
  {body}

  **Existing comments** ({comments_count} total, showing last 5):
  {last_5_comments}

  **Context**:
  - Linked PRs: {linked_prs or "none"}
  - Duplicate candidate of: {duplicate_of or "none"}
  - Risk classification: {risk_color}

  Analyze this issue and return a structured report:
  ### Scope Assessment
  What is this issue actually asking for? Is it clearly defined?

  ### Missing Information
  What's needed to act on this? (reproduction steps, version, environment, etc.)

  ### Risk & Impact
  Security risk? Breaking change? Who's affected?

  ### Effort Estimate
  XS (<1h) / S (1-4h) / M (1-2d) / L (3-5d) / XL (>1 week)

  ### Priority
  P0 (critical, act now) / P1 (high, this sprint) / P2 (medium, backlog) / P3 (low, someday)

  ### Recommended Action
  One of: Accept & Prioritize, Request More Info, Mark Duplicate (#N), Close (Stale), Close (Out of Scope), Link to Existing PR

  ### Draft Comment
  Draft a GitHub comment in English using the appropriate template from templates/issue-comment.md.
  Be specific, helpful, and constructive.

If issue has >50 comments, summarize only the last 5.

Aggregate all reports. Display a summary after all analyses.


Phase 3 — Actions (mandatory validation)

Possible action types

  • Comment : gh issue comment {num} --body-file -
  • Label : gh issue edit {num} --add-label "{label}" (skip if label already present)
  • Close : gh issue close {num} --reason "not planned" (never without validation)

Draft generation

For each analyzed issue, generate the actions (comment + labels + closure if applicable) using templates/issue-comment.md.

Rules :

  • Comment language: English (international audience)
  • Tone: professional, constructive, factual
  • Never re-label an issue that already has this label
  • Never propose "close" for an issue from a collaborator
  • Always display the draft BEFORE any gh issue comment

Display and validation

Display ALL drafts in the format:

---
### Draft — Issue #{num}: {title}

**Actions proposées** : {Commentaire | Label: "bug" | Fermeture}

**Commentaire** :
{commentaire complet}

---

Then request validation via AskUserQuestion :

question: "Ces actions sont prêtes. Lesquelles voulez-vous exécuter ?"
header: "Exécuter"
multiSelect: true
options:
  - label: "Toutes ({N} actions)"
    description: "Commenter + labeler + fermer selon les drafts"
  - label: "Issue #{x} — {title_truncated}"
    description: "Exécuter uniquement les actions pour cette issue"
  - label: "Aucune"
    description: "Annuler — ne rien faire"

(Generate one option per issue + "All" + "None")

Execution

For each validated action, execute in order: comment → label → close.

# Commenter
gh issue comment {num} --body-file - <<'COMMENT_EOF'
{commentaire}
COMMENT_EOF

# Labeler (si applicable)
gh issue edit {num} --add-label "{label}"

# Fermer (si applicable)
gh issue close {num} --reason "not planned"

Confirm each action: Commentaire posté sur issue #{num}: {title}

If "None" → Aucune action exécutée. Workflow terminé.


Edge case handling

Situation Behavior
0 open issues Aucune issue ouverte. + finish
Issue without body Categorize by title, recommend Comment needed
>50 comments Summarize only the last 5
Duplicate false positive Phase 2 confirms/rules out — do not act on suspicion alone
Labels already present Do not re-label, report "label already applied"
Outcome from a collaborator Never close candidate automatic
GitHub API rate limit Reduce --limit, notify the user
Merged PR linked to open issue Recommend closing the issue
Issue with no activity >90d Very Stale — propose closing with a kind message
Duplicate confirmed in Phase 2 Post comment + close in favor of the original issue

Notes

  • Always derive owner/repo via gh repo view, never hardcode
  • Use gh CLI (not curl GitHub API) except for the list of collaborators
  • updatedAt can be null on some issues → treat as createdAt
  • Never post or close without explicit user validation in the chat
  • Drafted comments must be visible BEFORE any gh issue comment
  • Jaccard similarity = |word intersection| / |word union| (exclude stop words: a, the, is, in, of, for, to, with, on, at, by)