Pr Triage logo

Pr Triage

CommunityPopular
FlorianBruniaux
pr-triage

4-phase PR backlog management with audit, deep code review, validated comments, and optional worktree setup. Use when triaging pull requests, catching up on pending code reviews, or managing a backlog of open PRs. Args: 'all' to review all, PR numbers to focus (e.g. '42 57'), 'en'/'fr' for language, no arg = audit only.

Overview

PublisherFlorianBruniaux
Repositoryclaude-code-ultimate-guide
Skill namepr-triage
Stars
6K
Forks
782
Bundled files
1
LicenseCC-BY-SA-4.0
Links
  • Markdown instructions

    A SKILL.md file the model loads on demand, so it only costs tokens when a request actually matches.

  • Works with any LLM

    AI skills are plain Markdown, not provider-specific code, so this works with GPT, Claude, Gemini, Grok, or a local model.

  • 1 bundled files

    Scripts, templates, and references the model can read while it works. Files are read-only and never executed.

  • Open source

    Published by FlorianBruniaux on GitHub. Read the source before you install it.

Installation

Install the Pr Triage AI skill in TypingMind to use it with any LLM, or drop it into another agent that reads SKILL.md.

1

Install in TypingMind

TypingMind installs a skill straight from its GitHub folder — it reads SKILL.md, bundles the resource files, and stores the result locally.

  1. Open the app and go to Plugins → Skills.
  2. Choose "Install from GitHub".
  3. Paste the skill folder URL below and confirm.
  4. Enable the skill in any chat where you want it available.
Plugins → Skills → Add skill → From GitHub URL, then paste the folder URL and press Continue.
2

Install in another agent

Any agent that reads the Agent Skills format can use this skill — copy the folder into that agent's skills directory.

Claude Code — .claude/skills
git clone --depth 1 https://github.com/FlorianBruniaux/claude-code-ultimate-guide.git /tmp/claude-code-ultimate-guide
mkdir -p .claude/skills
cp -r /tmp/claude-code-ultimate-guide/examples/skills/pr-triage .claude/skills/pr-triage
Restart Claude Code after copying so it picks up the new skill.

Use it in TypingMind

Enable Pr Triage in any TypingMind chat and the model takes it from there. Its name and description sit in the system prompt, and the moment a request matches, the model loads the full instructions itself — you never invoke it by hand, and it costs no tokens until it is actually used.

The model loads Pr Triage on its own as soon as a request matches it.

Works with any AI model

AI skills are plain Markdown instructions rather than provider-specific code, so Pr Triage is not tied to the model it was written for. Install it once in TypingMind and use it with GPT-5, Claude, Gemini, Grok, DeepSeek, Mistral, Llama, or a local model you run yourself — all on your own API keys.

  • Loaded only when it is needed

    The system prompt carries just the name and description. The instructions are fetched on the first matching request, so an idle skill costs nothing.

  • Switch models mid-chat

    Because the skill is instructions rather than code, changing model does not break it — the next model reads the same SKILL.md.

Skill instructions

This is the SKILL.md content the model loads. Read it before installing — a skill is instructions your model will follow.

PR Triage

4-phase workflow for maintainers: automated audit of all open PRs, opt-in deep review via parallel agents, validated comment posting, and optional worktree setup for local review.

When to Use This Skill

SkillUsageOutput
/pr-triageSort, review, and comment on a PR backlogTriage table + reviews + posted comments
/review-prReview a single PR in depthInline PR review

Triggers:

  • Manually: /pr-triage or /pr-triage all or /pr-triage 42 57
  • Proactively: when >5 PRs open without review, or stale PR >14 days 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) are ALWAYS in English (international audience)

Configuration

Thresholds used throughout the workflow. Edit to match your project:

ParameterDefaultDescription
staleness_days14Days without activity before flagging as stale
overlap_threshold50%Shared files % to flag as overlapping
cluster_min_prs3Author PR count to trigger cluster suggestion
xl_cutoff_additions1000Additions above which a PR is classified XL
xl_cutoff_files10Changed files above which a PR is "too large"

Preconditions

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

If either fails, stop and explain what is missing.


Phase 1: Audit (always executed)

Data Gathering (parallel commands)

bash
gh repo view --json nameWithOwner -q .nameWithOwner
gh pr list --state open --limit 50 \
  --json number,title,author,createdAt,updatedAt,additions,deletions,changedFiles,isDraft,mergeable,reviewDecision,statusCheckRollup,body
gh api "repos/{owner}/{repo}/collaborators" --jq '.[].login'

Collaborators fallback: if gh api .../collaborators returns 403/404:

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

If still ambiguous, ask via AskUserQuestion.

For each PR, fetch reviews and changed files:

bash
gh api "repos/{owner}/{repo}/pulls/{num}/reviews" \
  --jq '[.[] | .user.login + ":" + .state] | join(", ")'
gh pr view {num} --json files --jq '[.files[].path] | join(",")'

Notes: Fetching files requires 1 API call per PR; for 20+ PRs, prioritize overlap candidates. The author field is an object; always extract .author.login.

Analysis

Size classification:

LabelAdditions
XS< 50
S50–200
M200–500
L500–1000
XL> 1000

Size format: +{additions}/-{deletions}, {files} files ({label})

Detections:

  • Overlaps: compare file lists across PRs; if >50% files in common → cross-reference
  • Clusters: author with 3+ open PRs → suggest review order (smallest first)
  • Staleness: no activity for >14 days → flag "stale"
  • CI status: via statusCheckRollupclean / unstable / dirty
  • Reviews: approved / changes_requested / none

PR ↔ Issue linking:

  • Scan each PR body for fixes #N, closes #N, resolves #N (case-insensitive)
  • If found, display in the table: Fixes #42 in the Action/Status column

Categorization:

Internal PRs: author in collaborators list

External, Ready: additions ≤ 1000 AND files ≤ 10 AND mergeableCONFLICTING AND CI clean/unstable

External, Problematic: any of:

  • additions > 1000 OR files > 10
  • OR mergeable == CONFLICTING (merge conflict)
  • OR CI dirty (statusCheckRollup contains failures)
  • OR overlap with another open PR (>50% shared files)

Output: Triage Table

## Open PRs ({count})

### Internal PRs
| PR | Title | Size | CI | Status |
| -- | ----- | ---- | -- | ------ |

### External: Ready for Review
| PR | Author | Title | Size | CI | Reviews | Action |
| -- | ------ | ----- | ---- | -- | ------- | ------ |

### External: Problematic
| PR | Author | Title | Size | Problem | Recommended Action |
| -- | ------ | ----- | ---- | ------- | ------------------ |

### Summary
- Quick wins: {XS/S PRs ready to merge}
- Risks: {overlaps, XL sizes, CI dirty}
- Clusters: {authors with 3+ PRs}
- Stale: {PRs with no activity >14d}
- Overlaps: {PRs touching the same files}

0 PRs → display No open PRs. and stop.

Navigation Post-Phase 1

After displaying the triage table, ask via AskUserQuestion:

question: "What would you like to do next?"
header: "Next Step"
options:
  - label: "Phase 2: Deep review"
    description: "Analyze selected PRs with code-reviewer agents and generate comment drafts"
  - label: "Phase 4: Create worktrees"
    description: "Set up local worktrees for hands-on review (skips comment generation)"
  - label: "Done"
    description: "End the workflow here"

Note: Phase 3 (posting comments) is NOT offered here, as it requires the drafts generated in Phase 2. If the user picks "Phase 4", Phase 2 → Phase 3 remains accessible afterward.

Automatic Copy

After displaying the triage table, copy to clipboard using platform-appropriate command:

bash
UNAME=$(uname -s)
if [ "$UNAME" = "Darwin" ]; then
  pbcopy <<'EOF'
{full triage table}
EOF
elif command -v xclip &>/dev/null; then
  echo "{full triage table}" | xclip -selection clipboard
elif command -v wl-copy &>/dev/null; then
  echo "{full triage table}" | wl-copy
elif command -v clip.exe &>/dev/null; then
  echo "{full triage table}" | clip.exe
fi

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


Phase 2: Deep Review (opt-in)

PR Selection

If argument passed:

  • "all" → all external PRs
  • Numbers ("42 57") → only those PRs
  • No argument → propose via AskUserQuestion

If no argument, display:

question: "Which PRs do you want to review in depth?"
header: "Deep Review"
multiSelect: true
options:
  - label: "All external"
    description: "Review {N} external PRs with parallel code-reviewer agents"
  - label: "Problematic only"
    description: "Focus on {M} risky PRs (CI dirty, too large, overlaps)"
  - label: "Ready only"
    description: "Review {K} PRs ready to merge"
  - label: "Skip"
    description: "Stop here, audit only"

Draft PR behavior:

  • Draft PRs are EXCLUDED from "All external" and "Ready only"
  • Draft PRs are INCLUDED in "Problematic only" (they need attention)
  • To review a draft: type its number explicitly (e.g. 42)

If "Skip" → end workflow.

Executing Reviews

For each selected PR, launch a code-reviewer agent via Task tool in parallel:

subagent_type: code-reviewer
model: sonnet
prompt: |
  Review PR #{num}: "{title}" by @{author}

  **Metadata**: +{additions}/-{deletions}, {changedFiles} files ({size_label})
  **CI**: {ci_status} | **Reviews**: {existing_reviews} | **Draft**: {isDraft}

  **PR Body**:
  {body}

  **Diff**:
  {gh pr diff {num} output}

  Apply your security and architecture expertise. Use the project-specific checklist
  from the SKILL.md Configuration section if available.

  Return structured review:
  ### Critical Issues
  ### Important Issues
  ### Suggestions
  ### What's Good

  Be specific: quote file:line, explain the issue, suggest the fix.

Fallback if parallel agents unavailable: run reviews sequentially, one PR at a time. Notify user: Running sequential review (parallel agents not available).

Fetch diff via:

bash
gh pr diff {num}
gh pr view {num} --json body,title,author -q '{body: .body, title: .title, author: .author.login}'

Aggregate all reports. Display a summary after all reviews complete.


Phase 3: Comments (mandatory validation)

Draft Generation

For each reviewed PR, generate a GitHub comment using the template templates/review-comment.md.

Rules:

  • Language: English (international audience)
  • Tone: professional, constructive, factual
  • Always include at least 1 positive point
  • Quote code lines when relevant (format file:42)

Display and Validation

Display ALL drafted comments in format:

---
### Draft: PR #{num}: {title}

{full comment}

---

Then request validation via AskUserQuestion:

question: "These comments are ready. Which ones do you want to post?"
header: "Post Comments"
multiSelect: true
options:
  - label: "All ({N} comments)"
    description: "Post on all reviewed PRs"
  - label: "PR #{x}: {title_truncated}"
    description: "Post only on this PR"
  - label: "None"
    description: "Cancel, post nothing"

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

Posting

For each validated comment:

bash
gh pr comment {num} --body-file - <<'REVIEW_EOF'
{comment}
REVIEW_EOF

Confirm each post: Comment posted on PR #{num}: {title}

If "None" → No comments posted. Workflow complete.


Project-Specific Checklist

Add your stack's checklist to the agent prompt in Phase 2. Examples by stack:

Node.js / TypeScript:

  • No any type without explicit justification
  • async/await error handling (try/catch or .catch())
  • No unhandled promise rejections
  • Input validation at API boundaries

Python:

  • Type hints on all public functions
  • Exception specificity (no bare except:)
  • Resource cleanup (with statements, context managers)
  • No mutable default arguments

Rust:

  • Result<T, E> with .context() for error chain (no .unwrap() in production code)
  • No clone() on hot paths without justification
  • lazy_static! or once_cell for static regex
  • Lifetime annotations where ownership is non-obvious

Go:

  • Explicit error handling (no _ discard without comment)
  • defer for resource cleanup
  • Context propagation in concurrent code
  • No goroutine leaks

Generic (stack-agnostic):

  • No secrets or hardcoded credentials
  • New public functions have tests
  • Breaking changes documented in PR body
  • Dependencies added have clear justification


Phase 4: Worktree Setup (opt-in)

Creates local git worktrees for each selected PR so you can run, test, or review code without switching branches.

Never triggered automatically. Only via Phase 1 navigation or explicit user request.

Step 4.1: Cache check + PR list

Cache check: before using data from Phase 1, verify it is less than 30 minutes old:

bash
CACHE_FILE="/tmp/pr-triage-prs.json"
CACHE_AGE=$(( $(date +%s) - $(stat -f %m "$CACHE_FILE" 2>/dev/null || echo 0) ))
if [ "$CACHE_AGE" -gt 1800 ]; then
  echo "STALE_CACHE"
fi

If STALE_CACHE → re-run the Phase 1 data gathering before continuing.

Filter: exclude Draft PRs and bot PRs (Dependabot, renovate, etc.):

bash
python3 -c "
import json
prs = json.load(open('/tmp/pr-triage-prs.json'))
filtered = [
  p for p in prs
  if not p['isDraft']
  and not any(bot in p['author']['login'].lower() for bot in ['dependabot', 'renovate', 'snyk'])
]
import sys; json.dump(filtered, sys.stdout, indent=2)
" > /tmp/pr-triage-phase4.json

If 0 PRs after filtering → display No reviewable PRs available for worktree (all are drafts or bots). + end Phase 4.

Display grouped by author (use display name if available, fallback to login):

## PRs available for worktree (non-draft)

### Alice Martin (@alice)
  [1] #123: feat(auth): add OAuth2 support
      Branch: feat/oauth2  |  Size: M  |  CI: clean

### Bob Chen (@bob)
  [2] #456: fix(api): handle empty response
      Branch: fix/empty-response  |  Size: S  |  CI: dirty ⚠️

Step 4.2: Selection

Ask via AskUserQuestion (multiSelect):

question: "Which PRs do you want to create a worktree for?"
header: "Worktree Setup"
multiSelect: true
options:
  - label: "All"
    description: "Create worktrees for all {N} listed PRs"
  - label: "[1] #{num}: {title} ({author})"
    description: "Branch: {branch} | Size: {size} | CI: {ci}"
  - label: "None"
    description: "Cancel, return to menu"

If "None" → end Phase 4.

Step 4.3: Sequential creation

Execution model: Claude runs one bash command per PR, reads its output, updates its internal state (created / existing / failed), then moves to the next. Never a bash loop wrapping all PRs.

For each selected PR, Claude sets variables explicitly then runs:

bash
PR_NUM="123"
BRANCH_NAME="feat/oauth2"
WORKTREE_NAME="${BRANCH_NAME//\//-}"
REPO_ROOT="$(cd "$(git rev-parse --git-common-dir)/.." && pwd)"
WORKTREE_DIR="$REPO_ROOT/.worktrees/$WORKTREE_NAME"

# Already exists?
if [ -d "$WORKTREE_DIR" ]; then
  echo "STATUS:EXISTING:$PR_NUM:$WORKTREE_DIR"
  exit 0
fi

# .gitignore check (fail-fast)
if ! grep -qE "^\.worktrees/?$" "$REPO_ROOT/.gitignore" 2>/dev/null; then
  echo "STATUS:GITIGNORE_MISSING:$PR_NUM"
  exit 1
fi

# Fetch remote branch
if ! git fetch origin "$BRANCH_NAME" 2>/tmp/wt-fetch-$PR_NUM.log; then
  echo "STATUS:FETCH_FAILED:$PR_NUM"
  exit 1
fi

mkdir -p "$REPO_ROOT/.worktrees"

# Create worktree (branch local exists or not)
if ! git branch --list "$BRANCH_NAME" | grep -q "$BRANCH_NAME"; then
  git worktree add -b "$BRANCH_NAME" "$WORKTREE_DIR" "origin/$BRANCH_NAME" \
    2>/tmp/wt-err-$PR_NUM.log
else
  git worktree add "$WORKTREE_DIR" "$BRANCH_NAME" \
    2>/tmp/wt-err-$PR_NUM.log
fi

if [ $? -ne 0 ]; then
  if grep -q "already checked out" /tmp/wt-err-$PR_NUM.log; then
    echo "STATUS:ALREADY_CHECKED_OUT:$PR_NUM"
  else
    echo "STATUS:CREATE_FAILED:$PR_NUM"
  fi
  exit 1
fi

# Optional: symlink node_modules (Node.js projects, avoids reinstall)
[ -d "$REPO_ROOT/node_modules" ] && ln -sf "$REPO_ROOT/node_modules" "$WORKTREE_DIR/node_modules"

# Copy project-specific files listed in .worktreeinclude (if present)
if [ -f "$REPO_ROOT/.worktreeinclude" ]; then
  while IFS= read -r entry || [ -n "$entry" ]; do
    [[ "$entry" =~ ^#.*$ || -z "$entry" ]] && continue
    entry="$(echo "$entry" | xargs)"
    [ -e "$REPO_ROOT/$entry" ] && {
      mkdir -p "$(dirname "$WORKTREE_DIR/$entry")"
      cp -R "$REPO_ROOT/$entry" "$WORKTREE_DIR/$entry"
    }
  done < "$REPO_ROOT/.worktreeinclude"
fi

echo "STATUS:CREATED:$PR_NUM:$WORKTREE_DIR"

Status handling (Claude maintains internal state between PRs):

StatusClaude action
STATUS:CREATED:NUM:PATHAdd to "created" list
STATUS:EXISTING:NUM:PATHAdd to "existing" list → offer pull in Step 4.4
STATUS:FETCH_FAILED:NUMWarn + continue to next PR
STATUS:GITIGNORE_MISSING:NUMFail-fast: show fix instructions + stop Phase 4
STATUS:ALREADY_CHECKED_OUT:NUMWarn: "Branch already checked out in another worktree. Run git worktree list to locate it."
STATUS:CREATE_FAILED:NUMWarn + continue to next PR

GITIGNORE_MISSING fix instructions:

.worktrees/ is not in .gitignore. Add it to avoid accidentally committing worktree files:
  echo ".worktrees/" >> .gitignore
Then re-run Phase 4.

Step 4.4: Update existing worktrees

If any STATUS:EXISTING collected, offer a single prompt:

Existing worktrees detected:
  PR #123: .worktrees/feat-oauth2
  PR #789: .worktrees/fix-session-leak

- [Pull all] git pull --ff-only in all existing worktrees
- [#123] Pull PR #123 only
- [Skip] Leave as-is

For each selected pull, Claude runs (one command per worktree):

bash
PR_NUM="123"
BRANCH_NAME="feat/oauth2"
WORKTREE_DIR="/abs/path/.worktrees/feat-oauth2"

cd "$WORKTREE_DIR" && git pull origin "$BRANCH_NAME" --ff-only 2>/tmp/wt-pull-$PR_NUM.log
echo "PULL_STATUS:$?:$PR_NUM"

If PULL_STATUS ≠ 0:

⚠️ PR #123: --ff-only failed (branches have diverged)
   Manual fix: cd .worktrees/feat-oauth2 && git pull --rebase

Step 4.5: Summary

## Worktrees ready

| PR | Author | Branch | Path | Status |
|----|--------|--------|------|--------|
| #123 | Alice | feat/oauth2 | .worktrees/feat-oauth2 | Created |
| #456 | Bob | fix/empty-response | .worktrees/fix-empty-response | Created |
| #789 | Alice | fix/session-leak | .worktrees/fix-session-leak | Updated (pull) |
| #321 | Carol | feat/chat | .worktrees/feat-chat | Fetch failed ⚠️ |

Note: if a PR modifies package.json, install dependencies manually:
  cd .worktrees/<branch-name> && npm install   # or pnpm/yarn/bun

Next steps:
  cd .worktrees/<branch-name>
  claude

.worktreeinclude convention

Create a .worktreeinclude file at the repo root to list files Phase 4 copies into each new worktree. Useful for local config files not tracked in git:

# .worktreeinclude
.env.local
.env.test
config/local.json

Edge Cases

SituationBehavior
0 open PRsDisplay No open PRs. + stop
Draft PRShow in table, skip for review unless explicitly selected
Unknown CIDisplay ? in CI column
Review agent timeoutShow partial error, continue with others
gh pr diff emptySkip this PR, notify user
Very large PR (>5000 additions)Warn: "Partial review, diff truncated"
Collaborators API 403/404Fallback to last 10 merged PR authors
Parallel agents unavailableRun sequential reviews, notify user
Phase 4: .gitignore missing .worktrees/Fail-fast, show fix instructions, stop Phase 4
Phase 4: branch already checked outWarn with git worktree list hint, skip this PR
Phase 4: stale cache (>30min)Re-fetch PR list before creating worktrees
Phase 4: PR modifies package.jsonWarn in summary to run install manually
Phase 4: 0 non-draft PRsDisplay message + end Phase 4

Notes

  • Always derive owner/repo via gh repo view, never hardcode
  • Use gh CLI (not curl GitHub API) except for collaborators list
  • statusCheckRollup can be null → treat as ?
  • mergeable can be MERGEABLE, CONFLICTING, or UNKNOWN → treat UNKNOWN as ?
  • Never post without explicit user validation in chat
  • Drafted comments must be visible BEFORE any gh pr comment

Related: /review-pr

/pr-triage/review-pr
ScopeFull PR backlogSingle PR
Use whenCatching up after accumulation, periodic triageReviewing a specific incoming PR
Phases4 (audit + deep review + comments + worktrees)1 (review only)
AgentsParallel sub-agents per PRSingle session
OutputTriage table + review reports + GitHub comments + local worktreesInline review
ValidationAskUserQuestion before postingManual decision

Decision rule: use /pr-triage for backlog triage (5+ PRs), /review-pr for focused review of a single PR. Use Phase 4 when you want to run the code locally rather than just reading the diff.

Bundled files

The model reads these on demand while the skill is loaded. They are exposed as readable files and are never executed.

Frequently asked questions

What does the Pr Triage AI skill do?

4-phase PR backlog management with audit, deep code review, validated comments, and optional worktree setup. Use when triaging pull requests, catching up on pending code reviews, or managing a backlog of open PRs. Args: 'all' to review all, PR numbers to focus (e.g. '42 57'), 'en'/'fr' for language, no arg = audit only.

Why use Pr Triage on TypingMind?

Because you install it once and use it with any model. Pr Triage is plain Markdown rather than provider-specific code, so the same skill runs on GPT-5, Claude, Gemini, Grok, or a local model — and you can switch model mid-chat without it breaking. TypingMind runs on your own API keys, so you pay providers directly instead of a per-seat subscription, and your skills and chats stay in your own storage.

How do I install Pr Triage in TypingMind?

Open Plugins → Skills → Install from GitHub in TypingMind and paste https://github.com/FlorianBruniaux/claude-code-ultimate-guide/tree/main/examples/skills/pr-triage. TypingMind reads its SKILL.md and bundles its files and installs it as a skill you can enable per chat.

Which AI models can use Pr Triage?

Any model you connect in TypingMind. AI skills are plain Markdown instructions rather than provider-specific code, so GPT, Claude, Gemini, Grok, and local models can all load this skill when a request matches it.

How many AI models can I use with Pr Triage?

As many as you like. As long as a model supports skills, you can use Pr Triage with it — GPT, Claude, Gemini, Grok, DeepSeek, Mistral, Llama and more — all on TypingMind with your own API keys.

Is the Pr Triage AI skill free?

Yes. It is published on GitHub by FlorianBruniaux under the CC-BY-SA-4.0 license. You only pay your own AI provider for the tokens you use.

What are AI skills?

An AI skill is a reusable instruction bundle that teaches an AI model how to do one specific task. It follows the open Agent Skills format: a SKILL.md file with a name and description, plus any scripts, templates or reference files the model may need. The model reads the instructions only when your request matches the skill, so an installed skill costs nothing until it is used.

How are AI skills different from plugins or MCP servers?

A plugin or MCP server gives a model new tools to call — code that runs somewhere and returns a result. An AI skill gives the model knowledge and process instead: how to approach a task, which steps to follow, what good output looks like. Skills are plain Markdown, so they need no server, no API key and no runtime, and they work with any model.

View all

Set up your own AI workspace now

Get notified about new features and future giveaways by subscribing to our newsletter 👇