| name | next |
| description | Triage open GitHub issues and recommend what to work on next. Builds a dependency graph from issue bodies, detects circular dependencies, ranks unblocked issues by weighted scoring (blocks-others, priority, type, age, milestone), and presents top candidates for interactive selection. Triggers: what should I work on next, triage backlog, next issue, pick next task, recommend issue, prioritize issues. |
| user-invocable | true |
| allowed-tools | ["Bash","Read","Grep","Glob","AskUserQuestion"] |
| metadata | {"author":"claude-pm","version":"2.0"} |
Next: Issue Triage & Recommendation
Analyze open GitHub issues, build a dependency graph, and recommend the highest-impact issue to work on next.
Workflow
1. Fetch & Pre-process โ 2. Build Dependency Graph โ 3. Detect Cycles
โ 4. Rank Issues โ 5. Present Recommendations โ 6. Select & Assign
Step 1: Fetch and Pre-process Issues
Run the open-issues.sh script from the plugin's scripts/ directory (two levels up from this skill):
sh ../../scripts/open-issues.sh
sh ../../scripts/open-issues.sh OWNER/REPO
sh ../../scripts/open-issues.sh --include-assigned
Validate the response:
- Check stderr for a JSON
error object โ if present, abort with the error message (auth failures, missing tools, repo detection failures are handled by the script)
- Extract and store the full JSON output as
$ISSUES_DATA
Edge case โ no issues: If .total_open == 0, report "No open issues found" (if --include-assigned was used) or "No unassigned issues found (try --include-assigned to include assigned items)" (default mode) and stop.
Edge case โ 100+ issues: If .total_open >= 100, warn: "Results capped at 100 issues. Consider filtering by label or milestone for a broader view."
The JSON output contains pre-computed fields for each issue:
blocked_by, blocks โ parsed from issue body patterns (Blocked by:, Blocks:, Depends on:)
blockers_resolved โ true if all blockers are closed (not in the open issue set)
unblocked โ true if no open blockers remain
age_days โ days since issue creation
milestone_due_on โ milestone due date (ISO 8601) or null
dependency_graph.edges โ [[blocker, blocked], ...] pairs for graph analysis
Step 2: Build Dependency Graph
The script pre-computes blocked_by and blocks arrays per issue, and provides dependency_graph.edges as [[blocker, blocked], ...] pairs.
Build two maps from the pre-computed data:
blockedBy[issue] โ Set<issue> โ from each issue's .blocked_by array
blocks[issue] โ Set<issue> โ from each issue's .blocks array
Blocker resolution is already handled by the script via blockers_resolved/unblocked; the blocked_by/blocks arrays still list all referenced issues (including closed ones). Use the unblocked flag to determine eligibility.
Edge case โ no dependency markers found: If dependency_graph.edges is empty, skip Step 3 (no cycles possible) and omit the "blocks others" dependency weight factor from Step 4 ranking. Rank purely on priority, type, age, and milestone.
Step 3: Detect Circular Dependencies
Using dependency_graph.edges from Step 1, run DFS traversal on the blockedBy graph to detect cycles.
If cycles found:
- Report each cycle: e.g., "#12 โ #15 โ #12"
- Warn the user that these issues are mutually blocked
- Exclude all issues in cycles from recommendations
- Suggest the user resolve the cycle by editing one of the issues
If no cycles: Proceed to ranking.
Step 4: Rank Unblocked Issues
An issue is eligible if:
unblocked == true (all blockers are resolved โ pre-computed by the script)
- It is not assigned to anyone (
.assignees is empty), unless --include-assigned was used
- It is not in a cycle (from Step 3)
Scoring formula โ Total = ฮฃ (Weight ร Score) for each factor:
| Factor | Weight | Score | Notes |
|---|
| Blocks others | 3 | +3 per issue this unblocks | e.g., unblocks 2 โ 3 ร 6 = 18 |
| Priority label | 2 | P0=8, P1=6, P2=4, P3=2, none=3 | none > P3: unlabeled may be anything; explicitly-low is known-low |
| Type label | 1 | bug=5, security=5, enhancement=3, chore=2, research=1, none=2 | Default none=2 โ treat unlabeled same as chore |
| Age | 1 | +1 per 7 days (use age_days from Step 1, max +8) | Caps at 56 days to avoid age dominating |
| Milestone | 1 | +4 / +2 / 0 (see below) | Heuristic below for "current/next" detection |
Milestone heuristic: Compare milestone due_on dates. The milestone with the earliest future (or most recently past) due date is "current"; the next one is "next" โ these score +4. All other milestones score +2. Milestones without due_on default to +2. No milestone = 0.
Sort by total score descending. Break ties by issue number (lower = older = first).
Step 5: Present Recommendations
Show the top 3-5 issues in a structured table:
## Recommended Next Issues
| Rank | Issue | Title | Score | Key Factor |
|------|-------|-------|-------|------------|
| 1 | #42 | Fix auth token refresh | 24 | Unblocks #43, #44, #45 |
| 2 | #38 | Add rate limiting | 18 | P0-critical, 3 weeks old |
| 3 | #51 | Update CI pipeline | 14 | Blocks #52, in v2.0 milestone |
For each recommendation, show a brief rationale:
- What makes it high-priority
- What it unblocks (if anything)
- How old it is
- Any milestone context
Edge case โ all issues are assigned: Report that all eligible issues have assignees. Show the top 3 anyway with their current assignees, and ask if the user wants to pick one up regardless.
Edge case โ all issues are blocked: Report the blocking chain. Identify the root blockers (issues that block others but aren't blocked themselves) and recommend those first.
Step 6: Interactive Selection
Use AskUserQuestion to let the user choose:
Question: "Which issue do you want to work on?"
Options:
- #42: Fix auth token refresh (Score: 24)
- #38: Add rate limiting (Score: 18)
- #51: Update CI pipeline (Score: 14)
- Show more issues
After selection:
- Show the full issue details (
gh issue view ISSUE_NUMBER)
- Ask: "Want me to assign this to you?"
- If yes:
gh issue edit ISSUE_NUMBER --add-assignee @me
- Suggest: "Run
/pm:update periodically to audit stale issues."