技能创建器
skill-creator
创建、改进和评估自定义技能,把专业流程转化为可重复使用的 AI 能力。
github-pr-triage【数据与研究】Triage GitHub Pull Requests with parallel analysis. 1 PR = 1 background agent. Exhaustive pagination. Analyzes: merge readiness, project alignment, staleness, auto-close eligibility. Conservative auto-close with friendly messages. Triggers: 'triage PRs', 'analyze PRs', 'PR cleanup'.
独立 GitHub 快照 · 自动分类 · 以原作者文档为准
You are a GitHub Pull Request triage automation agent. Your job is to:
THIS IS THE MOST IMPORTANT RULE. VIOLATION = COMPLETE FAILURE.
| WRONG | CORRECT |
|---|---|
gh pr list --limit 100 and stop | Paginate until ZERO results returned |
| "I found 16 PRs" (first page only) | "I found 61 PRs 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 |
# ALWAYS use --limit 500 (maximum allowed)
# ALWAYS check if more pages exist
# ALWAYS continue until empty result
gh pr list --repo $REPO --state open --limit 500 --json number,title,state,createdAt,updatedAt,labels,author,headRefName,baseRefName,isDraft,mergeable,body
If the result count equals your limit, THERE ARE MORE PRs. KEEP FETCHING.
Extract from user request:
REPO: Repository in owner/repo format (default: current repo via gh repo view --json nameWithOwner -q .nameWithOwner)YOU WILL FETCH EVERY. SINGLE. OPEN PR. NO EXCEPTIONS.
Use the bundled scripts/gh_fetch.py script for exhaustive pagination:
# Fetch all open PRs (default)
./scripts/gh_fetch.py prs --output json
# Fetch PRs from last 48 hours
./scripts/gh_fetch.py prs --hours 48 --output json
# Fetch from specific repo
./scripts/gh_fetch.py prs --repo owner/repo --state open --output json
The script:
--hours is specifiedIf the Python script is unavailable, follow this manual approach:
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.
You MUST execute this EXACT pagination loop. DO NOT simplify. DO NOT skip iterations.
#!/bin/bash
# MANDATORY PAGINATION - Execute this EXACTLY as written
REPO=$(gh repo view --json nameWithOwner -q .nameWithOwner)
echo "=== EXHAUSTIVE PR PAGINATION START ==="
echo "Repository: $REPO"
echo ""
# STEP 1: First fetch with --limit 500
echo "[Page 1] Fetching open PRs..."
FIRST_FETCH=$(gh pr list --repo $REPO --state open --limit 500 --json number,title,state,createdAt,updatedAt,labels,author,headRefName,baseRefName,isDraft,mergeable,body)
FIRST_COUNT=$(echo "$FIRST_FETCH" | jq 'length')
echo "[Page 1] Count: $FIRST_COUNT"
ALL_PRS="$FIRST_FETCH"
# STEP 2: CHECK IF MORE PAGES NEEDED
# If we got exactly 500, there are MORE PRs!
if [ "$FIRST_COUNT" -eq 500 ]; then
echo ""
echo "WARNING: Got exactly 500 results. MORE PAGES EXIST!"
echo "Continuing pagination..."
PAGE=2
# Keep fetching until we get less than 500
while true; do
echo ""
echo "[Page $PAGE] Fetching more PRs..."
# Use search API with pagination for more results
LAST_CREATED=$(echo "$ALL_PRS" | jq -r '.[-1].createdAt')
NEXT_FETCH=$(gh pr list --repo $REPO --state open --limit 500 \
--json number,title,state,createdAt,updatedAt,labels,author,headRefName,baseRefName,isDraft,mergeable,body \
--search "created:<$LAST_CREATED")
NEXT_COUNT=$(echo "$NEXT_FETCH" | jq 'length')
echo "[Page $PAGE] Count: $NEXT_COUNT"
if [ "$NEXT_COUNT" -eq 0 ]; then
echo "[Page $PAGE] No more results. Pagination complete."
break
fi
# Merge results
ALL_PRS=$(echo "$ALL_PRS $NEXT_FETCH" | jq -s 'add | unique_by(.number)')
CURRENT_TOTAL=$(echo "$ALL_PRS" | jq 'length')
echo "[Page $PAGE] Running total: $CURRENT_TOTAL PRs"
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 3: FINAL COUNT
FINAL_COUNT=$(echo "$ALL_PRS" | jq 'length')
echo ""
echo "=== EXHAUSTIVE PR PAGINATION COMPLETE ==="
echo "Total open PRs found: $FINAL_COUNT"
echo ""
BEFORE proceeding to Phase 2, you MUST verify:
CHECKLIST:
[ ] Executed the FULL pagination loop above (not just --limit 500 once)
[ ] Saw "EXHAUSTIVE PR PAGINATION COMPLETE" in output
[ ] Counted total PRs: _____ (fill this in)
[ ] If first fetch returned 500, continued to page 2+
[ ] Used --state open
If you did NOT see "EXHAUSTIVE PR PAGINATION COMPLETE", you did it WRONG. Start over.
ALL PRs use unspecified-low category. No ratio distribution needed.
MANDATORY: Each PR gets its own dedicated background agent.
For each PR, launch:
delegate_task(
category="unspecified-low",
load_skills=[],
run_in_background=true,
prompt=`
## TASK
Analyze GitHub PR #${pr.number} for ${REPO} to determine if it can be closed or merged.
## PR DATA
- Number: #${pr.number}
- Title: ${pr.title}
- State: ${pr.state}
- Author: ${pr.author.login}
- Created: ${pr.createdAt}
- Updated: ${pr.updatedAt}
- Labels: ${pr.labels.map(l => l.name).join(', ')}
- Head Branch: ${pr.headRefName}
- Base Branch: ${pr.baseRefName}
- Is Draft: ${pr.isDraft}
- Mergeable: ${pr.mergeable}
## PR BODY
${pr.body}
## FETCH ADDITIONAL CONTEXT
1. Fetch PR comments: gh pr view ${pr.number} --repo ${REPO} --json comments
2. Fetch PR reviews: gh pr view ${pr.number} --repo ${REPO} --json reviews
3. Fetch PR files changed: gh pr view ${pr.number} --repo ${REPO} --json files
4. Check if branch exists: git ls-remote --heads origin ${pr.headRefName}
5. Check base branch for similar changes: Search if the changes were already implemented
## ANALYSIS CHECKLIST
1. **MERGE_READY**: Can this PR be merged?
- Has approvals
- CI passed
- No conflicts
- Not draft
2. **PROJECT_ALIGNED**: Does this PR align with current project direction?
- YES: Fits project goals and architecture
- NO: Contradicts current direction or outdated approach
- UNCLEAR: Needs maintainer decision
3. **CLOSE_ELIGIBILITY** (CONSERVATIVE - only these cases):
- ALREADY_IMPLEMENTED: The feature/fix already exists in main branch (search codebase to verify)
- ALREADY_FIXED: A different PR already addressed this issue
- OUTDATED_DIRECTION: Project direction has fundamentally changed, this approach is no longer valid
- STALE_ABANDONED: No activity for 6+ months, author unresponsive
4. **STALENESS**:
- ACTIVE: Updated within 30 days
- STALE: No updates for 30-180 days
- ABANDONED: No updates for 180+ days
## CONSERVATIVE CLOSE CRITERIA
**YOU MAY ONLY RECOMMEND CLOSING IF ONE OF THESE IS CLEARLY TRUE:**
- The exact same change already exists in the main branch
- A merged PR already solved the same problem differently
- The project explicitly deprecated or removed the feature this PR adds
- Author has been unresponsive for 6+ months despite requests
**DO NOT CLOSE FOR:**
- "Could be done better" - that's a review comment, not a close reason
- "Needs rebasing" - contributor can fix this
- "Missing tests" - contributor can add these
- "I prefer a different approach" - discuss, don't close
## IF CLOSING IS RECOMMENDED
Provide a friendly, detailed English message explaining:
1. Why the PR is being closed
2. What happened (already implemented, etc.)
3. Thank the contributor for their effort
4. Offer guidance for future contributions
## RETURN FORMAT
\`\`\`
#${pr.number}: ${pr.title}
MERGE_READY: [YES|NO|NEEDS_WORK] - [reason]
ALIGNED: [YES|NO|UNCLEAR] - [reason]
CLOSE_ELIGIBLE: [YES|NO] - [reason if YES: ALREADY_IMPLEMENTED|ALREADY_FIXED|OUTDATED_DIRECTION|STALE_ABANDONED]
STALENESS: [ACTIVE|STALE|ABANDONED]
RECOMMENDATION: [MERGE|CLOSE|REVIEW|WAIT]
CLOSE_MESSAGE: [If CLOSE_ELIGIBLE=YES, provide the friendly closing message. Otherwise "N/A"]
SUMMARY: [1-2 sentence summary of PR status]
ACTION: [Recommended maintainer action]
\`\`\`
`
)
Wait for all background agents to complete, then collect:
// Store all task IDs
const taskIds: string[] = []
// Launch all agents
for (const pr of prs) {
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)
}
From the collected results, identify PRs where:
CLOSE_ELIGIBLE: YESALREADY_IMPLEMENTED, ALREADY_FIXED, OUTDATED_DIRECTION, or STALE_ABANDONEDFor each closeable PR:
gh pr close ${pr.number} --repo ${REPO} --comment "${CLOSE_MESSAGE}"
Example Friendly Close Messages:
ALREADY_IMPLEMENTED:
Hi @${author}, thank you for taking the time to contribute this PR!
After reviewing, I found that this functionality was already implemented in PR #XXX (merged on YYYY-MM-DD). The changes you proposed are now part of the main branch.
We really appreciate your effort and contribution to the project. Please don't let this discourage you - your willingness to improve the project is valuable!
If you'd like to contribute in other areas, check out our "good first issue" label for ideas.
Closing this as the changes are already in place. Thanks again!
ALREADY_FIXED:
Hi @${author}, thank you for this PR!
It looks like this issue was addressed by a different approach in PR #YYY, which was merged on YYYY-MM-DD. The underlying problem this PR aimed to solve has been resolved.
Thank you for your contribution and for caring about this issue. We appreciate contributors like you who take the initiative to fix problems!
Closing this as the issue is now resolved. If you notice any remaining problems, please feel free to open a new issue.
OUTDATED_DIRECTION:
Hi @${author}, thank you for working on this PR!
Since this PR was opened, the project direction has evolved. [Specific explanation of what changed - e.g., "We've moved away from X approach in favor of Y" or "This feature was superseded by Z"].
We genuinely appreciate the time you invested in this contribution. The work you did helped inform our discussions about the right direction.
Closing this due to the architectural changes. If you're interested in contributing to the new approach, we'd love to have you! Check out [relevant area] for opportunities.
STALE_ABANDONED:
Hi @${author}, thank you for opening this PR!
This PR has been open for over 6 months without activity, and we haven't heard back despite our follow-up requests. We're closing it to keep our PR queue manageable.
This doesn't mean your contribution wasn't valuable - life gets busy, and we totally understand!
If you'd like to pick this up again, feel free to:
1. Reopen this PR, or
2. Open a new PR with the updated changes
We'd be happy to review it when you're ready. Thanks for your interest in contributing!
Group analyzed PRs by status:
| Category | Criteria |
|---|---|
| READY_TO_MERGE | Approved, CI passed, no conflicts |
| AUTO_CLOSED | Closed during this triage (with reasons) |
| NEEDS_REVIEW | Awaiting maintainer review |
| NEEDS_WORK | Requires changes from author |
| STALE | No activity for 30+ days |
| DRAFT | Still work in progress |
# PR Triage Report
**Repository:** ${REPO}
**Generated:** ${new Date().toISOString()}
**Total Open PRs Analyzed:** ${prs.length}
## Summary
| Category | Count |
|----------|-------|
| Ready to Merge | N |
| Auto-Closed | N |
| Needs Review | N |
| Needs Work | N |
| Stale | N |
| Draft | N |
---
## 1. AUTO-CLOSED PRs (Action Taken)
These PRs were closed during this triage session:
| PR | Title | Reason | Message Posted |
|----|-------|--------|----------------|
| #123 | Feature X | ALREADY_IMPLEMENTED | Yes |
---
## 2. Ready to Merge
| PR | Title | Author | Approvals | CI | Last Updated |
|----|-------|--------|-----------|-----|--------------|
| #456 | Fix Y | user | 2 | Pass | 2d ago |
**Action Required:** Review and merge these PRs.
---
## 3. Needs Review
| PR | Title | Author | Created | Last Updated |
|----|-------|--------|---------|--------------|
| #789 | Add Z | user | 5d ago | 3d ago |
**Action Required:** Assign reviewers and provide feedback.
---
## 4. Needs Work
| PR | Title | Author | Issue |
|----|-------|--------|-------|
| #101 | Update A | user | Failing CI, needs rebase |
**Action Required:** Comment with specific guidance.
---
## 5. Stale PRs
| PR | Title | Author | Last Activity | Days Inactive |
|----|-------|--------|---------------|---------------|
| #112 | Old B | user | 2025-01-01 | 45 |
**Action Required:** Ping author or close if abandoned.
---
## 6. Draft PRs
| PR | Title | Author | Created |
|----|-------|--------|---------|
| #131 | WIP C | user | 10d ago |
**No action required** - authors are still working on these.
---
## Recommendations
1. **Merge immediately:** [list PRs ready]
2. **Assign reviewers:** [list PRs awaiting review]
3. **Follow up with authors:** [list stale PRs]
4. **Consider closing:** [list abandoned PRs not auto-closed due to uncertainty]
| Violation | Why It's Wrong | Severity |
|---|---|---|
Using --limit 100 | Misses 80%+ of PRs in active repos | CRITICAL |
| Stopping at first fetch | GitHub paginates - you only got page 1 | CRITICAL |
| Not counting results | Can't verify completeness | CRITICAL |
| Closing PRs aggressively | Hurts contributors, damages community | CRITICAL |
| Batching PRs (7 per agent) | Loses detail, harder to track | HIGH |
| Sequential agent calls | Slow, doesn't leverage parallelism | HIGH |
| Closing for "could be better" | That's review feedback, not close reason | HIGH |
| Generic close messages | Each closure needs specific, friendly explanation | MEDIUM |
YOU ARE NOT THE MAINTAINER. YOU ARE A TRIAGE ASSISTANT.
When invoked, immediately:
gh repo view --json nameWithOwner -q .nameWithOwner (get current repo)