Skip to content
Back to skills

Github Issue Triage Hackefeller

ASecurity

Triage GitHub issues with parallel analysis. 1 issue = 1 background agent. Exhaustive pagination. Analyzes: question vs bug, project validity, resolution status, community engagement, linked PRs. Triggers: 'triage issues', 'analyze issues', 'issue report'.

  • 42 stars
  • 0 votes
  • 0 copies
  • 3 views
  • Added May 31, 2026
ai-agentstypescriptgobashdebugginggitapisecurity

Works with

  • api

Security analysis

A100/100

Scanned May 31, 2026

npx -y skills add diegosouzapw/awesome-omni-skill --skill github-issue-triage-hackefeller --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Github Issue Triage Hackefeller?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Github Issue Triage Hackefeller
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/diegosouzapw-github-issue-triage-hackefeller/badge)](https://www.skillsdirectory.com/skills/diegosouzapw-github-issue-triage-hackefeller)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: github-issue-triage
description: "Triage GitHub issues with parallel analysis. 1 issue = 1 background agent. Exhaustive pagination. Analyzes: question vs bug, project validity, resolution status, community engagement, linked PRs. Triggers: 'triage issues', 'analyze issues', 'issue report'."
---

# GitHub Issue Triage Specialist

You are a GitHub issue triage automation agent. Your job is to:

1. Fetch **EVERY SINGLE ISSUE** within a specified time range using **EXHAUSTIVE PAGINATION**
2. Launch ONE background agent PER issue for parallel analysis
3. Collect results and generate a comprehensive triage report

---

# CRITICAL: EXHAUSTIVE PAGINATION IS MANDATORY

**THIS IS THE MOST IMPORTANT RULE. VIOLATION = COMPLETE FAILURE.**

## YOU MUST FETCH ALL ISSUES. PERIOD.

| WRONG                                    | CORRECT                                 |
| ---------------------------------------- | --------------------------------------- |
| `gh issue list --limit 100` and stop     | Paginate until ZERO results returned    |
| "I found 16 issues" (first page only)    | "I found 61 issues after 5 pages"       |
| Assuming first page is enough            | Using `--limit 500` and verifying count |
| Stopping when you "feel" you have enough | Stopping ONLY when API returns empty    |

### WHY THIS MATTERS

- GitHub API returns **max 100 issues per request** by default
- A busy repo can have **50-100+ issues** in 48 hours
- **MISSING ISSUES = MISSING CRITICAL BUGS = PRODUCTION OUTAGES**
- The user asked for triage, not "sample triage"

### THE ONLY ACCEPTABLE APPROACH

```bash
# ALWAYS use --limit 500 (maximum allowed)
# ALWAYS check if more pages exist
# ALWAYS continue until empty result

gh issue list --repo $REPO --state all --limit 500 --json number,title,state,createdAt,updatedAt,labels,author
```

**If the result count equals your limit, THERE ARE MORE ISSUES. KEEP FETCHING.**

---

## PHASE 1: Issue Collection (EXHAUSTIVE Pagination)

### 1.1 Determine Repository and Time Range

Extract from user request:

- `REPO`: Repository in `owner/repo` format (default: current repo via `gh repo view --json nameWithOwner -q .nameWithOwner`)
- `TIME_RANGE`: Hours to look back (default: 48)

---

## AGENT CATEGORY RATIO RULES

**Philosophy**: Use the cheapest agent that can do the job. Expensive agents = waste unless necessary.

### Default Ratio: `unspecified-low:8, quick:1, writing:1`

| Category          | Ratio | Use For                                                          | Cost |
| ----------------- | ----- | ---------------------------------------------------------------- | ---- |
| `unspecified-low` | 80%   | Standard issue analysis - read issue, fetch comments, categorize | $    |
| `quick`           | 10%   | Trivial issues - obvious duplicates, spam, clearly resolved      | ¢    |
| `writing`         | 10%   | Report generation, response drafting, summary synthesis          | $$   |

### When to Override Default Ratio

| Scenario                | Recommended Ratio                                  | Reason                                |
| ----------------------- | -------------------------------------------------- | ------------------------------------- |
| Bug-heavy triage        | `unspecified-low:7, quick:2, writing:1`            | More simple duplicates                |
| Feature request triage  | `unspecified-low:6, writing:3, quick:1`            | More response drafting needed         |
| Security audit          | `unspecified-high:5, unspecified-low:4, writing:1` | Deeper analysis required              |
| First-pass quick filter | `quick:8, unspecified-low:2`                       | Just categorize, don't analyze deeply |

### Agent Assignment Algorithm

```typescript
function assignAgentCategory(issues: Issue[], ratio: Record<string, number>): Map<Issue, string> {
  const assignments = new Map<Issue, string>();
  const total = Object.values(ratio).reduce((a, b) => a + b, 0);

  // Calculate counts for each category
  const counts: Record<string, number> = {};
  for (const [category, weight] of Object.entries(ratio)) {
    counts[category] = Math.floor(issues.length * (weight / total));
  }

  // Assign remaining to largest category
  const assigned = Object.values(counts).reduce((a, b) => a + b, 0);
  const remaining = issues.length - assigned;
  const largestCategory = Object.entries(ratio).sort((a, b) => b[1] - a[1])[0][0];
  counts[largestCategory] += remaining;

  // Distribute issues
  let issueIndex = 0;
  for (const [category, count] of Object.entries(counts)) {
    for (let i = 0; i < count && issueIndex < issues.length; i++) {
      assignments.set(issues[issueIndex++], category);
    }
  }

  return assignments;
}
```

### Category Selection Heuristics

**Before launching agents, pre-classify issues for smarter category assignment:**

| Issue Signal                | Assign To                      | Reason                       |
| --------------------------- | ------------------------------ | ---------------------------- |
| Has `duplicate` label       | `quick`                        | Just confirm and close       |
| Has `wontfix` label         | `quick`                        | Just confirm and close       |
| No comments, < 50 char body | `quick`                        | Likely spam or incomplete    |
| Has linked PR               | `quick`                        | Already being addressed      |
| Has `bug` label + long body | `unspecified-low`              | Needs proper analysis        |
| Has `feature` label         | `unspecified-low` or `writing` | May need response            |
| User is maintainer          | `quick`                        | They know what they're doing |
| 5+ comments                 | `unspecified-low`              | Complex discussion           |
| Needs response drafted      | `writing`                      | Prose quality matters        |

---

### 1.2 Exhaustive Pagination Loop

# STOP. READ THIS BEFORE EXECUTING.

**YOU WILL FETCH EVERY. SINGLE. ISSUE. NO EXCEPTIONS.**

## THE GOLDEN RULE

```
NEVER use --limit 100. ALWAYS use --limit 500.
NEVER stop at first result. ALWAYS verify you got everything.
NEVER assume "that's probably all". ALWAYS check if more exist.
```

## MANDATORY PAGINATION LOOP (COPY-PASTE THIS EXACTLY)

You MUST execute this EXACT pagination loop. DO NOT simplify. DO NOT skip iterations.

```bash
#!/bin/bash
# MANDATORY PAGINATION - Execute this EXACTLY as written

REPO="hackefeller/ghostwire"  # or use: gh repo view --json nameWithOwner -q .nameWithOwner
TIME_RANGE=48  # hours
CUTOFF_DATE=$(date -v-${TIME_RANGE}H +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date -d "${TIME_RANGE} hours ago" -Iseconds)

echo "=== EXHAUSTIVE PAGINATION START ==="
echo "Repository: $REPO"
echo "Cutoff date: $CUTOFF_DATE"
echo ""

# STEP 1: First fetch with --limit 500
echo "[Page 1] Fetching issues..."
FIRST_FETCH=$(gh issue list --repo $REPO --state all --limit 500 --json number,title,state,createdAt,updatedAt,labels,author)
FIRST_COUNT=$(echo "$FIRST_FETCH" | jq 'length')
echo "[Page 1] Raw count: $FIRST_COUNT"

# STEP 2: Filter by time range
ALL_ISSUES=$(echo "$FIRST_FETCH" | jq --arg cutoff "$CUTOFF_DATE" \
  '[.[] | select(.createdAt >= $cutoff or .updatedAt >= $cutoff)]')
FILTERED_COUNT=$(echo "$ALL_ISSUES" | jq 'length')
echo "[Page 1] After time filter: $FILTERED_COUNT issues"

# STEP 3: CHECK IF MORE PAGES NEEDED
# If we got exactly 500, there are MORE issues!
if [ "$FIRST_COUNT" -eq 500 ]; then
  echo ""
  echo "WARNING: Got exactly 500 results. MORE PAGES EXIST!"
  echo "Continuing pagination..."

  PAGE=2
  LAST_ISSUE_NUMBER=$(echo "$FIRST_FETCH" | jq '.[- 1].number')

  # Keep fetching until we get less than 500
  while true; do
    echo ""
    echo "[Page $PAGE] Fetching more issues..."

    # Use search API with pagination for more results
    NEXT_FETCH=$(gh issue list --repo $REPO --state all --limit 500 \
      --json number,title,state,createdAt,updatedAt,labels,author \
      --search "created:<$(echo "$FIRST_FETCH" | jq -r '.[-1].createdAt')")

    NEXT_COUNT=$(echo "$NEXT_FETCH" | jq 'length')
    echo "[Page $PAGE] Raw count: $NEXT_COUNT"

    if [ "$NEXT_COUNT" -eq 0 ]; then
      echo "[Page $PAGE] No more results. Pagination complete."
      break
    fi

    # Filter and merge
    NEXT_FILTERED=$(echo "$NEXT_FETCH" | jq --arg cutoff "$CUTOFF_DATE" \
      '[.[] | select(.createdAt >= $cutoff or .updatedAt >= $cutoff)]')
    ALL_ISSUES=$(echo "$ALL_ISSUES $NEXT_FILTERED" | jq -s 'add | unique_by(.number)')

    CURRENT_TOTAL=$(echo "$ALL_ISSUES" | jq 'length')
    echo "[Page $PAGE] Running total: $CURRENT_TOTAL issues"

    if [ "$NEXT_COUNT" -lt 500 ]; then
      echo "[Page $PAGE] Less than 500 results. Pagination complete."
      break
    fi

    PAGE=$((PAGE + 1))

    # Safety limit
    if [ $PAGE -gt 20 ]; then
      echo "SAFETY LIMIT: Stopped at page 20"
      break
    fi
  done
fi

# STEP 4: FINAL COUNT
FINAL_COUNT=$(echo "$ALL_ISSUES" | jq 'length')
echo ""
echo "=== EXHAUSTIVE PAGINATION COMPLETE ==="
echo "Total issues found: $FINAL_COUNT"
echo ""

# STEP 5: Verify we got everything
if [ "$FINAL_COUNT" -lt 10 ]; then
  echo "WARNING: Only $FINAL_COUNT issues found. Double-check time range!"
fi
```

## VERIFICATION CHECKLIST (MANDATORY)

BEFORE proceeding to Phase 2, you MUST verify:

```
CHECKLIST:
[ ] Executed the FULL pagination loop above (not just --limit 500 once)
[ ] Saw "EXHAUSTIVE PAGINATION COMPLETE" in output
[ ] Counted total issues: _____ (fill this in)
[ ] If first fetch returned 500, continued to page 2+
[ ] Used --state all (not just open)
```

**If you did NOT see "EXHAUSTIVE PAGINATION COMPLETE", you did it WRONG. Start over.**

## ANTI-PATTERNS (WILL CAUSE FAILURE)

| NEVER DO THIS                        | Why It Fails                           |
| ------------------------------------ | -------------------------------------- |
| Single `gh issue list --limit 500`   | If 500 returned, you missed the rest!  |
| `--limit 100`                        | Misses 80%+ of issues in active repos  |
| Stopping at first fetch              | GitHub paginates - you got 1 page of N |
| Not counting results                 | Can't verify completeness              |
| Filtering only by createdAt          | Misses updated issues                  |
| Assuming small repos have few issues | Even small repos can have bursts       |

**THE LOOP MUST RUN UNTIL:**

1. Fetch returns 0 results, OR
2. Fetch returns less than 500 results

**IF FIRST FETCH RETURNS EXACTLY 500 = YOU MUST CONTINUE FETCHING.**

### 1.3 Also Fetch All PRs (For Bug Correlation)

```bash
# Same pagination logic for PRs
gh pr list --repo $REPO --state all --limit 500 --json number,title,state,createdAt,updatedAt,labels,author,body,headRefName | \
  jq --arg cutoff "$CUTOFF_DATE" '[.[] | select(.createdAt >= $cutoff or .updatedAt >= $cutoff)]'
```

---

## PHASE 2: Parallel Issue Analysis (1 Issue = 1 Agent)

### 2.1 Agent Distribution Formula

```
Total issues: N
Agent categories based on ratio:
- unspecified-low: floor(N * 0.8)
- quick: floor(N * 0.1)
- writing: ceil(N * 0.1)  # For report generation
```

### 2.2 Launch Background Agents

**MANDATORY: Each issue gets its own dedicated background agent.**

For each issue, launch:

```typescript
delegate_task(
  (category = "unspecified-low"), // or quick/writing per ratio
  (load_skills = []),
  (run_in_background = true),
  (prompt = `
## TASK
Analyze GitHub issue #${issue.number} for ${REPO}.

## ISSUE DATA
- Number: #${issue.number}
- Title: ${issue.title}
- State: ${issue.state}
- Author: ${issue.author.login}
- Created: ${issue.createdAt}
- Updated: ${issue.updatedAt}
- Labels: ${issue.labels.map((l) => l.name).join(", ")}

## ISSUE BODY
${issue.body}

## FETCH COMMENTS
Use: gh issue view ${issue.number} --repo ${REPO} --json comments

## ANALYSIS CHECKLIST
1. **TYPE**: Is this a BUG, QUESTION, FEATURE request, or INVALID?
2. **PROJECT_VALID**: Is this issue relevant to OUR project? (YES/NO/UNCLEAR)
3. **STATUS**: 
   - RESOLVED: Already fixed (check for linked PRs, owner comments)
   - NEEDS_ACTION: Requires maintainer attention
   - CAN_CLOSE: Can be closed (duplicate, out of scope, stale, answered)
   - NEEDS_INFO: Missing reproduction steps or details
4. **COMMUNITY_RESPONSE**: 
   - NONE: No comments
   - HELPFUL: Useful workarounds or info provided
   - WAITING: Awaiting user response
5. **LINKED_PR**: If bug, search PRs that might fix this issue

## PR CORRELATION
Check these PRs for potential fixes:
${PR_LIST}

## RETURN FORMAT
\`\`\`
#${issue.number}: ${issue.title}
TYPE: [BUG|QUESTION|FEATURE|INVALID]
VALID: [YES|NO|UNCLEAR]
STATUS: [RESOLVED|NEEDS_ACTION|CAN_CLOSE|NEEDS_INFO]
COMMUNITY: [NONE|HELPFUL|WAITING]
LINKED_PR: [#NUMBER or NONE]
SUMMARY: [1-2 sentence summary]
ACTION: [Recommended maintainer action]
DRAFT_RESPONSE: [If auto-answerable, provide English draft. Otherwise "NEEDS_MANUAL_REVIEW"]
\`\`\`
`),
);
```

### 2.3 Collect All Results

Wait for all background agents to complete, then collect:

```typescript
// Store all task IDs
const taskIds: string[] = []

// Launch all agents
for (const issue of issues) {
  const result = await delegate_task(...)
  taskIds.push(result.task_id)
}

// Collect results
const results = []
for (const taskId of taskIds) {
  const output = await background_output(task_id=taskId)
  results.push(output)
}
```

---

## PHASE 3: Report Generation

### 3.1 Categorize Results

Group analyzed issues by status:

| Category                | Criteria                                             |
| ----------------------- | ---------------------------------------------------- |
| **CRITICAL**            | Blocking bugs, security issues, data loss            |
| **CLOSE_IMMEDIATELY**   | Resolved, duplicate, out of scope, stale             |
| **AUTO_RESPOND**        | Can answer with template (version update, docs link) |
| **NEEDS_INVESTIGATION** | Requires manual debugging or design decision         |
| **FEATURE_BACKLOG**     | Feature requests for prioritization                  |
| **NEEDS_INFO**          | Missing details, request more info                   |

### 3.2 Generate Report

```markdown
# Issue Triage Report

**Repository:** ${REPO}
**Time Range:** Last ${TIME_RANGE} hours
**Generated:** ${new Date().toISOString()}
**Total Issues Analyzed:** ${issues.length}

## Summary

| Category            | Count |
| ------------------- | ----- |
| CRITICAL            | N     |
| Close Immediately   | N     |
| Auto-Respond        | N     |
| Needs Investigation | N     |
| Feature Requests    | N     |
| Needs Info          | N     |

---

## 1. CRITICAL (Immediate Action Required)

[List issues with full details]

## 2. Close Immediately

[List with closing reason and template response]

## 3. Auto-Respond (Template Answers)

[List with draft responses ready to post]

## 4. Needs Investigation

[List with investigation notes]

## 5. Feature Backlog

[List for prioritization]

## 6. Needs More Info

[List with template questions to ask]

---

## Response Templates

### Fixed in Version X

\`\`\`
This issue was resolved in vX.Y.Z via PR #NNN.
Please update: \`bunx ghostwire@X.Y.Z install\`
If the issue persists, please reopen with \`opencode --print-logs\` output.
\`\`\`

### Needs More Info

\`\`\`
Thank you for reporting. To investigate, please provide:

1. \`opencode --print-logs\` output
2. Your configuration file
3. Minimal reproduction steps
   Labeling as \`needs-info\`. Auto-closes in 7 days without response.
   \`\`\`

### Out of Scope

\`\`\`
Thank you for reaching out. This request falls outside the scope of this project.
[Suggest alternative or explanation]
\`\`\`
```

---

## ANTI-PATTERNS (BLOCKING VIOLATIONS)

## IF YOU DO ANY OF THESE, THE TRIAGE IS INVALID

| Violation                     | Why It's Wrong                         | Severity |
| ----------------------------- | -------------------------------------- | -------- |
| **Using `--limit 100`**       | Misses 80%+ of issues in active repos  | CRITICAL |
| **Stopping at first fetch**   | GitHub paginates - you only got page 1 | CRITICAL |
| **Not counting results**      | Can't verify completeness              | CRITICAL |
| Batching issues (7 per agent) | Loses detail, harder to track          | HIGH     |
| Sequential agent calls        | Slow, doesn't leverage parallelism     | HIGH     |
| Skipping PR correlation       | Misses linked fixes for bugs           | MEDIUM   |
| Generic responses             | Each issue needs specific analysis     | MEDIUM   |

## MANDATORY VERIFICATION BEFORE PHASE 2

```
CHECKLIST:
[ ] Used --limit 500 (not 100)
[ ] Used --state all (not just open)
[ ] Counted issues: _____ total
[ ] Verified: if count < 500, all issues fetched
[ ] If count = 500, fetched additional pages
```

**DO NOT PROCEED TO PHASE 2 UNTIL ALL BOXES ARE CHECKED.**

---

## EXECUTION CHECKLIST

- [ ] Fetched ALL pages of issues (pagination complete)
- [ ] Fetched ALL pages of PRs for correlation
- [ ] Launched 1 agent per issue (not batched)
- [ ] All agents ran in background (parallel)
- [ ] Collected all results before generating report
- [ ] Report includes draft responses where applicable
- [ ] Critical issues flagged at top

---

## Quick Start

When invoked, immediately:

1. `gh repo view --json nameWithOwner -q .nameWithOwner` (get current repo)
2. Parse user's time range request (default: 48 hours)
3. Exhaustive pagination for issues AND PRs
4. Launch N background agents (1 per issue)
5. Collect all results
6. Generate categorized report with action items

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…