Gh pr analysis
[COLM'26] SkillLearnBench is the first benchmark for evaluating continual learning methods that automatically generate agent skills.
npx -y skills add cxcscmu/SkillLearnBench --skill gh-pr-analysisAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
What its author says it does
Copied from the file, not written here
How to fetch and analyze pull request data from a GitHub repository for a given time period: counts, merge rates, average time-to-merge, and top contributors. Use this skill whenever the user wants PR metrics, pull request summaries, contributor leaderboards, or community pulse reports.
SKILL.md
3.0 KB, 707 tokens by cl100k_base, as published. Nobody here has run it
PR Analysis via GitHub REST API
Fetching PRs created in a date window
Use the /repos/{owner}/{repo}/pulls endpoint with state=all and since:
BASE = "https://api.github.com/repos/cli/cli"
def get_prs(start_iso, end_iso, token=None):
"""Fetch all PRs created between start_iso and end_iso (ISO 8601 strings)."""
headers = {"Accept": "application/vnd.github+json"}
if token:
headers["Authorization"] = f"token {token}"
start_dt = datetime.fromisoformat(start_iso.replace("Z", "+00:00"))
end_dt = datetime.fromisoformat(end_iso.replace("Z", "+00:00"))
results, page = [], 1
while True:
r = requests.get(f"{BASE}/pulls",
headers=headers,
params={"state": "all", "sort": "created",
"direction": "desc", "per_page": 100,
"page": page})
data = r.json()
if not data:
break
# Trim pages that are entirely before our window (sorted desc)
page_items = []
stop = False
for pr in data:
created = datetime.fromisoformat(pr["created_at"].replace("Z", "+00:00"))
if created > end_dt:
continue # too recent
if created < start_dt:
stop = True # gone past our window, no need to paginate further
break
page_items.append(pr)
results.extend(page_items)
if stop or len(data) < 100:
break
page += 1
return results
Key calculations
Merged vs closed-not-merged
merged = [p for p in prs if p.get("merged_at")]
# "closed" means closed without merge (GitHub convention in this report)
closed_not_merged = [p for p in prs if p["state"] == "closed" and not p.get("merged_at")]
Average time-to-merge (days, 1 decimal)
def ttm(pr):
c = datetime.fromisoformat(pr["created_at"].replace("Z", "+00:00"))
m = datetime.fromisoformat(pr["merged_at"].replace("Z", "+00:00"))
return (m - c).total_seconds() / 86400
avg_merge_days = round(sum(ttm(p) for p in merged) / len(merged), 1) if merged else 0.0
Top contributor
from collections import Counter
top_contributor = Counter(p["user"]["login"] for p in prs).most_common(1)[0][0]
Gotchas
merged_atis only present on the/pullsendpoint response, NOT on the/issuesendpoint. Always use/pulls?state=allfor PR data.- GitHub sorts by
createddesc by default; bail out oncecreated_at < startto avoid reading thousands of old PRs. - Bots (e.g.
dependabot[bot],github-actions[bot]) appear as contributors; decide whether to include/exclude them based on context.
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.