| name | ai-review |
| description | Run an automated code review on the current branch's pull request and post findings as a formal PR review with inline comments. Use when the user asks for ai-review, PR review posting, or to review the open PR on the current branch (GitHub via gh, Forgejo via user-forgejo MCP). |
| disable-model-invocation | true |
AI Review
Perform an automated code review of the current branch's pull request and post the results as a formal PR review with inline comments. Use GitHub CLI (gh) for GitHub-hosted repos and Forgejo MCP (user-forgejo) for Forgejo-hosted repos. Use Context7 MCP (user-context7) for library documentation lookups when needed.
Step 1 — Validate branch and detect platform
Gather context first (run in parallel):
git branch --show-current
git remote get-url origin
- If the branch is
main or released, stop immediately and tell the user: "This command can only run on a feature branch with an open PR."
- Parse the git remote URL to extract owner, repo, and host:
https://user@github.com/all3dp/content-platform.git → host: github.com, owner: all3dp, repo: content-platform
https://user@code.vicoli.de/vicoli/resume_vicoli_de.git → host: code.vicoli.de, owner: vicoli, repo: resume_vicoli_de
- Set platform:
github.com → github (use gh for all PR operations below)
- any other host →
forgejo (use Forgejo MCP)
Step 2 — Find the PR
GitHub (platform: github)
Run:
gh pr view --json number,title,body,url,headRefOid,headRefName,baseRefName
If that fails (no PR for current branch), run:
gh pr list --head <branch> --json number,title,body,url,headRefOid,headRefName,baseRefName
- If no matching open PR exists, stop and tell the user: "No open PR found for branch
<branch>."
- Record the PR number, title, body, url, and headRefOid (
commit_id for posting reviews).
Forgejo (platform: forgejo)
Call Forgejo MCP list_repo_pull_requests with the owner, repo, and state: "open".
Find the PR whose head.ref (head branch) matches the current branch name.
- If no matching open PR exists, stop and tell the user: "No open PR found for branch
<branch>."
- Record the PR index (number) for subsequent calls.
Step 3 — Read PR description
Use the PR title and body from Step 2 to understand the intent and scope of the changes before reviewing the diff.
- GitHub: already returned by
gh pr view
- Forgejo: call
get_pull_request_by_index with owner, repo, and the PR index
Step 4 — Reconcile previous AI reviews
GitHub
gh api repos/{owner}/{repo}/pulls/{number}/reviews \
--jq '.[] | {id, body, user: .user.login}'
For each review whose body contains the marker <!-- ai-review -->:
- Fetch inline comments:
gh api repos/{owner}/{repo}/pulls/{number}/reviews/{review_id}/comments \
--jq '.[] | {path, line, body}'
- For each inline comment, check whether the issue has been actually resolved in the current code:
- Read the file at the comment's
path locally and inspect the code around the referenced line.
- Compare with the current PR diff to see if the flagged code has been changed, removed, or fixed.
- A finding is resolved if the problematic code no longer exists or has been corrected.
- GitHub does not support dismissing
COMMENT reviews. If every inline comment from a previous AI review is resolved, note that in the new review summary (e.g. "All findings from previous AI review are resolved."). If any finding is still unresolved, do not claim resolution and avoid re-posting the same finding unless it still applies.
Leave all non-marker reviews (human reviews, CI bot reviews) untouched.
Forgejo
Call Forgejo MCP list_pull_reviews with owner, repo, and the PR index.
For each review whose body contains the marker <!-- ai-review -->:
- Call
list_pull_review_comments to retrieve all inline comments from that review.
- For each inline comment, check whether the issue it flagged has been actually resolved in the current code (same rules as GitHub above).
- Only dismiss the review (via
dismiss_pull_review with message "All findings resolved") if every inline comment in that review has been addressed.
- If any finding from an old review is still unresolved, leave that review undismissed.
Leave all non-marker reviews (human reviews, CI bot reviews) untouched.
Step 5 — Gather review data
Run these in parallel:
GitHub
gh pr diff {number} — full unified diff
gh pr diff {number} --name-only — changed file paths
Forgejo
- Forgejo MCP
get_pull_request_diff (owner, repo, index)
- Forgejo MCP
list_pull_request_files (owner, repo, index)
Both platforms
- Read the file
.ai_review/project.md for project-specific review context (architecture, focus areas, anti-patterns). If missing, infer focus areas from changed file paths (WordPress/PHP plugins, TypeScript/Nitro workers, Nuxt apps, etc.).
- Read the file
.ai_review/config.yml and extract the exclude_patterns list. If missing, use these defaults:
Filter out any changed files that match exclude patterns:
*.lock, pnpm-lock.yaml, *.min.js, *.min.css, node_modules/**, dist/**, .nuxt/**, .next/**, .output/**, .turbo/**, apps/web/app/data/**
For each remaining changed file (that was not deleted), read the full source file locally to get deeper context beyond just the diff hunks.
Step 6 — Look up library docs
If the changed code uses APIs from Nuxt, Payload CMS, ORPC, Nuxt UI, or TailwindCSS, use the Context7 MCP (user-context7) to look up relevant documentation:
- Call
resolve-library-id with the library name to get its Context7 ID.
- Call
get-library-docs / query-docs with that ID and a focused topic query to retrieve relevant API docs.
Use this to verify the code is using library APIs correctly. Only look up docs when you are uncertain about correct usage — do not look up every library mentioned.
Step 7 — Analyze the diff
Review all changed files against the project review focus areas from .ai_review/project.md (or inferred focus areas if that file is missing). Focus on:
Critical (always flag):
- ORPC procedures missing Zod input/output schemas, incorrect CMS data transformation, missing locale passthrough
- Payload access control issues (
overrideAccess: false missing when user is passed)
- Transaction safety: nested Payload operations in hooks missing
req
- Hook loop risk: hooks that update the same collection without
context.skipHooks guard
- Vue SSR violations:
window/document access outside onMounted, useFetch in event handlers
- Security: hardcoded secrets, API keys in client bundles, missing Turnstile validation, shared secrets exposed to browser JS
- i18n inconsistency between CMS localization and frontend
@nuxtjs/i18n
- WordPress: missing capability checks, nonce verification, or server-side-only secret usage
Report when meaningful:
- Missing error handling in ORPC procedures or external HTTP calls
- Accessibility issues (missing
aria-label, tabindex, keyboard handlers)
- Image URLs bypassing imgproxy
- Lexical virtual fields being persisted
- Race conditions in async admin/editor flows
Skip entirely:
- Pure style/formatting nits (the project uses
@antfu/eslint-config with pnpm lint:fix)
- Suggestions to use Prettier, axios, Vuex, TanStack Vue Query, Options API, TypeScript enums, GraphQL, manual Vue/Nuxt imports, or custom CSS/
<style> tags (these are known false positives for Nuxt-centric codebases)
For each finding, record:
path: file path relative to repo root
line: line number on the new side of the diff where the issue occurs (parse from unified diff @@ hunk headers and + line counts)
body: the finding in markdown, prefixed with a severity tag: Security:, Bug:, Performance:, or Suggestion:
fix_prompt: a minimal one-line action statement for a Cursor agent to fix the issue (e.g. Fix double period typo in README.md line 3)
For Forgejo-only field naming: Forgejo inline comments use new_position instead of line — record both mentally, use the field name required by the target platform in Step 8.
Step 8 — Post the review
Always end the review body with the marker <!-- ai-review --> on its own line.
Example summary with findings:
**AI Review Summary**
Found 3 issues across 2 files (1 bug, 2 suggestions).
<!-- ai-review -->
Example summary with no findings:
**AI Review Summary**
No issues found. All changes look good.
<!-- ai-review -->
Each inline comment body must include the severity-tagged finding followed by a collapsed fix prompt block:
**Bug:** Description of the issue.
<details>
<summary>Fix prompt</summary>
```text
Fix the issue in path/to/file.ts line 42
```
GitHub (platform: github)
With inline comments — use the REST API (requires commit_id from Step 2):
gh api repos/{owner}/{repo}/pulls/{number}/reviews --method POST --input - <<'EOF'
{
"commit_id": "<headRefOid>",
"event": "COMMENT",
"body": "**AI Review Summary**\n\n...\n\n<!-- ai-review -->",
"comments": [
{
"path": "path/to/file.ts",
"line": 42,
"side": "RIGHT",
"body": "**Bug:** Description.\n\n<details>\n<summary>Fix prompt</summary>\n\n```text\nFix ...\n```\n\n</details>"
}
]
}
EOF
Without inline comments — use:
gh pr review {number} --comment -F review-body.md
where review-body.md contains the summary and <!-- ai-review --> marker.
Forgejo (platform: forgejo)
Call Forgejo MCP create_pull_review with:
-
owner, repo, index: from earlier steps
-
state: "COMMENT"
-
body: review summary (with <!-- ai-review --> marker)
-
comments: JSON string array of inline comments using new_position (not line):
[{"path": "apps/web/server/router/procedures/foo.ts", "body": "**Security:** Missing input validation.\n\n<details>\n<summary>Fix prompt</summary>\n\n```text\nAdd Zod input schema to the handler in apps/web/server/router/procedures/foo.ts line 42\n```\n\n</details>", "new_position": 42}]
Omit comments entirely if there are no findings.
Step 9 — Confirm
Tell the user the review was posted successfully, including:
- The platform used (
GitHub or Forgejo)
- The PR number and title
- How many findings were posted
- How many previous AI reviews were reconciled (and dismissed on Forgejo, or noted as resolved on GitHub)
- A link to the PR:
- GitHub: URL from
gh pr view
- Forgejo:
https://<host>/<owner>/<repo>/pulls/<index>