Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 101 additions & 18 deletions .github/workflows/wizrd-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,17 @@ on:
workflow_call:
inputs:
review_style:
description: 'concise | thorough — appended to the plugin prompt as guidance.'
description: 'concise | thorough'
required: false
type: string
default: 'concise'
confidence_threshold:
description: 'Minimum confidence (0-100) to include an issue. Lower = noisier.'
required: false
type: number
default: 80
extra_instructions:
description: 'Optional extra prompt text appended after the plugin invocation (e.g. point at REVIEW_RULES.md / CLAUDE.md).'
description: 'Optional extra prompt text appended to the review prompt.'
required: false
type: string
default: ''
Expand All @@ -32,30 +37,108 @@ jobs:
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 1
fetch-depth: 0

- uses: anthropics/claude-code-action@v1
with:
claude_code_oauth_token: ${{ secrets.claude_token }}
plugin_marketplaces: 'https://github.com/anthropics/claude-code.git'
plugins: 'code-review@claude-code-plugins'
additional_permissions: |
actions: read
claude_args: >-
--allowed-tools
"Bash(gh pr view:*),Bash(gh pr diff:*),Bash(gh pr comment:*),Bash(gh issue view:*),Bash(gh api:*),Bash(git log:*),Bash(git diff:*),Bash(git show:*),Bash(git blame:*),Bash(grep:*),Bash(find:*),Bash(ls:*),Bash(cat:*),Bash(head:*),Bash(tail:*),Bash(wc:*),Read,Glob,Grep,Task"
prompt: |
/code-review:code-review --comment ${{ github.repository }}/pull/${{ github.event.pull_request.number }}
You are the Wizrd code reviewer for PR ${{ github.event.pull_request.number }} in **${{ github.repository }}**.

## Step 1 — Should we review?

Run `gh pr view ${{ github.event.pull_request.number }} --json state,isDraft,title,body,comments,additions,deletions,files`.

Skip (exit without posting anything) if any of:
- PR is closed or merged.
- PR is draft.
- PR is trivial: <10 changed lines, OR only touches lockfiles / generated files / docs typos.
- A previous Wizrd review comment already exists (look for `<!-- wizrd-review -->` marker in existing comments). If one exists, update plan: post a fresh comment only if there are NEW commits since the last review — otherwise skip.

If skipping, log the reason and stop. Do NOT post anything.

## Step 2 — Load review rules

Read the FIRST file that exists (in this order). Treat its content as the canonical review checklist:

1. `REVIEW_RULES.md` — repo-specific checklist. May use rule codes (e.g. B1, R3, A2). Reference codes verbatim in findings.
2. `CODE_REVIEW.md` — same idea, alternate name.
3. `CLAUDE.md` — prose project rules. Extract the relevant ones.
4. `.claude/ci-agent-context.md` — additional CI agent context.

If none exist, apply standard senior-engineer judgement: correctness, security, simplicity, tests, performance, error handling, type safety.

## Step 3 — Read the diff

`gh pr diff ${{ github.event.pull_request.number }}` — focus only on changed lines.

For non-trivial PRs (>50 changed lines OR >5 files), spawn parallel sub-agents via the Task tool:
- **Agent A: Rules compliance** — verify every changed file against the loaded review rules. Reference rule codes if available.
- **Agent B: Bug detector** — look for obvious bugs IN THE CHANGES (not pre-existing). Off-by-one, null deref, race conditions, missing await, wrong API, broken happy path.
- **Agent C: Context analyzer** — for any suspicious change, run `git blame` / `git log -p` on surrounding lines to understand why it was that way before. Flag refactors that silently change behaviour.

For small PRs, do it inline.

## Step 4 — Score findings

Each finding gets a confidence score 0-100:
- 0-24: false positive / not confident → DROP
- 25-49: might be real → DROP
- 50-74: probably real but minor → DROP
- 75-100: real and important → KEEP

Threshold: **${{ inputs.confidence_threshold }}**. Drop anything below.

Filter out:
- Pre-existing issues not introduced in this PR.
- Pedantic style nitpicks the linter would catch.
- Auto-generated files, lockfiles, migration boilerplate.
- Issues with `lint-disable` / `eslint-disable` / `# noqa` comments nearby.

## Step 5 — Format the review

```
<!-- wizrd-review -->
## Wizrd review

<2-sentence PR overview based on the diff>

### 🔴 BLOCKING (must fix before merge)
<issues; reference rule codes if available + file:line; if none: "No blocking issues found.">

### 🟡 REQUIRED (should fix before merge)
<issues; if none: "No required fixes.">

### 🟢 ADVISORY (reviewer discretion)
<skip section entirely if none>

### ✅ What's Good
<2-3 specific things>

---
<sub>Style: ${{ inputs.review_style }} · Threshold: ${{ inputs.confidence_threshold }} · ${{ github.sha }}</sub>
```

For each finding cite `file:line` and link to the line on GitHub:
`https://github.com/${{ github.repository }}/blob/${{ github.event.pull_request.head.sha }}/<path>#L<line>`

Be concise. Max ~30 lines combined for BLOCKING + REQUIRED. Group repeated patterns into one finding.

Review style: ${{ inputs.review_style }}.
## Step 6 — POST THE REVIEW

Before reviewing, read these if present (auto-discovery order):
REVIEW_RULES.md → CODE_REVIEW.md → CLAUDE.md → .claude/ci-agent-context.md.
Apply rule codes from REVIEW_RULES.md if it uses them (B/R/A). Otherwise apply
standard senior-engineer judgement: correctness, security, simplicity, tests.
This is the critical step. Use:

Categorise findings:
🔴 BLOCKING (must fix before merge)
🟡 REQUIRED (should fix before merge)
🟢 ADVISORY (reviewer discretion)
✅ What's Good (2-3 specific things)
```
gh pr comment ${{ github.event.pull_request.number }} \
--repo ${{ github.repository }} \
--body-file /tmp/wizrd-review.md
```

Be concise. Cite `file:line` for every code finding. Group repeated patterns.
Skip auto-generated files, lockfiles, migration boilerplate.
Write the formatted review to `/tmp/wizrd-review.md` first (heredoc), then post. Do NOT skip this step. Do NOT just print the review to stdout — it MUST land on the PR.

${{ inputs.extra_instructions }}