pr-rules-sync

Mines a GitHub repository's pull request history to discover recurring review patterns and common mistakes, then generates or updates AI agent instruction files (CLAUDE.md, .cursorrules, AGENTS.md) with those inferred rules. Use this skill whenever a developer wants to: sync AI rules from PR history, update their CLAUDE.md or cursorrules from past code reviews, analyze what reviewers keep flagging in a repo, extract team coding patterns from GitHub PRs, or make an AI agent learn from past code review feedback. Also trigger for requests like "what does my team always comment on?", "keep my AI rules up to date", "mine rules from my repo", or "what mistakes do we keep making?"

PR Rules Sync

You help developers extract recurring code review patterns from their GitHub PR history and bake those patterns into their AI agent instruction files — so the next AI session can avoid the same mistakes reviewers keep catching.

Overview of the workflow

  1. Connect to GitHub (detect what's available)
  2. Fetch PRs using the smart default strategy
  3. Analyze comments + diffs to find recurring patterns
  4. Write a clearly-marked section to the chosen instruction file(s)

Step 1 — Understand the context

Ask the user for:

  • The GitHub repository (owner/repo format, or full URL). If there's already a gh auth or a remote in the current working directory, detect it automatically with gh repo view --json nameWithOwner.
  • Which instruction file(s) to update. Offer these choices:
    • CLAUDE.md (Claude Code / Cowork)
    • .cursorrules or .cursor/rules/*.mdc (Cursor IDE)
    • AGENTS.md (OpenAI Codex / other agents)
    • Custom path
    • All of the above
  • Whether there's a specific area they want to focus on (optional — e.g. "security", "TypeScript", "API layer"). If they don't specify, cast a wide net.

Step 2 — Connect to GitHub

Try these in order, use the first that works:

  1. gh CLI — this is the preferred method. Check with which gh && gh auth status. The CLI is fast, token-efficient, and handles pagination cleanly. If authenticated, use it exclusively.

    gh pr list --repo <owner/repo> --state merged --limit 100 --json number,title,comments,reviews
    
  2. GitHub REST API with token — if gh isn't available but the user has a GITHUB_TOKEN env var or provides one:

    curl -H "Authorization: Bearer $GITHUB_TOKEN" \
      "https://api.github.com/repos/<owner>/<repo>/pulls?state=closed&per_page=100"
    
  3. GitHub MCP — fall back to MCP tools (mcp__github__*) only if neither of the above work. MCP is convenient but tends to be slower and more token-heavy for bulk data fetching like this workflow requires.

  4. Prompt the user — if none of the above work, tell them what to set up. Recommend gh as the easiest path: brew install gh && gh auth login.


Step 3 — Fetch PRs and build reviewer seniority profiles

This step does two things in parallel: fetch the PRs you'll analyze, and build a seniority map for every reviewer. The seniority map is what lets you weight comments appropriately in the analysis step.

Pass 1 — Wide historical fetch for reviewer profiling (up to 200 PRs)

Fetch a broad slice of the repo's history — you won't read all of these deeply, but you need them to figure out when each reviewer first appeared:

gh pr list --repo <owner/repo> --state merged --limit 200 \
  --json number,reviews \
  | python3 -c "
import json, sys
prs = json.load(sys.stdin)
# Build: reviewer -> earliest PR number they reviewed
reviewer_first = {}
for pr in prs:
    for review in pr.get('reviews', []):
        login = review.get('author', {}).get('login', '')
        if login and login not in reviewer_first:
            reviewer_first[login] = pr['number']
        elif login:
            reviewer_first[login] = min(reviewer_first[login], pr['number'])
# Sort by earliest PR number ascending (lower = more tenure)
ranked = sorted(reviewer_first.items(), key=lambda x: x[1])
total = len(ranked)
for i, (login, first_pr) in enumerate(ranked):
    tier = 'anchor' if i < total * 0.25 else ('regular' if i < total * 0.75 else 'occasional')
    print(f'{login},{first_pr},{tier}')
"

This gives you a seniority tier for each reviewer:

  • Anchor (top 25% by tenure) — been reviewing since early in the repo's life; deep institutional context
  • Regular (middle 50%) — solid reviewers with meaningful codebase history
  • Occasional (bottom 25%) — newer or infrequent reviewers; may still be valuable but carry less weight

The underlying logic: a reviewer who first appeared in PR #8 when the repo is now at PR #200 has seen the codebase through many architectural shifts, refactors, and bug patterns. Their feedback reflects accumulated knowledge of why certain mistakes matter in this specific codebase, not just general best practices.

Pass 2 — Select the top 30 PRs for deep analysis

From the recent 60 PRs (or all PRs if the repo is small), rank by comment density and take the top 30:

gh pr list --repo <owner/repo> --state merged --limit 60 \
  --json number,title,author,mergedAt,comments,reviewDecision

Rank by total comment count. Take the top 30. If you have fewer than 20 PRs total, use all of them.


Step 4 — Fetch the review content for each selected PR

For each of the top 30 PRs, fetch:

  • Review comments (inline, on specific lines of code) — these are the highest-signal data because they point at exactly what was wrong and where
  • PR-level comments (general discussion) — useful for architectural and process feedback
  • The diff (optional, for context when a comment references code) — only fetch if needed to understand a comment; avoid pulling full diffs for every PR, it's expensive
# Inline review comments
gh api repos/<owner>/<repo>/pulls/<number>/comments

# PR-level comments
gh api repos/<owner>/<repo>/issues/<number>/comments

# Review bodies (reviewer's summary comments)
gh api repos/<owner>/<repo>/pulls/<number>/reviews

Step 5 — Analyze patterns

This is the core of the skill. Read through all the review comments and look for recurrence — the same kind of feedback appearing across multiple PRs, multiple authors, multiple files.

Think like a senior engineer trying to write down "the unwritten rules of this codebase." You're not just listing every comment; you're distilling the themes.

What to look for

High-signal patterns (prioritize these):

  • The same class of bug or oversight mentioned in 3+ PRs (e.g., "missing null check", "not handling errors")
  • Style/naming patterns that reviewers consistently correct (e.g., "use camelCase for handlers", "don't abbreviate")
  • Architecture or layering rules (e.g., "don't call DB from controllers", "services shouldn't import each other")
  • Missing practices that reviewers always add (e.g., "add a test for edge case", "log the error before rethrowing")
  • Security patterns (e.g., "sanitize user input before passing to query", "don't hardcode secrets")

Lower-signal noise (skip or minimize):

  • One-off style nits on a single PR
  • Comments that are questions, not corrections
  • Comments from the PR author responding to reviews
  • Merge commit messages, bot comments, CI/CD messages

Clustering with reviewer seniority weighting

Group similar comments into a named pattern, and compute a weighted score for each:

  • Each comment from an anchor reviewer contributes 3 points to the pattern's score
  • Each comment from a regular reviewer contributes 2 points
  • Each comment from an occasional reviewer contributes 1 point

This reflects the fact that an anchor reviewer's repeated feedback almost certainly describes a real codebase-specific convention, whereas a single occasional reviewer's comment may just be personal preference.

A few important nuances:

  • Cross-tier validation raises confidence. If both anchor and occasional reviewers flag the same pattern independently, that's strong signal — multiple people with different experience levels all noticed it.
  • Frequency still matters. A pattern mentioned 8 times by occasional reviewers (8 points total) still outweighs a one-off comment from an anchor reviewer (3 points). The weighting shifts the signal, it doesn't override it.
  • Don't discard occasional reviewer comments entirely. They may catch things senior people have stopped noticing because they've internalized the rule. Occasional reviewer patterns that score ≥3 points are worth including if they're specific and actionable.

Example:

  • data / res naming issue flagged in 5 PRs: 2 by @sarah (anchor, 3pts each) + 3 by @mike (regular, 2pts each) → score = 12 points → high priority rule
  • One-off style nit by @newdev (occasional): score = 1 point → skip unless it appears in multiple PRs

Aim for 10–25 distinct patterns, sorted by weighted score descending. Fewer is better than more.

Evidence

For each pattern, pick the single best example from the actual review comments or diff — a short snippet (3–8 lines max) that makes the rule concrete and memorable. If the diff is needed to show the before/after, include both. This is what transforms a vague rule into something the AI can actually apply.


Step 6 — Structure the output

Organize the inferred rules into these categories (only include categories where you actually found patterns):

  • Error Handling & Async — promise rejections, try/catch, error propagation
  • Naming & Readability — variable names, function names, clarity
  • Architecture & Layering — module boundaries, dependency rules, separation of concerns
  • Testing — missing test cases, test quality, edge cases
  • Security — input validation, auth checks, secrets
  • Performance — N+1 queries, unnecessary loops, caching
  • Style & Conventions — formatting, imports, file structure specific to this repo
  • Documentation & Comments — when/how to comment, JSDoc, README

If a pattern doesn't fit neatly, put it in a general "Team Patterns" section.


Step 7 — Write to the instruction file(s)

Finding the file

Look for the instruction file in the repo root or the user's current working directory. Common locations:

  • ./CLAUDE.md, ./AGENTS.md, ./.cursorrules, ./.cursor/rules/

If the file doesn't exist, create it with a minimal header.

What to append

Add this section at the end of the file (do NOT touch existing content):

---

## Inferred from PR Review History
> Auto-generated by pr-rules-sync on <DATE>. Based on analysis of <N> pull requests in <owner/repo>.
> Re-run this skill to refresh as the codebase evolves.

### <Category Name>

**Rule**: <Concise rule statement — what to do or avoid>

**Why**: <One sentence explaining why reviewers care about this — the reasoning behind the rule>

**Signal**: Raised in <N> PRs · anchor reviewers: <names> · score: <weighted score>

**Example from PR #<N>**:
```<language>
// ❌ What was changed
<before snippet>

// ✅ What reviewers asked for
<after snippet>
<repeat for each rule in this category> ```

The Signal line is important — it tells the AI agent (and any human reading the file) how confident to be in each rule. A rule raised by two anchor reviewers across 8 PRs deserves much more weight than a rule raised once by an occasional reviewer. This context helps the agent calibrate how hard to enforce each rule.

Tone for the rules

Write rules in the imperative, as direct instructions to the AI agent:

  • "Always validate X before Y" not "Validation of X should happen before Y"
  • "Never import Z from W" not "It is not recommended to import Z from W"
  • "Use X pattern when Y" not "The X pattern is preferred for Y"

Keep each rule to 1–2 sentences. The code example carries the weight of explanation.


Step 8 — Report back to the user

After writing:

  1. Tell the user which file was updated and how many rules were added
  2. Give a brief summary of the top 3–5 patterns you found — these are the most important ones worth knowing about
  3. Mention roughly how many PRs were analyzed and the date range
  4. Optionally suggest: "Re-run this skill periodically (e.g. monthly or after a big sprint) to keep the rules fresh"

Example summary format:

✅ Updated CLAUDE.md with 18 inferred rules across 5 categories.
Analyzed 30 PRs from Jan 2025 – Mar 2026.
Reviewer tiers: @sarah, @mike, @lisa (anchor) · @dev1, @dev2 (regular) · @newjoin (occasional)

Top patterns found (by weighted score):
• [score 24 · anchor] Error handling: async errors were the most common miss — @sarah + @mike flagged in 11 PRs
• [score 18 · anchor] Architecture: service layer importing from controllers — @mike flagged 6 times
• [score 12 · mixed]  Naming: generic variable names (data, res, tmp) — flagged by all tiers across 8 PRs
• [score 9  · regular] Testing: edge cases missing — @dev1 + @dev2 flagged in 5 PRs
• [score 6  · anchor] Security: unvalidated user input in DB queries — @lisa flagged in 4 PRs

Tips for large repos

  • If a repo has 500+ PRs, the smart default (recent 60 → top 30 by comments) is usually enough. Don't try to process everything — quality beats quantity for pattern detection.
  • If the user wants to focus on a specific directory or module (e.g. "only look at the API layer"), filter PRs by files changed: gh pr list --search "is:merged" | xargs or use the files endpoint per PR.
  • For monorepos, ask the user if they want repo-wide rules or package-specific rules.

Tips for small/new repos

  • If there are fewer than 10 PRs with comments, be honest: tell the user the sample is small and the rules may not be highly representative yet. Still generate what you can, but note the caveat in the output file.

Keeping it fresh

The generated section includes a timestamp and re-run instruction. Each time the skill runs:

  • It finds any existing ## Inferred from PR Review History section and replaces it (not appends again)
  • This prevents duplicate sections building up over time

To find and replace an existing section, look for the marker ## Inferred from PR Review History and remove everything from that line to the end of the file (or to the next --- separator), then append the new section.