brave/review
'Review code for quality, root cause analysis, and fix confidence. Supports PR review and local review of uncommitted/branch changes. Default mode is local /review <pr_url>, /review local, /review, check bot pr quality.'
npx skills add https://github.com/brave/brave-core --skill review
Perform a comprehensive review of code changes. Supports two modes:
from master
Parse the arguments to determine the mode:
/review or /review local → Local mode/review <pr_url> or /review <pr_number> → PR modeIf no argument is provided or the argument is local, use local mode.
This skill runs from the src/brave (brave-core) directory.
src/) is at ../ relative to this repoWhen reviewing local changes, gather the diff from two sources:
The base branch is what this branch's changes should be compared against. Do NOT
assume master — the branch may depend on another feature branch.
Detect the base branch in this order:
branch:
CURRENT_BRANCH=$(gitbranch --show-current)
PR_BASE=$(gh pr view "$CURRENT_BRANCH" --repo brave/brave-core \
--json baseRefName --jq '.baseRefName' 2>/dev/null) || true
branch tracks:
TRACKING=$(gitrev-parse --abbrev-ref \
"$CURRENT_BRANCH@{upstream}" 2>/dev/null) || true
# Strip the remote prefix (e.g., "origin/branch-A" -> "branch-A")
master: If neither method yields a result, use master.# 1. Get the merge base with the detected base branch
MERGE_BASE=$(gitmerge-base HEAD $BASE_BRANCH)
# 2. Get all committed changes on this branch since diverging from base
gitdiff $MERGE_BASE..HEAD
# 3. Get uncommitted changes (staged + unstaged)
gitdiff HEAD
# 4. Get list of changed files for context
gitdiff --name-only $MERGE_BASE..HEAD
gitdiff --name-only HEAD
Combine these diffs to form the complete set of changes to review. The combined
diff represents what would be in a PR against $BASE_BRANCH if one were created
right now.
Report the base branch at the start of the review so it's clear what the
changes are compared against (e.g., "Reviewing against base branch:
branch-A").
gitbranch --show-current
gitlog $MERGE_BASE..HEAD --oneline
context
Then proceed to the Common Analysis Steps below (Step 3 onward), using the
gathered diff instead of a PR diff.
Note: For local reviews, skip Steps 1-2 (PR-specific steps) and the
filtering scripts step (Step 4), since there is no PR or GitHub data to filter.
When reviewing a PR, follow Steps 1-3 below, then continue with the Common
Analysis Steps.
Extract PR information from the provided URL:
# Example: https://github.com/brave/brave-core/pull/12345
PR_REPO="brave/brave-core" # or extract from URL
PR_NUMBER="12345" # extract from URL
Get PR details:
gh pr view $PR_NUMBER --repo $PR_REPO --json title,body,state,headRefName,author,files
CRITICAL: Before evaluating the current fix, understand what has been tried
before. If previous attempts exist, the current fix **MUST prove it is
materially different or the review is an AUTOMATIC FAIL**.
Where to search: Previous fix attempts live as pull requests in the target
repository (typically brave/brave-core). Search by issue number AND by test
name/keywords, since not all PRs reference the issue directly:
# Extract issue number from PR body
ISSUE_NUMBER="<extracted from PR body>"
# Search PRs in the target repo by issue number and test name
gh api search/issues --method GET \
-f q="repo:brave/brave-core is:pr $ISSUE_NUMBER OR <test-name>" \
--jq '.items[] | {number, title, state, html_url, user: .user.login}'
For each previous attempt found:
# Get the diff to understand what was tried
gh pr diff <pr-number> --repo brave/brave-core
# Get review comments to understand why it failed/was rejected
gh pr view <pr-number> --repo brave/brave-core --json reviews,comments
Document findings:
When previous fix attempts exist, you MUST compare the current PR's diff against
each previous attempt's diff and answer:
not just the PR description. Look at:
check, both reorder operations)?
RunUntilIdle() call. This PR instead usesTestFuture to synchronize on the specific callback."
condition by adding an observer."
guard)
duration, different variable name for the same fix)
The burden of proof is on the current fix. If you cannot clearly articulate
why this fix is different from previous failed attempts, the review MUST FAIL
with the reason: "Fix is not materially different from previous attempt(s)
The following steps apply to both local and PR mode reviews.
For PR mode, fetch the full diff once and save it for subagent use:
PR_DIFF=$(gh pr diff $PR_NUMBER --repo $PR_REPO)
For local mode, the diff was already gathered in Step L2. Combine the
committed + uncommitted diffs into PR_DIFF.
Extract the file list from the diff:
echo "$PR_DIFF" | grep '^diff --git' | sed 's|.*b/||'
File classification is handled automatically by the discovery script in Step 6.1
— no manual classification needed.
For the associated issue (if any):
gh issue view $ISSUE_NUMBER --repo brave/brave-browser --json title,body,comments
For PR reviews and comments:
gh api repos/$PR_REPO/pulls/$PR_NUMBER/reviews --paginate
gh api repos/$PR_REPO/pulls/$PR_NUMBER/comments --paginate
gh api repos/$PR_REPO/issues/$PR_NUMBER/comments --paginate
Analyze the code in context:
# For each changed file, read the full file to understand context
# Example: If the diff modifies browser/ai_chat/ai_chat_tab_helper.cc
# Read: src/brave/browser/ai_chat/ai_chat_tab_helper.cc
# If modifying src/brave/chromium_src/chrome/browser/foo.cc
# Also read ../chrome/browser/foo.cc to understand what's being overridden
Questions to answer:
IMPORTANT: The main context does NOT load best practices docs directly. Each
review is performed by subagents — one per chunk of ~3 rules — running in
parallel. Large best-practice documents are split into evenly-sized chunks by a
preprocessing script, so each subagent handles a focused set of rules. This
ensures every rule is systematically checked rather than relying on a single
pass to hold many rules in mind.
**ZERO-TOLERANCE RULE: You MUST launch a subagent for EVERY chunk from EVERY
discovered document. No exceptions. No filtering. No "focusing on key areas." No
commentary about the number of chunks. Just launch them all.**
CRITICAL — NO SHORTCUTS FOR LARGE DIFFS: Regardless of diff size (even
100KB+), you MUST pass the complete, untruncated diff to every subagent and
review ALL changed files. Do NOT skip files, truncate the diff, selectively
review "key chunks", or take any other shortcut based on diff size. The chunked
subagent architecture is specifically designed to handle large diffs — each
subagent only checks ~3 rules, so the diff size is not a constraint. If the diff
is large, that means MORE subagents are needed, not fewer.
CRITICAL — LAUNCH ALL DISCOVERED DOCS: You MUST launch subagents for ALL
documents returned by the discovery script — not just the ones you consider
"most relevant." The discovery script already filters out inapplicable
categories (e.g., iOS docs when no iOS files changed). If a document appears in
the discovery output, it MUST get a subagent. Do NOT second-guess the discovery
script or selectively skip documents. The only filtering happens in the script;
you do not apply additional filtering.
CRITICAL — NO COMMENTARY ABOUT CHUNK COUNT: Do NOT output any text
commenting on the number of chunks, expressing concern about the volume of work,
or announcing that you will "focus on key areas" or "launch focused subagents
for the most relevant areas." Just launch ALL subagents silently. The number of
chunks is irrelevant — launch them all in parallel without editorializing. Any
message like "Given the large number of chunks (N total), I'll focus on..." is
WRONG and violates this skill's requirements. You must launch every single chunk
subagent regardless of how many there are.
For each applicable best-practice document, run the chunking script to split it
into groups of ~3 rules, then launch one subagent per chunk. **Use multiple
Agent tool calls in a single message** so they run in parallel. Pass the
PR_DIFF content (fetched in Step 3) directly in each subagent's prompt so they
don't need to fetch it again.
Discovery step: First, determine which best-practice docs apply to this
change. The discovery script auto-detects applicable documents based on changed
file types — no hardcoded document list needed:
# Extract changed file paths from the diff
CHANGED_FILES=$(echo "$PR_DIFF" | grep '^diff --git' | sed 's|.*b/||')
# Discover applicable docs (pass changed files via stdin)
echo "$CHANGED_FILES" | python3 ./.claude/skills/review/discover-bp-docs.py \
./docs/best-practices/ --changed-files-stdin
The script outputs JSON with each applicable doc's path and category. Documents
are matched to file types by naming convention (e.g., testing-*.md applies
when test files are changed, android.md when .java/.kt files are changed).
Documents that don't match any specific category (like architecture.md,
documentation.md) are always included.
Chunking step: For each discovered document, run:
python3 ./.claude/skills/review/chunk-best-practices.py <doc_path>
This outputs JSON with one or more chunks per document. Each chunk contains:
doc: the source document filenamechunk_index / total_chunks: position within the documentrule_count: number of ## rules in this chunkheadings: list of rule heading texts (for the audit trail)content: the full text to pass to the subagent (includes the doc header +the chunk's rules)
Small documents (<=5 rules) produce 1 chunk. Large documents are split evenly
(e.g., 25 rules → 5 chunks of 5). Launch one subagent per chunk.
Each subagent prompt MUST include:
content field from the chunking scriptoutput directly in the prompt. The subagent does NOT read any files — all
rules are provided inline. Include it like:
Here are the best practice rules to check:
<chunk content>
directly in the prompt. Never omit, summarize, or truncate any portion of the
diff regardless of its size. The subagent MUST NOT call gh pr diff or
git diff — the diff is already provided. Embed it in the prompt like:
Here is the diff to review:
<PR_DIFF content>
+prefix) or in unchanged code visible in the diff, do NOT comment on it or
suggest fixing it -- unless the changes directly affect or break that
surrounding code
duplicate DEPS entries, code inside wrong #if guard)
involves dependencies, includes, or patterns, read the full file context
(e.g., the BUILD.gn deps list, existing includes in the file) to verify
your claim is accurate. Do NOT claim a PR "adds a dependency" or
"introduces a pattern" if it already existed before the PR.
or architectural issue already existed before this PR, do not flag it —
even if it violates a best practice. The author is not responsible for
pre-existing issues. Focus exclusively on what the changes add or modify.
When a + line imports or calls a function/class/variable from another
module, and that symbol's definition is NOT in a file changed by the diff,
do not comment on the symbol's naming. Only flag naming issues on symbols
that are defined or renamed within the changed files.
scrutiny — type mismatches, truncation, and correctness issues should use
stronger language
headers, simple inline getters in headers, style preferences not in the
documented best practices, include/import ordering (this is handled by
formatting tools and linters)
NOT make claims based on general knowledge or assumptions about what
"should" be a best practice. If the best practices docs do not contain a
rule about something, do NOT flag it as a violation — even if you believe
it to be true. Hallucinated rules erode trust and waste developer time.
When in doubt, do not comment.
"nit:" for genuinely minor/stylistic issues. Substantive issues (test
reliability, correctness, banned APIs) should be direct without "nit:"
prefix
a stable ID anchor (e.g., <a id="CS-001"></a>) on the line before the
heading. For each violation, the subagent MUST include a direct link using
that ID. The link format is:
https://github.com/brave/brave-core/tree/master/docs/best-practices/<doc>.md#<ID>
**CRITICAL: The rule_link fragment MUST be an exact <a id="..."> value
from the rules provided in the chunk.** Do NOT invent IDs, guess ID numbers,
or construct anchors from heading text. If no <a id> tag exists for the
rule, omit the rule_link field entirely.
**CRITICAL — this is what prevents the subagent from stopping after finding a
few violations.**
The subagent MUST work through its chunk heading by heading, checking every
## rule against the diff. It must output an audit trail listing EVERY ##
heading in the chunk with a verdict:
AUDIT:
PASS: Always Include What You Use (IWYU)
PASS: Use Positive Form for Booleans and Methods
N/A: Consistent Naming Across Layers
FAIL: Don't Use rapidjson
PASS: Use CHECK for Impossible Conditions
... (one entry per ## heading in the chunk)
Verdicts:
This forces the model to explicitly consider every rule rather than satisficing
after a few findings.
Each subagent MUST return this structured format:
DOCUMENT: <document name> (chunk <chunk_index+1>/<total_chunks>)
AUDIT:
PASS: <rule heading>
N/A: <rule heading>
FAIL: <rule heading>
... (one line per ## heading in the chunk)
VIOLATIONS:
- file: <path>, line: <line_number>, severity: <"high"|"medium"|"low">, rule: "<rule heading>", rule_link: <full GitHub URL to the rule heading>, issue: <brief description>, draft_comment: <1-3 sentence comment>
- ...
NO_VIOLATIONS (if none found)
Severity guide:
- **high**: Correctness bugs, use-after-free, security issues, banned APIs, test reliability problems (e.g., RunUntilIdle)
- **medium**: Substantive best practice violations (wrong container type, missing error handling, architectural issues)
- **low**: Nits, style preferences, missing docs, naming suggestions, minor cleanup
After ALL chunk subagents return:
severity: high → medium → low.
rule_link, extract thefragment ID and validate it exists in the target doc:
python3 ./script/manage-bp-ids.py --check-link <ID> --doc <doc>.md
If the ID is invalid, strip the link from the comment text. Violations
missing rule_link that are not genuine bug/correctness/security findings
should be dropped.
remaining violation by reading the actual source code:
Read tool (not the diff) to see the full file context
instead of Y", confirm X is actually available, appropriate, and consistent
with the rest of the file/module
file to confirm deprecation. Do NOT rely on training data
or patterns that explain the code
incorrect, drop it
walk through the remaining violations sequentially. For each violation,
present it to the user and ask whether they want it fixed:
**Violation 1/N** (severity: high)
**File**: path/to/file.cc:42
**Rule**: <rule heading>
**Issue**: <description>
**Suggested fix**: <what the fix would look like>
Fix this violation? (yes/no/skip)
if not already loaded, make the targeted change, then confirm what was
changed before moving to the next violation.
without further prompting.
proceed to the report.
Fix guidelines:
requires
and ask the user which approach they prefer before editing
or new tests), say so and move on
Best Practices section. Mark each as (fixed) or (unfixed) so the user
knows what remains.
Read the PR body and any issue analysis carefully.
Check for RED FLAGS indicating insufficient root cause analysis:
These words are acceptable ONLY if followed by concrete investigation:
signal Z ensures proper ordering."
hope)
contribute - e.g., different UI elements, additional features, different
timing characteristics, etc.)
Watch for generic explanations that could apply to any bug:
Demand specifics:
If a test fails in Brave but passes in Chrome (or is flaky in Brave but stable
in Chrome), the root cause analysis MUST explain what Brave-specific factors
contribute:
Without this explanation, the analysis is incomplete even if the general
mechanism is understood.
These checks are performed directly by the main context (not subagents) because
they require PR-level reasoning rather than per-rule checking:
If the fix works by altering execution timing rather than adding proper
synchronization:
BANNED patterns:
RunUntilIdle() (explicitly forbidden by Chromium)ACCEPTABLE patterns:
base::test::RunUntil() with a proper conditionTestFuture for callback synchronizationEvalJs() or ExecJs() inside RunUntil() lambdasIf the fix is disabling a test:
CRITICAL: Use the most specific filter file possible.
Filter files follow the pattern: {test_suite}-{platform}-{variant}.filter
Available specificity levels (prefer most specific):
browser_tests-windows-asan.filter - Platform + sanitizer specific (MOSTSPECIFIC)
browser_tests-windows.filter - Platform specificbrowser_tests.filter - All platforms (LEAST SPECIFIC - avoid if possible)Before accepting a test disable, verify:
bot/arch/_) and CI job names
macOS-specific behavior)
vs non-OFFICIAL)
Examples:
browser_tests-windows-asan.filterbrowser_tests-linux.filterbrowser_tests.filter
applies to upstream Chromium tests (defined in src/ but NOT in
src/brave/). Brave-specific tests won't appear in the Chromium database.
For Chromium tests, check the LUCI Analysis database:
python3 ./script/check-upstream-flake.py "<TestName>"
The script queries analysis.api.luci.app and returns a verdict:
the PR comment mentions upstream flakiness.
should document this.
cause is likely Brave-specific. The PR must explain what Brave-specific
factors cause the failure. A disable without this explanation is a **red
flag**.
Manual analysis needed.
Use --days 60 for a wider lookback window if the default 30 days has
insufficient data.
Red flags (overly broad disables):
browser_tests.filter when failure is only reported on one platform(ASAN/MSAN/UBSAN)
For flaky tests, the root cause analysis must explain **why the failure is
intermittent** - not just why it fails, but why it doesn't fail every time:
Questions to answer:
Examples of good intermittency explanations:
complete before the screenshot is captured, depending on system load"
scheduling happens to interleave the operations in a specific order"
faster machines, it doesn't"
Red flags (incomplete analysis):
Rate confidence level:
CRITICAL: Avoid Redundancy
everything above
CRITICAL: Fill Informational Gaps Yourself
in Brave but not upstream?"), DO THE RESEARCH and provide the answer in your
analysis
from the PR author that you cannot provide
missing context - if you filled the gaps, confidence should be higher
CRITICAL: No Vague Language in YOUR Analysis
the PR's analysis
have NOT completed the review
Action" section
this is incomplete
is returned, OR list "Determine exact channel value returned in CI
environment" as an issue requiring investigation
# PR Review: #<number> - <title>
## Summary
<2-3 sentences: what this PR does, the root cause, and whether the fix is
appropriate>
## Context
- **Issue**: #<number or "N/A">
- **Previous attempts**: <Brief list or "None found">
- **Differentiation**: <How this fix differs from previous attempts, or "N/A -
no previous attempts">
## Analysis
### Root Cause
<Summarize the PR's explanation. If incomplete, research and provide the missing
context yourself rather than flagging it as an issue.>
### Brave-Specific Factors (if applicable)
<If this fails in Brave but not upstream, research and explain why. Provide this
context yourself.>
### Fix Evaluation
<Does the fix address the root cause? Any best practices violations?>
### Best Practices (Chunked Subagent Results)
<Summarize findings from the chunked best practices review. List any validated
violations with file, line, severity, and the specific rule violated. Include
rule links where available.>
## Issues Requiring Author Action
<ONLY list issues that genuinely require the PR author to take action. Do NOT
include:
- Informational gaps you filled in the Analysis section
- Context you researched and provided above
- Minor suggestions>
If no issues: "None - PR is ready for review."
## Verdict: PASS / FAIL (assessed AFTER accounting for any context you provided above)
**Confidence**: HIGH / MEDIUM / LOW
<1-2 sentence reasoning>
# Local Review: <branch-name>
## Summary
<2-3 sentences: what these changes do and whether the approach is sound>
## Changes Overview
- **Branch**: <branch-name>
- **Base branch**: <base-branch> (how it was detected: PR / tracking / default
master)
- **Files changed**: <count>
- **Commits on branch**: <count> (+ uncommitted changes if any)
## Analysis
### Change Evaluation
<What do the changes accomplish? Is the approach correct? Any logic errors?>
### Best Practices (Chunked Subagent Results)
<Summarize findings from the chunked best practices review. List any validated
violations with file, line, severity, and the specific rule violated. Include
rule links where available.>
## Issues Found
<List significant issues that should be addressed before creating a PR. Do NOT
include:
- Style preferences
- Minor naming suggestions
- Optional refactoring ideas>
If no issues: "None - changes look ready for PR."
## Verdict: PASS / FAIL
**Confidence**: HIGH / MEDIUM / LOW
<1-2 sentence reasoning>
DO report:
DO NOT report:
timing issue exists or why this change fixes it. Specifically, what two
operations are racing and how does the new wait prevent that race?"
source code in src/brave/ and src/.** Do not make assertions about APIs,
patterns, deprecations, or behavior without first confirming them in the
actual codebase. Look at how the API/pattern is used elsewhere, check header
files for documentation, and read upstream Chromium code when relevant. Every
comment you make should be grounded in what the code actually says, not
assumptions.
user explicitly asks**
If the user asks you to post the review as a comment on GitHub, **always prefix
the review body** with:
I generated this review about the changes, sharing here. It should be used for
informational purposes only and not as proof of review.
This disclaimer must appear at the very beginning of the review body (as plain
text, not as a blockquote).
Post as inline code comments when possible. When the review identifies
specific issues tied to files and lines, post them as inline review comments on
the actual code rather than as a single general comment. Use the GitHub review
API to submit a single review with:
disclaimer prefix above)
gh api repos/brave/brave-core/pulls/{number}/reviews \
--method POST \
--input - <<'EOF'
{
"event": "COMMENT",
"body": "I generated this review about the changes, sharing here. It should be used for informational purposes only and not as proof of review.\n\n## Summary\n...\n\n## Verdict: PASS/FAIL\n...",
"comments": [
{
"path": "path/to/file.cc",
"line": 42,
"side": "RIGHT",
"body": "specific issue description for this line"
}
]
}
EOF
Key details:
side: "RIGHT" targets the new version of the file (changed lines)line is the line number in the new fileauthor)
review body instead
back to including that issue in the review body
Review local changes (default - no argument needed):
/review
/review local
Review a specific PR by URL:
/review https://github.com/brave/brave-core/pull/12345
Review a PR by number (assumes brave/brave-core):
/review 12345
FAILED the review)
prefix)
Take brave/review from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.