Install in Claude Code
Copygit clone --depth 1 https://github.com/FerroxLabs/wayland /tmp/pr-automation && cp -r /tmp/pr-automation/.claude/skills/pr-automation ~/.claude/skills/pr-automationThen start a new Claude Code session; the skill loads automatically.
Definition
SKILL.md
# PR Automation
Orchestrate the full PR automation lifecycle using a label-based state machine.
Each invocation performs at most one "heavy" action (review or fix), then exits.
Pure skips continue within the same session to find the next eligible PR.
**Announce at start:** "I'm using pr-automation skill to process PRs."
## Usage
```
/pr-automation
```
No arguments required. The daemon script `scripts/pr-automation.sh` manages the automation loop.
## Configuration
```
TRUSTED_CONTRIBUTORS_TEAM: detected from REPO org (e.g. FerroxLabs/trusted-contributors)
CRITICAL_PATH_PATTERN: env var, default in scripts/pr-automation.conf
LARGE_PR_FILE_THRESHOLD: env var (default: 50), also in scripts/pr-automation.conf
PR_DAYS_LOOKBACK: env var (default: 7), also in scripts/pr-automation.conf
```
**REPO** is detected automatically at runtime - do not hardcode it:
```bash
REPO=$(gh repo view --json nameWithOwner --jq '.nameWithOwner')
ORG=$(echo "$REPO" | cut -d'/' -f1)
```
## Label State Machine
| Label | Meaning | Terminal? |
| ------------------------ | ----------------------------------------------------------------------- | --------- |
| `bot:reviewing` | Review in progress (mutex) | No |
| `bot:ready-to-fix` | CONDITIONAL review done, waiting for bot to fix next session | No |
| `bot:fixing` | Fix in progress (mutex) | No |
| `bot:ci-waiting` | CI failed and author notified - snoozed until author pushes new commits | No |
| `bot:needs-rebase` | Merge conflict that bot cannot auto-resolve - author must rebase | No |
| `bot:needs-human-review` | Blocking issues - human must intervene | Yes |
| `bot:ready-to-merge` | Bot done, code is clean - human just needs to confirm and merge | Yes |
## Exit Rules
- **Any substantive action** (approve workflow, post comment, run review, run fix) → EXIT after completing
- **Pure skip** (WIP, draft, terminal label, CI running, mergeability unknown, `bot:ci-waiting`) → continue to find next PR in same session
---
## Steps
### Step 1 - Fetch Candidate PRs
Read the lookback window from the environment (default 7 days):
```bash
DAYS=${PR_DAYS_LOOKBACK:-7}
gh pr list \
--state open \
--search "created:>=$(date -v-${DAYS}d '+%Y-%m-%d' 2>/dev/null || date -d "${DAYS} days ago" '+%Y-%m-%d') -is:draft" \
--json number,title,labels,createdAt,author \
--limit 50
```
Save the result as `candidate_prs`.
If `candidate_prs` is empty: log `[pr-automation] No open PRs found. Exiting.` then log `[pr-automation:exit] action=no_prs reason="no open PRs"` and EXIT.
### Step 2 - Get Trusted Contributors
```bash
gh api orgs/${ORG}/teams/trusted-contributors/members --jq '[.[].login]'
```
Save as `trusted_logins`. If API call fails, treat as empty array.
### Step 3 - Select Target PR
Sort `candidate_prs` using this **three-key** order:
1. **Primary**: has label `bot:ready-to-fix` → these PRs first
2. **Secondary**: author.login in `trusted_logins` → trusted PRs next
3. **Tertiary**: createdAt ascending (oldest first / FIFO)
Iterate through sorted list to find the **first eligible PR**.
**Skip conditions** (skip this PR, try next - stay in session):
| Condition | Check |
| --------------------------------------- | --------------------------------------------------------------------------- |
| Title contains `WIP` (case-insensitive) | `title.toLowerCase().includes('wip')` |
| Has label `bot:needs-rebase` | check labels array |
| Has label `bot:needs-human-review` | check labels array |
| Has label `bot:ready-to-merge` | check labels array |
| Has label `bot:done` | check labels array |
| Has label `bot:reviewing` | check labels array |
| Has label `bot:fixing` | check labels array |
| Has label `bot:ci-waiting` | check labels array - wake-up check runs as fallback if no eligible PR found |
**When eligible PR found:**
For **fresh PRs** (no bot: label): add `bot:reviewing` to claim it:
```bash
gh pr edit <PR_NUMBER> --add-label "bot:reviewing"
```
For **`bot:ready-to-fix` PRs**: swap label atomically:
```bash
gh pr edit <PR_NUMBER> --remove-label "bot:ready-to-fix" --add-label "bot:fixing"
```
Save this PR as `target_pr` (number, title, author.login, is_ready_to_fix).
**If no eligible PR found after full iteration:** run the snoozed PR wake-up checks as a fallback before giving up.
**Fallback: Wake Up Snoozed PRs**
Check both `bot:ci-waiting` and `bot:needs-rebase` PRs for new commits.
**1. Wake up `bot:ci-waiting` PRs:**
Fetch all open PRs with `bot:ci-waiting` and check if the author has pushed new commits since the last CI failure comment:
```bash
WAITING_PRS=$(gh pr list --state open --label "bot:ci-waiting" \
--json number,createdAt,author --limit 50)
```
For each PR in `WAITING_PRS` (sorted by createdAt ascending, oldest first):
```bash
PR_NUMBER=<number>
LAST_CI_COMMENT_TIME=$(gh pr view $PR_NUMBER --json comments \
--jq '[.comments[] | select(.body | test("<!-- pr-review-bot -->") and test("CI checks failed"))] | last | .createdAt // ""')
LATEST_COMMIT_TIME=$(gh pr view $PR_NUMBER --json commits \
--jq '.commits | last | .committedDate')
```
If `LAMore from this repository
architectureSkill
|
bump-versionSkill
Use when bumping the Wayland version: update package.json, run checks, branch, commit, push, create PR, wait for merge, tag release.
fix-issuesSkill
|
fix-sentrySkill
|
i18nSkill
|
oss-prSkill
Use when creating a pull request, after committing changes, or when user invokes /oss-pr. Covers branch management, quality checks, commit, push, and PR creation.
pr-fixSkill
|
pr-reviewSkill
|