pr-shepherd — Claude Code skill: what it does, how to install
Diagnoses red CI checks on open PRs, repairs mechanical issues, and drives branches to merge.
npx skills add dshakes/compass --skill pr-shepherd -a claude-codeWhat pr-shepherd does
The skill polls open pull requests with gh pr list, inspects failing step logs via gh run view, and categorises failures into environmental issues, mechanical slips, or genuine logic bugs. For routine failures like lint formatting, stale lockfiles, or generator drift, it applies fixes inside an isolated git worktree. Every fix is verified locally before pushing.
Forked pull requests remain strictly read-only: the agent inspects and comments, avoiding checkouts or push attempts. An enforced three-strike limit halts runaway retry loops after three failed fix attempts, assigning the ticket to human inbox status. Intermediate outcomes append to state/shepherd.md so recurring passes pick up where the previous run stopped.
Merges occur only when explicit merge authority is granted within the active session. Absent that permission, the tool outputs a check summary marked ready-to-merge and leaves the final click to you.
What it helps with
- classify failing GitHub status checks automatically
- patch formatting and lint drifts on PR branches
- separate runner environment flakes from actual regressions
- shepherd batches of pull requests toward merge gates
Example prompts for the agent
- /pr-shepherd
- /loop 15m /pr-shepherd
- Validate the open pull requests, fix mechanical failures and merge if green
How to install pr-shepherd
1Skills CLI (Vercel)
npx skills add dshakes/compass --skill pr-shepherd -a claude-code2Manually: put the files in place
~/.claude/skills/pr-shepherd/SKILL.mdCopy the whole skill folder; for one project use .claude/skills/pr-shepherd/
1Skills CLI (Vercel)
npx skills add dshakes/compass --skill pr-shepherd -a codex2Manually: put the files in place
.agents/skills/pr-shepherd/SKILL.mdFor all projects use ~/.agents/skills/
1Skills CLI (Vercel)
npx skills add dshakes/compass --skill pr-shepherd -a cursor2Manually: put the files in place
.cursor/skills/pr-shepherd/SKILL.mdCursor also reads .agents/skills/ and .claude/skills/
1GitHub CLI
gh skill install dshakes/compass pr-shepherd2Manually: put the files in place
.github/skills/pr-shepherd/SKILL.md1Skills CLI (Vercel)
npx skills add dshakes/compass --skill pr-shepherd -a gemini-cli2Platform CLI
gemini skills install https://github.com/dshakes/compass --path claude/skills/pr-shepherdManually: put the files in place
.devin/skills/pr-shepherd/SKILL.mdThe legacy .windsurf/skills/ path still works
Skills CLI (Vercel)
npx skills add dshakes/compass --skill pr-shepherd -a opencodeClaude.ai
Zip the folder and upload it in Settings → Capabilities → Skills
Step by step, with commands for each platform: How to install skills in Claude Code: five ways
Questions about pr-shepherd
How to install pr-shepherd in Claude Code?
Run npx skills add dshakes/compass --skill pr-shepherd -a claude-code in your terminal.
How are broken logic tests handled?
True defects are never silently patched. The skill posts its diagnosis as a PR comment and marks the entry as inbox for human review.
Can pr-shepherd merge code without approval?
No. Merge execution demands explicit per-session clearance like --merge. Otherwise, it stops at the gate and reports the branch as ready.
Source text
SKILL.md · MIT
---
name: pr-shepherd
description: Take every open PR end-to-end — diagnose failing checks, classify them (real defect vs mechanical vs environmental), fix the mechanical ones on the PR branch, re-verify, and stop at the merge gate. Use on demand ("handle the open PRs") or on an interval via /loop (e.g. "/loop 15m /pr-shepherd"). Merges only when the human has granted merge authority in the current session; otherwise reports ready-to-merge.
allowed-tools: Read, Grep, Glob, Bash, Edit, Write
---
# PR shepherd — the loop's handoff + verification moves, applied to PRs
A loop has five moves: **discovery → handoff → verification → persistence → scheduling**
(see [docs/20-loops.md](../../docs/20-loops.md)). `morning-triage` is discovery — it finds
work. This skill is what happens *after* a PR exists: no PR sits red waiting for a human to
diagnose a check that a machine can read. It shepherds each open PR to exactly one of three
outcomes: **merged** (gate satisfied + authority granted), **ready-to-merge** (reported), or
**inbox** (needs a human, with the diagnosis already written).
## Enumerate
`gh pr list --state open --json number,title,author,isDraft,isCrossRepository,headRefName,statusCheckRollup`
Skip drafts. **Fail closed on forks**: if `isCrossRepository` is true — or the field is
missing from the response — the PR is read-only: diagnose and comment, never check out into a
pushable worktree, never push.
## Diagnose — read the check, don't guess
For each red check, read the actual failing step (`gh run view <run-id> --log-failed`) and
classify it. The class decides the action — this is the judgment step, don't skip it:
| class | signature | action |
|---|---|---|
| **environmental** | missing secrets (Dependabot actor), runner flake, quota | note it; if it recurs, fix the *workflow* (root cause), not the PR |
| **mechanical** | drift/sync gates, lint, format, lockfile, generated files | fix it on the PR branch |
| **real defect** | failing tests on changed logic, security finding | never auto-fix silently — comment the diagnosis on the PR, mark `inbox` |
A failure that pattern-matches "flake" still gets its log read once. Silence is not success:
a check that never ran (skipped, stuck queue) is a finding, not a pass.
## Fix — mechanical only, verified before pushed
Work in a scratch worktree (`git worktree add … origin/<branch>`), never in the main checkout:
1. Make the smallest fix the failing gate names (e.g. the gate says
`run: cp sdlc/workflows/X .github/workflows/` — run that).
2. **Run the same gate locally and watch it pass** before pushing. Never push a guess.
3. Push to the PR branch with a commit message that names the gate it satisfies.
4. **Three strikes**: after 3 failed fix attempts on one PR, stop — mark it `inbox` with what
was tried. A non-converging loop must stop spending
([the resource-ceiling principle](../../docs/20-loops.md)).
## Gate — where the loop stops
Merge requires **all** of:
- every non-environmental check green (environmental reds are named in the report, not ignored);
- the human granted merge authority *in the current session* ("validate and merge",
"/pr-shepherd --merge"). Authority is per-session, never assumed from a past one;
- squash merge, never force-push, never merge red, never bypass a required check.
Without authority: report the PR as **ready-to-merge** with a one-line verdict per check.
The merge button is the human's; the shepherd's job is to make pressing it trivial.
## Persist
Append one row per touched PR to `state/shepherd.md` (create if absent) so the next run
resumes instead of re-diagnosing. **The agent forgets; the repo does not.**
```markdown
| pr | class | action | status |
|---|---|---|---|
| #71 | mechanical (mirror drift) | synced templates, pushed | merged |
| #74 | real defect (auth test) | diagnosis commented | inbox |
```
## Schedule
- On demand: `/pr-shepherd`.
- Interval (session open): `/loop 15m /pr-shepherd` — each firing re-reads state, handles
what changed.
- Unattended cadence (no session open): `compass schedule add pr-shepherd --twice-daily`
— a bounded headless run (turn + budget + timeout capped, spend ledgered) at 09:07 and
17:07 while the laptop is awake, with merge authority and the same rails
(`sdlc/routines/prompts/pr-shepherd.md`). Crontab skips missed slots; it doesn't catch up.
- Every firing re-reads `state/shepherd.md` first; a PR already `inbox` stays with the human
until they act — don't re-litigate it every run.
© dshakes · MIT · dshakes/compass