Self-Review
A rigorous, two-pass review of all changes on the current branch. Pass 1
catches mechanical errors via automated checks and mechanical checklists.
Pass 2 applies the deep design judgment of a senior Staff Engineer to catch
the subtler issues that separate correct code from good code.
This workflow is designed to be invoked standalone on any branch, or as an
embedded step within a parent workflow (e.g., implement-spec).
Pass 1: Mechanical Verification
Purpose: eliminate the rote mistakes that waste human reviewer time. Every
check here is binary — pass or fail, no judgment required.
Step 1.1 — Run automated verification
Run the repo's build/test/lint verification for the changeset. Resolve what
to run in this order — use the first that applies:
Explicit command — the verify_cmd input or a $VERIFY_CMD environment
variable.
Repo-provided verification entry point — a canonical script or target the
repo already defines: e.g. ./scripts/verify.sh, ./bin/verify,
make verify, make check, or the verification commands documented in the
repo's AGENTS.md / CONTRIBUTING.md. Prefer a changed-files-aware runner
if the repo has one.
The bundled inference helper — scripts/verify.sh (shipped with this
skill) detects the repo's toolchain(s) and runs their standard
build/test/lint commands:
scripts/verify.sh # exit 0 = pass, 1 = failures, 2 = could not infer
Manual derivation — if the helper exits 2 (nothing inferable, or a
build system like Bazel that needs targeted invocation), derive the exact
commands from the repo's docs and build files for the packages you changed,
and run those. Never skip verification silently — if truly nothing can
be run, state that explicitly in the final summary.
If any check fails, diagnose and fix the issue before proceeding. Re-run
until all checks pass. Maximum 3 fix iterations — if still failing after 3
attempts, report the remaining failures and stop.
Step 1.2 — Apply mechanical checklists
Determine which files and languages are affected by the changes:
BASE="${base_branch:-$(git remote show origin | sed -n 's/.*HEAD branch: //p')}"
git diff --name-only "$(git merge-base "origin/${BASE}" HEAD)"...HEAD
Then apply, in order:
- The general checklist —
checklists/general.md (shipped with this
skill): language-agnostic mechanical items that apply to any changeset.
- Repo-specific checklists — from
checklists_dir if provided, else
auto-discover in the repo (in order): .agents/checklists/,
.dev/checklists/, docs/checklists/. Apply every checklist whose
language/stack matches the changed files.
- Derived checklists — for each affected language with no repo checklist,
derive a short mechanical checklist before reviewing: read the repo's
linter/formatter/compiler configs and agent docs, and extract the rules that
are (a) binary and (b) would fail the build or CI (fatal warnings, import
rules, naming rules, generated-file policies). Apply that list.
Walk the checklists one category at a time, with that category as your sole
focus for the sweep (all files for diff hygiene, then all files for safety,
and so on) — controlled experiments show that an explicit "look for X" focus
directive raises defect detection far more than checklist possession alone.
Fix any violations found. If fixes were made, re-run Step 1.1 to confirm
nothing broke.
Pass 2: Design Review
Purpose: catch the things that make code good versus merely correct. This is
where the frontier model's intelligence earns its keep. No checklist can
enumerate these concerns — they require taste, judgment, and deep experience
with what makes software maintainable over years.
Independence
The agent that wrote the code is a systematically biased reviewer of it: LLM
evaluators favor their own generations, and the effect is amplified when the
reviewing context contains the memory of writing — you remember the intent
and read the intent into the code. Therefore:
- Where the harness supports subagents, run Pass 2 in a fresh context
given only: the base-branch diff, the changed files (to read in full), the
standards below, and — if invoked by a parent workflow — the spec/ticket.
Not the implementation history or conversation.
- Where it doesn't, apply the fallback discipline: every judgment must be
argued from what is on disk, re-read in full — never from memory of writing
it. If you catch yourself thinking "this is fine, I know why I did it,"
re-read the code as evidence instead.
The Reviewer Standards
Review against the standards below, directing your attention to each concern
in turn. (The framing is a working stance, not magic: evidence shows role
assignment by itself doesn't improve judgment — what does measurably help is
explicitly focusing attention on each named concern, which is what the
categories below are for.)
You are a Staff Engineer with 15+ years of experience building and
maintaining production distributed systems. You have mass-reviewed
thousands of PRs across your career. You have seen how innocent-looking code
decisions compound into unmaintainable systems over months and years. You
have also seen the opposite — code that was a joy to come back to because
someone made the right structural choices up front.
You are not a pedant. You don't care about bikeshedding or stylistic
trivia — the mechanical checklist in Pass 1 already handled that. You care
about the things that determine whether this code will age well or poorly:
Abstraction Quality
- Is each function/class/module doing one thing well, with a clear contract?
- Are the boundaries between components clean and well-motivated?
- Could a competent engineer who has never seen this code understand the
intent by reading the types, names, and structure — without needing
inline comments as a crutch?
- Is the level of abstraction appropriate? Not so concrete that similar
logic is duplicated, but not so abstract that you need a PhD to trace
the control flow?
Naming as Design
- Do names reveal intent and domain meaning, not implementation details?
- Would someone reading a call site understand what's happening without
jumping to the definition?
- Are boolean parameters and return values self-documenting? (e.g.,
forceRefresh = true vs a bare true)
- Do collection variable names indicate what they contain, not just that
they're collections?
DRY Without Over-Abstraction
- Is there duplicated logic that should be a shared utility or method?
- But equally important: is anything abstracted prematurely? Is a
"reusable" component actually used in only one place, adding indirection
without benefit?
- Does factoring out shared code actually reduce total complexity, or does
it just move it somewhere harder to find?
Error Handling as a Design Choice
- Are errors handled at the right level of the call stack — not too deep
(swallowing context), not too shallow (leaking implementation details)?
- Is enough context preserved for debugging in production? If this fails at
3am, will the error message tell the on-call engineer what happened?
- Are failure modes explicit and visible, not hidden behind silent
defaults, empty fallbacks, or swallowed exceptions?
- Is the error handling strategy consistent with adjacent code in the
same module?
Extensibility and Change Resilience
- What is the next feature someone will likely want to add in this area?
Does this design make that easy, or will it require reworking the
current change?
- If the underlying data model changes (a new field, a new enum value, a
new source type), how many files need to be touched? Is the blast
radius proportional to the change?
- Are there implicit assumptions or magic constants that will silently
break when requirements evolve?
Codebase Coherence
- Does this code look like it belongs next to the adjacent code?
- Does it follow the idioms and patterns established by the rest of
the codebase — or does it introduce a new way of doing something that
already has an established pattern?
- If it introduces a new pattern, is there a compelling reason? Or is it
just the agent's default style leaking through?
Simplicity and Proportionality
- Is this the simplest solution that handles all the actual requirements?
- Could any part of the change be deleted without losing correctness or
meaningful capability?
- Is the complexity of the implementation proportional to the complexity
of the problem it solves? Over-engineering is a design defect, not a
virtue.
Test Quality (where tests exist or should exist)
- Do tests verify behavior and contracts, or do they just exercise
code paths for coverage?
- Are meaningful edge cases covered — empty inputs, error paths, boundary
conditions?
- Would a test failure give you enough information to diagnose the bug
without re-running with debug logging?
- Are test names descriptive enough to serve as documentation of expected
behavior?
The Gestalt
- Step back and look at the full set of changes as a whole. Does this
changeset tell a coherent story? Is the scope focused, or has it
drifted into unrelated cleanup?
- If you were the reviewer, would you feel confident approving this
after reading it once? Or would you need to ask clarifying questions?
- Is this the kind of code that builds trust with reviewers, or the kind
that erodes it?
Procedure for Pass 2
Get the diff against the base branch:
git diff "origin/${BASE}"...HEAD
Read every changed file in full — not just the diff. The diff shows
what changed, but correctness and design quality depend on the surrounding
code. A one-line filter change is only correct if downstream code handles
the new possible values.
Read adjacent files to understand context, existing patterns, and how
the changed code fits into the broader module. The goal is to see the
change the way a reviewer who knows the codebase would see it.
For each file, evaluate against the design criteria above — one
category at a time; a focused sweep per concern outperforms one diffuse
read. Be honest and critical. The point is not to validate your own work —
it's to find the things a rigorous human reviewer would find.
For genuine issues: fix them. Don't just note problems — resolve them.
A self-review that produces a list of "consider doing X" is not a review,
it's procrastination. Either it's worth fixing or it's not worth
mentioning.
After all fixes, re-run Pass 1 (Step 1.1) to ensure nothing broke.
Calibration
Only flag genuine issues. A Staff Engineer doesn't leave nitpick
comments on code that's already style-consistent and functionally correct.
If the code follows established patterns and handles its cases, let it
stand.
Every flag must be demonstrable. For each issue you raise, you must be
able to state at least one of: the input/sequence that makes it fail, the
contract or invariant it violates, or the concrete maintenance cost it
incurs. LLM critics are known to hallucinate plausible-sounding bugs; if
you cannot articulate the demonstration, the issue isn't real — drop it.
Pragmatism over perfection. The goal is production-quality code, not
platonic-ideal code. If a minor abstraction improvement would require
touching 10 additional files for marginal benefit, that's not worth doing
in this changeset.
"Maybe consider..." is not an action. If you find yourself hedging,
that's a signal it's not a real issue. Either commit to fixing it or move
on.
Respect existing patterns. If the rest of the codebase handles a
concern in a particular way, follow that way — even if you'd prefer a
different approach in a greenfield project. Consistency is more valuable
than local optimality.
Shared-abstraction extraction: factor repeated patterns into a shared
utility/component only where it genuinely reduces complexity and the
extraction would be used in 2+ places. Don't extract something used once —
that's just indirection.
Completion
After both passes are done and all fixes have been verified:
- Report a brief summary: how many mechanical issues were found and fixed,
how many design issues were found and fixed, and the final verification
status (including anything that could not be verified and why).
- If invoked as part of a parent workflow, return control to it.
- If invoked standalone, optionally commit and push the fixes.
1---2name: self-review3description: Two-pass self-review of the current branch: mechanical verification (build/test/lint + checklists) then a Staff Engineer design critique4license: MIT5---67# Self-Review89A rigorous, two-pass review of all changes on the current branch. Pass 110catches mechanical errors via automated checks and mechanical checklists.11Pass 2 applies the deep design judgment of a senior Staff Engineer to catch12the subtler issues that separate correct code from *good* code.1314This workflow is designed to be invoked standalone on any branch, or as an15embedded step within a parent workflow (e.g., `implement-spec`).1617---1819## Pass 1: Mechanical Verification2021Purpose: eliminate the rote mistakes that waste human reviewer time. Every22check here is binary — pass or fail, no judgment required.2324### Step 1.1 — Run automated verification2526Run the repo's build/test/lint verification for the changeset. Resolve what27to run in this order — use the first that applies:28291. **Explicit command** — the `verify_cmd` input or a `$VERIFY_CMD` environment30 variable.312. **Repo-provided verification entry point** — a canonical script or target the32 repo already defines: e.g. `./scripts/verify.sh`, `./bin/verify`,33 `make verify`, `make check`, or the verification commands documented in the34 repo's `AGENTS.md` / `CONTRIBUTING.md`. Prefer a changed-files-aware runner35 if the repo has one.363. **The bundled inference helper** — `scripts/verify.sh` (shipped with this37 skill) detects the repo's toolchain(s) and runs their standard38 build/test/lint commands:3940 ```bash41 scripts/verify.sh # exit 0 = pass, 1 = failures, 2 = could not infer42 ```43444. **Manual derivation** — if the helper exits 2 (nothing inferable, or a45 build system like Bazel that needs targeted invocation), derive the exact46 commands from the repo's docs and build files for the packages you changed,47 and run those. **Never skip verification silently** — if truly nothing can48 be run, state that explicitly in the final summary.4950If any check fails, diagnose and fix the issue before proceeding. Re-run51until all checks pass. Maximum 3 fix iterations — if still failing after 352attempts, report the remaining failures and stop.5354### Step 1.2 — Apply mechanical checklists5556Determine which files and languages are affected by the changes:5758```bash59BASE="${base_branch:-$(git remote show origin | sed -n 's/.*HEAD branch: //p')}"60git diff --name-only "$(git merge-base "origin/${BASE}" HEAD)"...HEAD61```6263Then apply, in order:64651. **The general checklist** — `checklists/general.md` (shipped with this66 skill): language-agnostic mechanical items that apply to any changeset.672. **Repo-specific checklists** — from `checklists_dir` if provided, else68 auto-discover in the repo (in order): `.agents/checklists/`,69 `.dev/checklists/`, `docs/checklists/`. Apply every checklist whose70 language/stack matches the changed files.713. **Derived checklists** — for each affected language with no repo checklist,72 derive a short mechanical checklist *before* reviewing: read the repo's73 linter/formatter/compiler configs and agent docs, and extract the rules that74 are (a) binary and (b) would fail the build or CI (fatal warnings, import75 rules, naming rules, generated-file policies). Apply that list.7677Walk the checklists **one category at a time, with that category as your sole78focus for the sweep** (all files for diff hygiene, then all files for safety,79and so on) — controlled experiments show that an explicit "look for X" focus80directive raises defect detection far more than checklist possession alone.81Fix any violations found. If fixes were made, re-run Step 1.1 to confirm82nothing broke.8384---8586## Pass 2: Design Review8788Purpose: catch the things that make code good versus merely correct. This is89where the frontier model's intelligence earns its keep. No checklist can90enumerate these concerns — they require taste, judgment, and deep experience91with what makes software maintainable over years.9293### Independence9495The agent that wrote the code is a systematically biased reviewer of it: LLM96evaluators favor their own generations, and the effect is amplified when the97reviewing context contains the memory of writing — you remember the *intent*98and read the intent into the code. Therefore:99100- **Where the harness supports subagents**, run Pass 2 in a **fresh context**101 given only: the base-branch diff, the changed files (to read in full), the102 standards below, and — if invoked by a parent workflow — the spec/ticket.103 Not the implementation history or conversation.104- **Where it doesn't**, apply the fallback discipline: every judgment must be105 argued from what is on disk, re-read in full — never from memory of writing106 it. If you catch yourself thinking "this is fine, I know why I did it,"107 re-read the code as evidence instead.108109### The Reviewer Standards110111Review against the standards below, directing your attention to each concern112in turn. (The framing is a working stance, not magic: evidence shows role113assignment by itself doesn't improve judgment — what does measurably help is114explicitly focusing attention on each named concern, which is what the115categories below are for.)116117> You are a Staff Engineer with 15+ years of experience building and118> maintaining production distributed systems. You have mass-reviewed119> thousands of PRs across your career. You have seen how innocent-looking code120> decisions compound into unmaintainable systems over months and years. You121> have also seen the opposite — code that was a joy to come back to because122> someone made the right structural choices up front.123>124> You are not a pedant. You don't care about bikeshedding or stylistic125> trivia — the mechanical checklist in Pass 1 already handled that. You care126> about the things that determine whether this code will age well or poorly:127>128> **Abstraction Quality**129> - Is each function/class/module doing one thing well, with a clear contract?130> - Are the boundaries between components clean and well-motivated?131> - Could a competent engineer who has never seen this code understand the132> intent by reading the types, names, and structure — without needing133> inline comments as a crutch?134> - Is the level of abstraction appropriate? Not so concrete that similar135> logic is duplicated, but not so abstract that you need a PhD to trace136> the control flow?137>138> **Naming as Design**139> - Do names reveal intent and domain meaning, not implementation details?140> - Would someone reading a call site understand what's happening without141> jumping to the definition?142> - Are boolean parameters and return values self-documenting? (e.g.,143> `forceRefresh = true` vs a bare `true`)144> - Do collection variable names indicate what they contain, not just that145> they're collections?146>147> **DRY Without Over-Abstraction**148> - Is there duplicated logic that should be a shared utility or method?149> - But equally important: is anything abstracted *prematurely*? Is a150> "reusable" component actually used in only one place, adding indirection151> without benefit?152> - Does factoring out shared code actually reduce total complexity, or does153> it just move it somewhere harder to find?154>155> **Error Handling as a Design Choice**156> - Are errors handled at the right level of the call stack — not too deep157> (swallowing context), not too shallow (leaking implementation details)?158> - Is enough context preserved for debugging in production? If this fails at159> 3am, will the error message tell the on-call engineer what happened?160> - Are failure modes explicit and visible, not hidden behind silent161> defaults, empty fallbacks, or swallowed exceptions?162> - Is the error handling strategy consistent with adjacent code in the163> same module?164>165> **Extensibility and Change Resilience**166> - What is the next feature someone will likely want to add in this area?167> Does this design make that easy, or will it require reworking the168> current change?169> - If the underlying data model changes (a new field, a new enum value, a170> new source type), how many files need to be touched? Is the blast171> radius proportional to the change?172> - Are there implicit assumptions or magic constants that will silently173> break when requirements evolve?174>175> **Codebase Coherence**176> - Does this code look like it *belongs* next to the adjacent code?177> - Does it follow the idioms and patterns established by the rest of178> the codebase — or does it introduce a new way of doing something that179> already has an established pattern?180> - If it introduces a new pattern, is there a compelling reason? Or is it181> just the agent's default style leaking through?182>183> **Simplicity and Proportionality**184> - Is this the simplest solution that handles all the actual requirements?185> - Could any part of the change be deleted without losing correctness or186> meaningful capability?187> - Is the complexity of the implementation proportional to the complexity188> of the problem it solves? Over-engineering is a design defect, not a189> virtue.190>191> **Test Quality** (where tests exist or should exist)192> - Do tests verify *behavior* and *contracts*, or do they just exercise193> code paths for coverage?194> - Are meaningful edge cases covered — empty inputs, error paths, boundary195> conditions?196> - Would a test failure give you enough information to diagnose the bug197> without re-running with debug logging?198> - Are test names descriptive enough to serve as documentation of expected199> behavior?200>201> **The Gestalt**202> - Step back and look at the full set of changes as a whole. Does this203> changeset tell a coherent story? Is the scope focused, or has it204> drifted into unrelated cleanup?205> - If you were the reviewer, would you feel confident approving this206> after reading it once? Or would you need to ask clarifying questions?207> - Is this the kind of code that builds trust with reviewers, or the kind208> that erodes it?209210### Procedure for Pass 22112121. **Get the diff against the base branch:**213 ```bash214 git diff "origin/${BASE}"...HEAD215 ```2162172. **Read every changed file in full** — not just the diff. The diff shows218 what changed, but correctness and design quality depend on the surrounding219 code. A one-line filter change is only correct if downstream code handles220 the new possible values.2212223. **Read adjacent files** to understand context, existing patterns, and how223 the changed code fits into the broader module. The goal is to see the224 change the way a reviewer who knows the codebase would see it.2252264. **For each file, evaluate against the design criteria above** — one227 category at a time; a focused sweep per concern outperforms one diffuse228 read. Be honest and critical. The point is not to validate your own work —229 it's to find the things a rigorous human reviewer would find.2302315. **For genuine issues: fix them.** Don't just note problems — resolve them.232 A self-review that produces a list of "consider doing X" is not a review,233 it's procrastination. Either it's worth fixing or it's not worth234 mentioning.2352366. **After all fixes, re-run Pass 1** (Step 1.1) to ensure nothing broke.237238### Calibration239240- **Only flag genuine issues.** A Staff Engineer doesn't leave nitpick241 comments on code that's already style-consistent and functionally correct.242 If the code follows established patterns and handles its cases, let it243 stand.244245- **Every flag must be demonstrable.** For each issue you raise, you must be246 able to state at least one of: the input/sequence that makes it fail, the247 contract or invariant it violates, or the concrete maintenance cost it248 incurs. LLM critics are known to hallucinate plausible-sounding bugs; if249 you cannot articulate the demonstration, the issue isn't real — drop it.250251- **Pragmatism over perfection.** The goal is production-quality code, not252 platonic-ideal code. If a minor abstraction improvement would require253 touching 10 additional files for marginal benefit, that's not worth doing254 in this changeset.255256- **"Maybe consider..." is not an action.** If you find yourself hedging,257 that's a signal it's not a real issue. Either commit to fixing it or move258 on.259260- **Respect existing patterns.** If the rest of the codebase handles a261 concern in a particular way, follow that way — even if you'd prefer a262 different approach in a greenfield project. Consistency is more valuable263 than local optimality.264265- **Shared-abstraction extraction:** factor repeated patterns into a shared266 utility/component only where it genuinely reduces complexity and the267 extraction would be used in 2+ places. Don't extract something used once —268 that's just indirection.269270---271272## Completion273274After both passes are done and all fixes have been verified:275276- Report a brief summary: how many mechanical issues were found and fixed,277 how many design issues were found and fixed, and the final verification278 status (including anything that could not be verified and why).279- If invoked as part of a parent workflow, return control to it.280- If invoked standalone, optionally commit and push the fixes.