Skip to content

feat(hooks): review per-commit + pre-PR gate, replacing pre-push review#3056

Open
mmagician wants to merge 6 commits into
nextfrom
mmagician-claude/per-commit-review
Open

feat(hooks): review per-commit + pre-PR gate, replacing pre-push review#3056
mmagician wants to merge 6 commits into
nextfrom
mmagician-claude/per-commit-review

Conversation

@mmagician

@mmagician mmagician commented Jun 5, 2026

Copy link
Copy Markdown
Collaborator

Spawn review agents after each commit + before creating a PR draft, instead of pre-push.
This has two effects:

  • review agents run regardless of whether the final task output is reviewed on GitHub or locally
  • the diff is much simpler to review on each commit (HEAD~1..HEAD), but we still run the pre-draft hook on the full PR as some changes might only be relevant within the broader PR context

The pre-draft hook will only be relevant when the engineer uses a /work command (see #3057) which goes full cycle towards opening a PR.
Other commands might need to be added alongside /work for local-first workflows

Reviewers now run as a PostToolUse hook on `git commit` over the commit's
own delta (HEAD~1..HEAD) and a PreToolUse gate on `gh pr create` over the
whole PR. Reviewing per commit makes the diff scope trivially the commit
itself, eliminating the base-selection logic (merge-base / @{upstream}
tracking, "don't flag pre-existing code" prompt rules) that pre-push
review needed to review each change once.

- _review.py: shared orchestrator (run both reviewers in parallel over a
  given diff range, parse severity, return blocked + rendered output).
- post_commit_review.py: PostToolUse on git commit; covers normal/-a/
  --amend/rebase uniformly via HEAD~1..HEAD; exit 2 halts the agent which
  fixes and amends to re-review.
- pre_pr_review.py: PreToolUse on gh pr create; whole-PR review against
  origin/HEAD merge-base; denies PR creation on findings.
- Delete pre_push_review.py; push keeps only its test gate.
- Simplify reviewer prompts to diff the range named in the prompt.
- Update settings.json and hook routing tests; add parser + base tests.

Supersedes #3048.
@mmagician mmagician added the no changelog This PR does not require an entry in the `CHANGELOG.md` file label Jun 5, 2026
Reviewing in context shouldn't mandate reading the whole file every time -
what matters is the relevant and related code (callers, callees, the rest
of the file where relevant), which may be the whole file or just a few
chunks.
@mmagician mmagician marked this pull request as ready for review June 5, 2026 12:32
claude and others added 3 commits June 5, 2026 12:47
The reviewers run as fresh subprocesses with no view of the conversation,
so they sometimes contradict choices the user explicitly asked for. Extract
the human prompts from the hook payload's transcript_path and pass them to
both reviewers, with a rule to respect deliberate, requested choices (real
correctness/security bugs still block).

- _hookutils.recent_user_prompts: parse the JSONL transcript, keep human
  turns (drop tool results, tool calls, and <system-reminder> noise),
  most-recent-first and length-capped.
- _review.run_review gains an `intent` arg folded into the reviewer prompt.
- post_commit_review / pre_pr_review pass the extracted intent.
- code-reviewer / security-reviewer prompts gain a respect-intent rule.
- Drop the recent_user_prompts unit tests (and unused import).
- Align the agent prompts with the hook's severity policy: Critical/
  Important (code) and Critical/Warning (security) block; Nits/Notes are
  surfaced but never block. Removes the contradiction where the prompts
  claimed "all findings block" while the hook only blocks the top tiers,
  and fixes the BLOCK/APPROVE/CLEAN verdicts to match.
- Stop mixing "Nit/Note": each agent uses its own lowest tier (Nit for
  code-reviewer, Note for security-reviewer); the shared run_review prompt
  is now convention-neutral and defers severity to each agent's rules.
- Stricter intent handling: a genuinely exploitable/real defect a user
  requested stays blocking; only downgrade to a Nit/Note when the objection
  is defensive-programming hardening or a non-critical weakness.
@mmagician mmagician requested a review from Fumuran June 8, 2026 09:09

@partylikeits1983 partylikeits1983 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, but was wondering if we could make _review.py and _hookutils.py not have a prepended _.

Comment on lines -125 to +123
**All findings (Critical, Important, and Nit) block the merge.** Every issue must be addressed before pushing.
**Critical and Important findings block the merge; Nits are surfaced but do not block.** Address the blocking findings before pushing.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is great

Comment thread .claude/hooks/_review.py
Comment on lines +1 to +2
"""Shared reviewer orchestration for the review hooks.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why does this file name have a prepended _ and the others don't?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

no changelog This PR does not require an entry in the `CHANGELOG.md` file

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants