Pr review
PR review as agent skills. My code-review standards, installable in any skills.sh agent.
npx -y skills add satejbidvai/skills --skill pr-reviewAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Review a PR using Satej's personal review standards
SKILL.md
15.0 KB, ~3.6k tokens by cl100k_base, as published. Nobody here has run it
Review a pull request against my review standards using specialized sub-agents that run in parallel, then merge and deduplicate findings.
Input: The argument after /pr-review is the GitHub PR URL. Optionally, a second sentence can provide focus context (e.g., "focus on the new dialog component").
Voice — include in every sub-agent prompt:
Write like a friendly senior engineer reviewing a teammate's PR. Be direct, concise, and conversational. Say "this" not "this code block." Vary your phrasing — no two comments should sound templated. When you're unsure, express it naturally ("I think," "looks like," "not sure if this was intentional") — never use structured confidence markers. Explain "why" only when the reason isn't obvious or common knowledge — don't bloat comments with explanations everyone already knows. No praise, no emojis. One or two sentences per comment, max.
Steps
-
Parse the PR URL to extract
owner,repo, andpr_number. -
Fetch PR context — run these in parallel:
# PR metadata (title, description, labels, branch, HEAD SHA) gh pr view {pr_number} --repo {owner}/{repo} --json title,body,labels,headRefName,headRefOid # Changed files with diffs gh api repos/{owner}/{repo}/pulls/{pr_number}/files --paginate --jq '.[] | {filename, status, patch}' > /tmp/pr-review-diff.jsonThen annotate every diff line with its real new-file line number, so sub-agents copy line numbers instead of counting from
@@headers:python3 - <<'PY' import json, re files = [json.loads(l) for l in open('/tmp/pr-review-diff.json') if l.strip()] out = [] for f in files: out.append(f"### FILE: {f['filename']} ({f['status']})") newln = None for l in (f.get('patch') or '').split('\n'): m = re.match(r'^@@ -\d+(?:,\d+)? \+(\d+)', l) if m: newln = int(m.group(1)); out.append(l); continue if newln is None: out.append(l); continue if l.startswith('-'): # removed line — no new-file number out.append(f" {l}") else: # added/context line — prefix real new-file line number out.append(f"{newln:>6} {l}"); newln += 1 out.append('') open('/tmp/pr-review-annotated.txt', 'w').write('\n'.join(out)) PYPass the annotated diffs (from
/tmp/pr-review-annotated.txt) to sub-agents. -
Filter to web-relevant files only — skip files outside
web/unless the PR is explicitly about root config. Focus on.ts,.tsx,.css,.mjs,.jsonchanges. Skip generated files (*.gen.*). -
Build an intent brief — a short summary (3-5 sentences) of:
- What this PR is doing (from title, body, labels)
- Which areas of the codebase it touches
- Any focus context the user provided
This brief is passed to every sub-agent so they understand the PR's purpose.
-
Classify changed files into two groups:
- Test files:
*.test.*,*.spec.* - Source files: everything else
- Test files:
-
Spawn review sub-agents in parallel using the Task tool. Each sub-agent receives the Voice instructions, the intent brief, its assigned annotated file diffs, the shared severity/format definitions below, and only the review rules for its domain.
- Code Quality Agent — gets source file diffs + Code Quality Rules
- Intent & UX Agent — gets source file diffs + Intent & UX Rules
- Testing Agent — gets test file diffs + Testing Rules. Skip entirely if no test files in the PR.
- Architecture Agent (
readonly: true) — gets all file diffs + codebase access. No rules from this file — its job is to search the codebase for existing solutions, patterns, or utilities that overlap with or duplicate what the PR introduces. Flag only when the approach itself is wrong or when existing codebase utilities/patterns should be used instead.
Tool restrictions for sub-agents:
- Code Quality, Intent & UX, and Testing agents must include this instruction: "All diffs you need are provided below. Do NOT use Read, Grep, or Glob tools — work exclusively from the diffs in this prompt."
- Architecture Agent must include this instruction: "The PR diffs are provided below for reference. You MUST search the broader codebase to find existing patterns, utilities, or solutions that overlap with what the PR introduces. Use Read, Grep, and Glob freely."
Each sub-agent prompt must include:
Severity tags (internal — used by sub-agents only, translated at merge time):
[blocking]— Must fix. Bugs, incorrect patterns, violations of core conventions.[suggestion]— Should consider. Better abstractions, cleaner patterns, architectural improvements.[nit]— Minor. Naming, formatting, small simplifications.[question]— Needs clarification. Intent unclear, seems unrelated, or potentially unintentional.
Output format for each sub-agent — return findings grouped by file path, each as:
- [severity] Line N: descriptionNis the number printed to the left of the line you're flagging in the annotated diff — copy it verbatim, do not count or compute it. If the code isn't in any diff hunk (no number on the left), use[not-in-diff]instead of a line number. -
Merge findings from all sub-agents:
- If two agents flagged the same code for the same underlying issue, merge into one finding with the higher severity and note both perspectives.
- Sort by severity: blocking first, then suggestions, nits, questions.
- Translate severity tags to final format: strip the
[blocking]and[suggestion]prefixes entirely (no prefix in output). Convert[nit]tonit:and[question]toQuestion:.
-
Output the review in the format specified at the bottom. Prepend a metadata header as the very first line of the review output (before any findings):
<!-- pr:{owner}/{repo}/{pr_number} sha:{headSha} -->This is invisible in chat and used by
/post-pr-reviewto extract PR metadata.
Code Quality Rules
Assigned to the Code Quality Agent. Covers TypeScript patterns, React Query, component design, and codebase conventions.
TypeScript Strictness
- No
asassertions. Flag every use ofas. Suggest Zod parsing, type guards, or fixing the upstream type instead. - No
any. Flag everyany. Suggest proper types, generics, orunknownwith narrowing. - No unnecessary
unknown. If the shape is known, type it properly. - Type constants and config objects so typos are caught at compile time, not runtime.
- Prefer exhaustive
switchover if/else chains so TypeScript catches unmatched cases when types expand. - No fallback on exhaustively-typed lookups. If a const map covers all possible keys, don't add
??fallback — it's dead code that hides type gaps.
React Query Is the Only Way to Call APIs
- Never call SDK/API directly in components or event handlers. Always use
useQuery/useMutationfrom React Query. - Use
selectto transform query data instead ofuseMemoon the raw response. - Use
variablesfromuseMutationto track submitted values instead of a separateuseState. - Use
combinewithuseQuerieswhen merging multiple queries. - Prefer query invalidation over optimistic updates unless there's a clear UX justification.
- Don't create custom query keys or hand-write a
queryFnwhen generatedqueryOptionsalready provide them.
Component Architecture
- Break large conditional blocks into sub-components for readability.
- Reduce state count. Flag components with many
useStatecalls. Ask:- Can related states be combined into one object?
- Can React Query handle loading/error/data states instead?
- Can state be derived from existing data instead of synced?
- No boolean props to switch behavior. Prefer enums or
mode: 'view' | 'edit'so the pattern scales when a third option appears. - Keep domain logic out of shared/common components. Flag domain-specific branches in a component meant to be generic — push them to the caller.
- Make required props required. Don't make a prop optional and pass a no-op — make it optional or split the component.
- Don't pass hooks as props. Flag and question this pattern.
- Hooks should never be called conditionally. This violates the Rules of Hooks.
Avoid useEffect When React Patterns Suffice
- Adjust state during render instead of syncing with
useEffect— see React docs: "You Might Not Need an Effect". - Use
keyto reset component state instead ofuseEffectwatching a prop. - Derive values during render instead of storing them in state and syncing with effects.
Use Existing Abstractions
- Before writing any utility function, check the project's existing dependencies. These libraries cover most common needs:
es-toolkit,react-use,use-debounce,date-fns/date-fns-tz,fast-equals. - Prefer a schema-driven form abstraction (react-hook-form + Zod style) over manual form state built from
useState/useRef+ hand-rolled validation. - Single source of truth for derived values. If the same non-trivial derivation or fallback is repeated across call sites, extract it into one helper/selector — or compute it once at the parent/data boundary and pass it down — so a site can't be missed.
Key internal abstractions:
- Domain form fields (
InputField,RichTextEditorField,CheckboxField, etc. from@/components/form-field/) — not raw Radix inputs insideFormField. - Flag any case where existing codebase helpers or dependencies are being reinvented.
Naming Conventions
useprefix is reserved for hooks. Never name a regular functionuseSomething.- Schemas start with capital letters (e.g.,
const UserSchema = z.object({...})). - Constants use
SCREAMING_SNAKE_CASE. - UI-only keys use
camelCase, even if BE sendssnake_case. - Destructure and rename loading states from different queries so it's clear which query they belong to (e.g.,
isPending: isAccountLoadingandisPending: isContactLoading). - Name functions/types for their domain, not their implementation. Avoid generic names like
isIAMPendingwhenisAdminPermissionsLoadingis clearer. - Flag confusingly similar names in the same scope — sibling functions or variables should be immediately distinguishable without reading their implementations.
Static Values Outside Render
- Move constant arrays, objects, regex, and templates outside components/functions if they don't depend on props/state. They get recreated on every render otherwise.
- Flag
useMemowrapping static data that should just be a module-level constant.
React Query State Semantics
isLoadingvsisPendingvsisFetching— flag redundant checks.isFetchingis true during all fetches;isPending || isFetchingis redundant unlessenabled: falseis used.- Use
isLoading(which isisPending && isFetching) for initial load states instead of combining flags manually.
Don't Mutate Props
- If a function receives an array or object parameter, copy it before modifying. Never mutate arguments directly.
Prefer Modern APIs
toSorted()oversort()(avoids mutation).replaceAll()over chainedreplace().Array.from()over push loops when building arrays.array.at(-1)overarray[array.length - 1].- Destructuring over repeated property access.
- Default parameters over
??chains in function bodies — push defaults to the signature or type definition.
Intent & UX Rules
Assigned to the Intent & UX Agent. Covers questioning intent, code hygiene, UX patterns, and URL state.
Questioning Intent
- Unrelated changes — flag files/hunks that seem unrelated to the PR's purpose as
[question]. - Removed code — if code, comments, or components are deleted, ask if it was intentional.
- Changed logic flow — if a component's rendering conditions or data flow changed and it seems unrelated to the PR's purpose, ask if it was intentional. Do NOT question visual/styling changes.
- Templated content — when a file is clearly derived from another adapter/domain, flag user-facing strings, variable names, or domain references that weren't updated to match the new context.
Code Hygiene
- Remove
console.logand debug statements. - Remove commented-out code. Use version control, not comments, to preserve old code.
- Flag unnecessary re-exports. If a module's only purpose is
export { X } from './other'and callers could import directly, question whether the indirection layer is justified. - Don't keep "will use later" code. Dead code should be deleted.
- Fix typos in user-facing strings and variable names.
- Add comments for non-obvious code — regex patterns, workarounds, and intentional
refetchOnWindowFocus: falseoverrides should have a comment explaining why.
UX Awareness
- Inline errors for forms, not toasts. Toast is for async operations, not form validation.
!importantin Tailwind — always flag and ask why it's needed. It almost never is.- Arbitrary Tailwind values like
[13px]— prefer extending the Tailwind config with design tokens.
NUQS (URL State)
- Use
nuqsfor all URL state. Don't useuseSearchParamsor manual query string parsing. - Use the correct parser — e.g.,
parseAsBooleanfor booleans instead of comparing strings likeedit === "true". - Define query state schemas adjacent to the route file.
setQueryStatessupports partial updates — no need to spread...prev.
Testing Rules
Assigned to the Testing Agent. Only used when the PR contains test files (*.test.*, *.spec.*).
- Never mock components. Tests should render real components.
- Never mock helper functions. Let the real implementation run.
- Avoid
getByTestId,querySelector, anddata-testid. Prefer accessible queries:getByRole,getByText,getByLabelText,getByPlaceholderText. - No manual timeouts (
setTimeout, hardcoded delays) in tests. Useexpect.poll,waitFor, or Vitest's async utilities. - Prefer
userEvent.typeoverfireEvent.changefor typing interactions. - No mocking
useRouter,useParamsunless verified as the recommended approach.
Output Format
Group findings by file path. Within each file, list findings in order of severity (blocking first, then suggestions, nits, questions). Use this format:
## `web/components/example/example-component.tsx`
- Line 42: Using `as Status` here — a type guard would be safer.
- Line 18: This would read cleaner with `select` in useQuery instead of the extra `useMemo`.
- nit: Line 7: Schema name should be `FormSchema`.
- Question: Line 55: The progress bar got removed — intentional?
If a file has no findings, skip it entirely.
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.
Gives 0 of the 12 instructions most pr commit review skills give in ~3.6k tokens
Counted across 888 of the 1,342 authors here whose files we hold, read 2026-08-07
- Use conventional commits formatin 127 of 888, across 115 files
- Keep subject line under 72 charactersin 62 of 888, across 48 files
- Delete branches after mergein 51 of 888, across 38 files
- Use imperative mood in subject linein 51 of 888, across 42 files
- Use imperative mood in commit messagesin 44 of 888
- Verify directory is ignored before creating worktreein 43 of 888, across 12 files
- Generate a conventional commit messagein 43 of 888
- Add unignored worktree directories to gitignorein 42 of 888, across 10 files
- Make atomic commitsin 39 of 888, across 27 files
- Run tests before committingin 36 of 888, across 25 files
- Verify clean test baselinein 35 of 888, across 9 files
- Split unrelated changes into separate commitsin 35 of 888, across 30 files
Said here and by no other author read
- annotate diff lines with real line numbers
- skip files outside web directory
- build a short intent brief
- classify changed files as test or source
- deduplicate sub-agent findings by issue
- translate severity tags to final format
Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.