Plan phase for oss-pr-lessons playbook — load state, determine next batch of PRs to analyze for any repository
Scanned 9/2/2026
Install to Claude Code
npx -y skills add kookr-ai/kookr --skill oss-pr-plan --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Oss Pr Plan?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/kookr-ai-oss-pr-plan)More formats (shields.io, HTML) on the badges page.
---
name: oss-pr-plan
description: Plan phase for oss-pr-lessons playbook — load state, determine next batch of PRs to analyze for any repository
keywords: oss, pr, plan, batch, pagination, state, open source, contribution, analyze
related: [oss-pr-critic, oss-pr-state, oss-pr-threshold, oss-pr-distill]
---
# OSS PR Plan
Load state and determine the next batch of PRs to analyze. Generalized version of `codex-pr-plan` that works for any repository.
## When to Use
Invoked at the start of each `oss-pr-lessons` iteration.
## Non-Negotiable Rules
| # | Rule | Violation Example | Correct Pattern |
|---|------|-------------------|-----------------|
| 1 | Always read state.json before fetching PRs | Fetching PRs without checking processed list | `cat ~/.claude/{repoSlug}-pr-lessons/state.json` first |
| 2 | Batch size is exactly 5 | Processing 10 or 20 PRs at once | Fetch 5 closed PRs per iteration |
| 3 | Use cursor for pagination | Re-fetching from page 1 every time | Use `state.json.cursor` |
| 4 | Skip already-processed PRs | Analyzing PR #123 that's in processed_prs | Filter out all IDs in processed_prs and skipped_prs |
| 5 | Include both merged AND closed-unmerged PRs | Only looking at merged PRs | Closed-unmerged PRs teach what NOT to do |
| 6 | Validate the batch manifest against state before critic work starts | Selecting #123, then noticing later it was already processed | Print the final 5 IDs and confirm none exist in processed_prs or skipped_prs |
## Parameters
- **repoFullName**: `owner/repo` (e.g., `microsoft/vscode`)
- **repoSlug**: URL-safe slug (e.g., `microsoft-vscode`)
## Pre-Plan: Registry Eligibility Check
Before planning PR analysis, check if the repo is eligible. (`~/.claude/hooks/oss-registry-check` is not yet implemented; the 126/127 branch below already degrades gracefully when it is absent.)
```bash
REPO="{{repoFullName}}"
RESULT=$(~/.claude/hooks/oss-registry-check "$REPO" 2>&1)
RC=$?
echo "$RESULT"
case $RC in
0) ;; # Eligible — proceed
1) # Ineligible (anti-ai or blocked)
echo "Cannot analyze PRs: repo is not eligible for AI contributions."
exit 0
;;
2) # Unknown — not in registry
echo "Repo not in registry. Run oss-repo-recon first to assess eligibility."
exit 0
;;
126|127) # Resolver missing
echo "WARNING: oss-registry-check not found. Proceeding without eligibility check."
;;
esac
```
## Workflow
### Step 1: Initialize state if needed
```bash
SLUG="{{repoSlug}}"
REPO="{{repoFullName}}"
mkdir -p ~/.claude/${SLUG}-pr-lessons
if [ ! -f ~/.claude/${SLUG}-pr-lessons/state.json ]; then
cat > ~/.claude/${SLUG}-pr-lessons/state.json << EOF
{
"repo": "${REPO}",
"version": 1,
"processed_prs": [],
"skipped_prs": [],
"total_processed": 0,
"total_skipped": 0,
"distillation_count": 0,
"last_batch_at": null,
"last_distillation_at": null,
"cursor": 1,
"notes": "State file for ${REPO} PR lessons."
}
EOF
fi
if [ ! -f ~/.claude/${SLUG}-pr-lessons/learnings-raw.md ]; then
cat > ~/.claude/${SLUG}-pr-lessons/learnings-raw.md << EOF
# Raw PR Learnings
Accumulated observations from analyzing closed PRs in ${REPO}.
Each batch appends a section below. When this file exceeds 200 lines, distillation is triggered.
---
EOF
fi
```
### Step 2: Load state
```bash
cat ~/.claude/${SLUG}-pr-lessons/state.json
```
### Step 3: Fetch next batch of closed PRs
```bash
CURSOR=$(jq '.cursor // 1' ~/.claude/${SLUG}-pr-lessons/state.json)
gh api "repos/${REPO}/pulls?state=closed&sort=updated&direction=desc&per_page=20&page=${CURSOR}" \
--jq '.[] | {number, title, merged_at, closed_at, user: .user.login, additions, deletions, changed_files, body: (.body[:200])}'
```
### Step 4: Filter and select batch
From the fetched PRs:
1. Remove any PR whose number is in `processed_prs` or `skipped_prs`
2. Skip bot PRs (dependabot, renovate, github-actions, and repo-specific bots) — add to `skipped_prs`
3. Skip PRs with zero discussion and zero code changes — add to `skipped_prs`
4. Skip release PRs (title matches `release`, `bump version`, `chore(release)`) — add to `skipped_prs`
5. Select the first 5 remaining PRs as the batch
6. Prefer a mix of merged and closed-without-merge PRs
### Step 5: Output batch manifest
Return a list of PR numbers and titles for the critic phase to process.
### Step 6: Preflight batch validation
Before the critic phase starts, validate the exact selected IDs against state again:
```bash
SLUG="{{repoSlug}}"
SELECTED='[123,124,125,126,127]'
jq --argjson selected "${SELECTED}" '
{
processed_hits: [ $selected[] as $id | select(.processed_prs | index($id)) | $id ],
skipped_hits: [ $selected[] as $id | select(.skipped_prs | index($id)) | $id ]
}
' ~/.claude/${SLUG}-pr-lessons/state.json
```
Correct pattern:
1. Print the final batch manifest
2. Confirm `processed_hits` and `skipped_hits` are both empty
3. Only then hand the batch to `oss-pr-critic`
If any selected PR appears in `processed_prs` or `skipped_prs`, stop and re-filter before analysis.
## Skip Criteria
Add to `skipped_prs` (never revisit):
- Bot-authored PRs (dependabot, github-actions, renovate, and repo-specific bots)
- PRs opened and closed within 1 minute (accidental)
- Draft PRs never marked ready
- PRs with 0 files changed
- Release/version-bump PRs
- Dependency-only PRs (`chore(deps):`)
## Cursor Strategy
- `cursor` in state.json is the GitHub API page number (starts at 1)
- After processing a page, increment cursor if all PRs on that page were already processed or skipped
- If the batch was filled from the current page, keep the cursor the same
- If cursor reaches a page with 0 results, reset to 1 (wrap around for newly closed PRs)
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!