pr-review
Reviews a pull request from outside the core team on an open-source Umbraco package: runs the `reviewer` agent, then checks what's unsafe to build locally, security, contribution rules, docs, and whet
SKILL.mdplugins/umbraco-devkit/skills/pr-review/SKILL.md
GitHubReview a contribution
For a pull request filed against an Umbraco package's public repo by someone outside the core
maintainer team. Most packages in this space are open source, so this is a steady trickle, not
an edge case. The diff didn't come from your own builder/plan-folder pipeline, so three
things are different from a normal in-house review: you don't know the author's intent beyond
what the PR says, you haven't vetted the code that's about to run on your machine, and the
trust bar for "does this quietly break something" needs to sit higher by default.
This skill doesn't replace reviewer — it wraps it. reviewer already carries the
Umbraco-aware checklist that matters most here: public API impact, a renamed manifest alias,
multi-version/provider parity, layering, and the security skills. This skill adds the handful
of checks that only exist because the diff came from outside.
Scope
- IN: a PR on a package's public repo, opened by someone who isn't a core maintainer. Fetching it, reviewing it, drafting a review comment.
- OUT: a
feature-buildtask's own diff (dispatchreviewerdirectly — that's whatfeature-build/quick-fixalready do); merging, approving, or requesting changes without you confirming the drafted comment first; fixing the contribution yourself (if it's close but needs a small push, say so in the comment and let the contributor or a maintainer decide who pushes it).
Argument
$ARGUMENTS is a PR number or URL. If empty, ask which PR.
Workflow
Fetch the PR, don't run anything yet.
gh pr view <number> --json title,body,author,baseRefName,headRefName,additions,deletions,filesandgh pr diff <number>. Read the diff before touching your working tree.Scan for anything that would execute on your machine before you build or test. A malicious or careless PR can put code where CI, a build, or a package restore will run it automatically. Flag any of these as
Criticaland read them by hand before continuing: a changed.github/workflows/*, a build script (.ps1,.sh,csproj/build.caketargets),NuGet.config(a changed package source can redirect where packages come from), a new or changednpm/package.jsonscriptsentry (postinstallruns unattended), or any new binary/executable file. None of these block the review outright, but don't rundotnet build/npm installagainst the PR branch until you've read what they'd execute.Check out the branch.
git statusfirst (per this project's own safety rules — don't discard uncommitted work). Thengh pr checkout <number>.Treat the PR's own description as its task. There's no
PLAN.mdtask text for an outside contribution — the PR title/body (and the issue it links, if any) is the closest equivalent. Read it before judging the diff:reviewerneeds a task to judge scope against in its own step 8, and "what the PR says it does" is that task here.Dispatch
reviewer(Agent tool,subagent_type: reviewer), passing the PR's stated intent as the task. With the PR branch already checked out, its own step 1 (git diffagainst the base branch) finds the same diff you just scanned. Let it run its full workflow — build, test, docs/sibling comparison, consumer-impact, entry-point trace, ghost code, multi-version/provider parity, verdict.Add the checks
reviewerdoesn't know to make for outside code:- The security skill runs unconditionally.
revieweronly reaches forumbraco-securitywhen the diff visibly touches auth, user input, the Management API, or secrets. For a PR from outside the team, loadumbraco-securityyourself regardless of what the diff looks like it touches, and whether or notreviewerran. A security pass from memory doesn't replace it: the skill holds the Umbraco-specific checks you won't think of unprompted. An external diff is a new trust boundary, and "doesn't look security-relevant" is exactly the blind spot a deliberately disguised change would aim for. - Contribution hygiene. If the repo has a
CONTRIBUTING.md, check the PR follows it: target branch, commit/PR conventions, sign-off trailer (DCO/CLA) if the repo requires one, tests included for new behavior. - Docs flag, no assumed location. If the diff adds or changes a public feature, flag that it probably needs a docs update — but don't assume where. Only Umbraco HQ-owned packages keep docs in the UmbracoDocs repo; everyone else keeps docs in their own repo, a separate site, or nowhere formal. Say "this looks like it needs a docs update, check wherever this project keeps its docs" and leave it there.
- Intent match. Compare the diff against the PR's own stated purpose (and linked issue,
if any). Flag anything beyond it — an unrelated reformat, a drive-by refactor of a file
the stated fix never needed to touch — as a
Suggestionif small and harmless,Importantif it changes behavior outside the stated scope. This isn'treviewer's own scope check (step 8 in its workflow), which judges against a plan-folder task; here there is no plan, so the PR's own description is the only scope boundary there is.
- The security skill runs unconditionally.
Check every finding before it reaches the contributor. A wrong finding on an outside PR costs the contributor a round trip and makes the next finding easier to ignore. Do this on every PR, however small, and don't check the findings yourself instead: you collected them, so you're the wrong one to doubt them. Dispatch one fresh general-purpose subagent (Agent tool) on the checked-out branch with every finding from steps 5 and 6. Tell it to try to disprove each one by reading the code around the cited file:line and beyond the diff: a guard in a base class, attribute or caller, a handler elsewhere that already covers it, an API that doesn't behave the way the finding assumes. It returns each finding as confirmed, refuted, or unsure, with the evidence. Drop refuted ones, and turn unsure ones into a question for the contributor instead of a demand. List what was dropped, and why, for the user under the draft, not in it.
Draft the review, don't post it yet. Combine
reviewer's verdict and the findings that survived step 7 into one comment. Before the first finding, give one line with the verdict and the count per tier, such asChanges needed: 1 Important, 2 Suggestions; with nothing to fix, say so in those words. Then the findings, grouped the same wayreviewertiers them (Critical / Important / Suggestion / Pre-existing). Pre-existing ones are for the maintainer, so say plainly the contributor doesn't need to fix them. Write it followingplain-writing— a contributor who doesn't know this codebase needs to be able to act on it. Say what's blocking and what's a nice-to-have; don't bury aCriticalfinding in a wall of Suggestions.Show the draft and ask before posting. A PR comment on a public repo is visible to the contributor and anyone else watching the repo — confirm with the user first, every time. Once confirmed, post with
gh pr review <number> --comment --body-file <path>for a plain comment, or--request-changes/--approveinstead of--commentonly if the user explicitly wants the review state set, not just a comment left. Never pass--approvewithout the user having said so. Same sanity rules asgit-workflow: never--no-verify, never force-push, re-check the diff for secrets before anything is staged locally.
Hand off
One line: the PR, the verdict (reviewer's tier plus anything step 6 added), and whether the
comment was posted or is still waiting on confirmation.