Bitwarden Code Review
Skill 10 of 83
Review a GitHub pull request or local changes and write the review to local files instead of posting
6 minutes · 1,241 words
Install
npx skills add bitwarden/ai-plugins --skill code-review-localnpx skills add bitwarden/ai-plugins/plugin marketplace add bitwarden/ai-pluginsThe first command installs just this skill, by the name in its SKILL.md; the second installs the whole repository.
Take --base <ref> out of $ARGUMENTS first, before anything below reads it. The accepted form is exactly that — --base, a space, then the ref — and nothing else. Remove the pair and resolve the target from what is left, so --base origin/rc on its own still reaches the interactive path instead of being read as a target. It names the ref local mode diffs against, and it applies to local changes only — with a pull request target, drop it and say you did. A pull request’s base is the one GitHub records, and gh pr diff already uses it.
Any other appearance of the token --base is an error, --base=<ref> and a trailing --base with nothing after it and a second --base among them. Do not invoke the Task tool: say which form you were given and ask again. The rule is stated this way round on purpose — an enumeration of bad forms is a closed list, and the next one nobody thought of falls through it.
Never continue with the default base once --base has appeared in any form. An unrecognized form leaves no ref to validate, so it would otherwise reach the interactive path, emit no BASE: line, and let the agent review the trunk merge base under an ordinary verdict with nothing saying the requested base was dropped. That is the silent wrong scope this parameter exists to prevent, and the entry path is the only place it could still happen. Aborting here also keeps a leftover token out of target resolution, where a --base=rc2 could have its 2 read as a pull request number.
The ref must match ^[A-Za-z0-9][A-Za-z0-9._/-]*$ before it goes into the BASE: line. It is written verbatim into git diff <ref>...HEAD, and Bash(git diff:*) is a prefix rule, so a value starting with - matches that rule as an option rather than a ref and reaches git as a flag. The leading character class is what rejects that; the rest keeps whitespace, shell metacharacters, and @{ out of the command string. If the value does not match, do not invoke the Task tool at all: report what you were given and ask again.
Take --output-dir <path> out of $ARGUMENTS too, before resolving the target. The only accepted form is --output-dir, a space, then the path, which ends at the next whitespace; any other form is an error, handled as for --base. Unlike --base, it applies to both targets. Expand a leading ~ to the home directory, then make the path absolute, resolving a relative one against the working directory. Without the flag, emit no OUTPUT_DIR: line; the agent defaults to ${CLAUDE_PLUGIN_DATA}/code-reviews/.
Resolve the target next, in this turn. Two ways in:
$ARGUMENTS names a PR. Extract just the number — 123, https://github.com/org/repo/pull/456, and PR #789 all yield a bare integer.$ARGUMENTS is empty, or names nothing that parses as a PR. Use AskUserQuestion to ask whether to review a pull request or the local changes, and settle it here; the agent runs as a subagent and cannot prompt mid-run, so a question left for it has no one to answer. This turn cannot list open PRs, so take the number as free text rather than offering a menu.If the target is a pull request, the number must match ^[0-9]+$ before it goes into the TARGET: line. (A local-changes target has no number; this check does not apply to it.) It is written verbatim into gh pr view, gh pr diff, and the GraphQL variable below, and Bash(gh pr view:*) is a prefix rule — gh pr view 1 --repo attacker/repo would match it and redirect the review. If the value does not match, do not invoke the Task tool at all: report what you were given and ask again. Never delegate without a resolved target.
Then invoke the Task tool with subagent_type: "bitwarden-code-review:bitwarden-code-reviewer". Begin the prompt with the resolved target on its own line, in exactly one of these forms, followed by everything from CRITICAL INSTRUCTIONS FOR THE AGENT onward — not this paragraph, which is addressed to the command turn and would tell the agent not to do its own job:
TARGET: PR #<number>
TARGET: local changesOn the line after it, add BASE: <ref> — only when the target is local changes and a validated ref survived above. Omit the line entirely otherwise. There is no placeholder form: the agent defaults to origin/HEAD when the line is absent, and a placeholder would be diffed against as a literal ref name.
On the next line, always add OUTPUT: local files — both targets. This command writes to local files and never posts, so that declaration, not the target, is what Skill(posting-review-summary) routes on.
On the line after that, add OUTPUT_DIR: <absolute dir> — only when --output-dir was given. Omit the line entirely otherwise: there is no placeholder form, and the agent applies its default when the line is absent.
The TARGET: line is the only carrier — $ARGUMENTS is empty on the interactive path, so an agent left to re-derive the target from it would find nothing. This command’s own turn holds only AskUserQuestion and Task: it settles the target and delegates. Thread pre-fetching belongs to the workflow-driven /bitwarden-code-review:code-review, not here. Do not run the gh, git, Skill, or Write operations described below yourself — they are the agent’s, and it carries its own grants for them.
Invoke the bitwarden-code-reviewer agent now with the instructions below. When it returns, tell the user the full path of each file it wrote.
CRITICAL INSTRUCTIONS FOR THE AGENT:
Read the target from the TARGET: line at the top of this prompt. It is already resolved — the command turn settled it before delegating. Do not ask and do not re-derive it: you hold no AskUserQuestion grant and no one is there to answer.
TARGET: PR #<number> — use that number for thread detection and for fetching PR data with gh pr viewTARGET: local changes — follow the local-mode procedure in your AGENT.md, which defines how the base is resolved and what to do when there is nothing to review. Skip thread detection (step 2). The scope is whatever that procedure resolves, not both scopes at onceBASE: <ref> on the following line, when present — diff against that ref instead of origin/HEAD. Re-check it against ^[A-Za-z0-9][A-Za-z0-9._/-]*$ yourself; the command turn checked it, but you also run on prompts it did not write. Absent the line, use origin/HEADDetect Existing Threads (PR reviews only - skip for local changes):
Fetch existing review threads to prevent duplicate comments. Capture BOTH comment sources:
# General PR comments
gh pr view <PR_NUMBER> --json comments
# Inline review threads (resolved + open)
gh api graphql -f query='
query($owner: String!, $repo: String!, $pr: Int!) {
repository(owner: $owner, name: $repo) {
pullRequest(number: $pr) {
reviewThreads(first: 100) {
nodes {
id
isResolved
isOutdated
path
line
startLine
diffSide
comments(first: 10) {
nodes {
id
body
author { login }
createdAt
}
}
}
}
}
}
}
' -f owner="<OWNER>" -f repo="<REPO>" -F pr="<PR_NUMBER>"Thread Matching Logic - Before creating any new comment, check for matches:
| Match Type | Criteria | Action |
|---|---|---|
| Exact | Same file + same line | Use existing thread |
| Nearby | Same file + line within ±5 | Use existing thread |
| Content | Body similarity >70% | Use existing thread |
| No match | None of above | Create new comment |
Local Review Mode: Writing to local files instead of GitHub. Invoke Skill(posting-review-summary) with local output context.
Output Destination: Both files go to the local-file destination your AGENT.md Step 1 resolves — the OUTPUT_DIR: directory when that line is present, its default otherwise — under the names it assigns.
Format Exactly As PR Comments: Both files MUST contain exactly what would be posted to GitHub
No GitHub Posting: Do NOT use gh pr review --comment or gh pr comment to post anything. Only READ from GitHub, WRITE to local files.
Include All Standard Review Elements:
<details> sections for each findingNote: The output formats below mirror the standard GitHub review formats documented in your AGENT.md file, adapted for local file output instead of direct GitHub posting.
File 1: the summary file
Uses the same format as Skill(posting-review-summary), including its ## No Verdict form when nothing could be reviewed:
## 🤖 Bitwarden Claude Code Review
**Overall Assessment:** APPROVE / REQUEST CHANGES
[1-2 neutral sentence describing what was reviewed]
<details>
<summary>Code Review Details</summary>
- [emoji]: [One-line description]
- `filename.ts:42`
</details>File 2: the inline-comments file
Contains all inline review comments with file and line references (same format as would be posted with gh pr review --comment in standard GitHub reviews, but written to local file). Format:
## [file-path]:[line-number]
[Emoji]: [One-line description]
<details>
<summary>Details and fix</summary>
[Full details, code examples, rationale]
</details>
---
## [next-file]:[next-line]
[Next comment...]
---AskUserQuestionTaskplugins/bitwarden-code-review/skills/code-review-local/SKILL.mdmain, last pushed 6 November 2026.SKILL.md, not by matching a directory convention. 20 distinct layouts observed: plugins/bitwarden-abacus-tools/skills/*/SKILL.md, plugins/bitwarden-adr-tools/skills/*/SKILL.md, plugins/bitwarden-atlassian-tools/skills/*/SKILL.md, plugins/bitwarden-code-review/skills/*/SKILL.md, plugins/bitwarden-delivery-tools/skills/*/SKILL.md, plugins/bitwarden-design-tools/skills/*/SKILL.md, plugins/bitwarden-designer/skills/*/SKILL.md, plugins/bitwarden-devops-engineer/skills/*/SKILL.md, plugins/bitwarden-doc-parity/skills/*/SKILL.md, plugins/bitwarden-mailcatcher-tools/skills/*/SKILL.md, plugins/bitwarden-product-analyst/skills/*/SKILL.md, plugins/bitwarden-retrospective-tools/skills/*/SKILL.md, plugins/bitwarden-security-engineer/skills/*/SKILL.md, plugins/bitwarden-shepherd/skills/*/SKILL.md, plugins/bitwarden-stripe-tools/skills/*/SKILL.md, plugins/bitwarden-tech-lead/skills/*/SKILL.md, plugins/bitwarden-testing-tools/skills/*/SKILL.md, plugins/bitwarden-testmo-tools/skills/*/SKILL.md, plugins/claude-config-validator/skills/*/SKILL.md, plugins/claude-retrospective/skills/*/SKILL.md..claude-plugin/marketplace.json by Bitwarden, declaring 23 plugins. It is read for editorial metadata only — never as the skill index, which is always the repository tree./bitwarden/ai-plugins.md, and each skill at its own .md URL.1 file · 4 KB
Everything this skill ships beside its prose. All of it is set here, as a subchapter of skill 10.
Everything else published alongside the skill.