Skip to content
Back to skills

Bobby Review

ASecurity

Code Review Skill: Deep code review that traces data flow, checks callers, and catches regressions. MANDATORY TRIGGERS: review, code review, peer review, review PR, check code, approve, review changes.

  • 6 stars
  • 0 votes
  • 0 copies
  • 4 views
  • Added October 26, 2026
developmentgotestingdebugginggitapidatabaseperformance

Works with

  • api

Security analysis

A100/100

Pro scans all 3 files and shows the line behind each finding

Scanned October 26, 2026

npx -y skills add ccevans/bobbycode --skill bobby-review --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Bobby Review?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Bobby Review
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/ccevans-bobby-review/badge)](https://www.skillsdirectory.com/skills/ccevans-bobby-review)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: review-code
description: "Code Review Skill: Deep code review that traces data flow, checks callers, and catches regressions. MANDATORY TRIGGERS: review, code review, peer review, review PR, check code, approve, review changes."
argument-hint: "<ticket ID to review>"
---

# Bobby Review Skill

> Deep code review. Reads the full context around every change to catch regressions, broken callers, misused APIs, and LLM-typical mistakes. Separate agent from build for fresh perspective.

## Pre-flight Checks

1. **Check learnings** — Read `.claude/skills/bobby-review/learnings.md` + `.claude/skills/bobby-review/learnings.local.md` and `.claude/skills/bobby-shared/learnings.md` + `.claude/skills/bobby-shared/learnings.local.md` in parallel
2. **Branch check** — `git branch --show-current` must NOT be main/master
3. **Hygiene check** — `git status --short` should show no uncommitted source files (build agent left dirty state if it does)
4. **Load context** — Read these in parallel:
   - The ticket's `ticket.md` — acceptance criteria
   - The ticket's `plan.md` — intended approach
   - The ticket's `test-cases.md` — expected test coverage
5. **Understand what was built** — `git log --oneline main..HEAD` to see all branch commits

## Investigation First

<investigation_rules>
Before forming any opinion about the code:
- Read `ticket.md` and `plan.md` in parallel — understand what was supposed to be built and the intended approach
- Read every file referenced in `plan.md` that was supposed to change
- If the diff touches files not in the plan, read those files to understand why
- Do not approve or reject based on the diff alone — verify against the actual codebase
</investigation_rules>

## Deep Code Review

This is the core of your job. Don't skim diffs — investigate the code like you're debugging a production incident before it happens.

### 1. Trace the change boundaries

- Run `git diff main...HEAD --stat` — get an overview of every file touched
- For each changed file, **read the full file** (not just the diff hunk) to understand context
- Cross-reference against `plan.md`:
  - Files in the plan that were NOT changed — were they supposed to be?
  - Changed files NOT in the plan — why were they touched? Is this scope creep?

### 2. Check for breakage in callers and dependents

For every function, component, or API endpoint that was **modified or renamed**:
- Grep the codebase for its callers/consumers
- Verify callers still work with the new signature, return type, or behavior
- Check if any imports were added — do the imported modules actually export what's being used?
- Check if any exports were removed or renamed — are there consumers that still reference the old name?

### 3. Look for LLM-typical mistakes

<llm_mistakes>
These are patterns that LLM-generated code frequently gets wrong:

- **Hallucinated APIs**: Method calls on libraries/frameworks that don't exist (e.g., `router.pushState()` instead of `router.push()`, `db.findOneBy()` instead of `db.findOne()`). When you see an unfamiliar API call, verify it exists.
- **Stale references**: Code referencing variables, functions, or files that were renamed or removed elsewhere in the codebase.
- **Copy-paste drift**: Similar code added in multiple places that is subtly inconsistent (different arg order, missing a condition, wrong variable name).
- **Incomplete migrations**: A pattern was changed (renamed function, new API) but only in the new code — old call sites still use the previous version.
- **Wrong assumptions about existing code**: The builder may have misread how an existing function works and used it incorrectly. Verify the usage matches the actual implementation.
</llm_mistakes>

### 4. Performance and resource concerns

<performance_review>
Look for these specific patterns in the diff:

- **N+1 queries**: Database/API calls inside loops — each iteration triggers a separate query
- **Unbounded fetches**: Queries without LIMIT, pagination, or reasonable caps
- **Missing cleanup**: Event listeners, intervals, subscriptions, or timers that are added but never removed (memory leaks)
- **Synchronous blocking**: Heavy operations (file I/O, network calls, large data processing) that should be async
- **Redundant work**: Computing the same value multiple times when it could be computed once
- **Large objects in memory**: Holding entire datasets when only a subset is needed
</performance_review>

### 5. Verify test quality

Don't just check that tests exist — check that they would actually catch bugs:

- Do assertions check the **right thing**? A test that asserts `result !== null` passes even if the result is completely wrong.
- Are there tests that would pass even if the feature was completely broken? (e.g., only testing that a function doesn't throw)
- Do tests cover the sad path, not just the happy path? (invalid input, empty data, error conditions)
- Read `test-cases.md` and confirm each documented test case has a corresponding test in the diff
- Are test descriptions accurate? A test named "should filter by status" that doesn't actually test filtering is misleading.

## Decisions Check

Run `bobby decision list` to see the active decisions (it hides invalidated ones). Scan the changed code for violations. For each violation found, flag it by decision `id` in `review.md` under a "Decision Violations" section. A decision violation is a rejection reason.

If the change establishes a new constraint the codebase should be held to, record it with `bobby decision add --id … --fact … --why … --ticket {ID}` rather than editing `.bobby/decisions.yaml`.

Examples of what to look for based on the decision `fact` field:
- "Never call the database directly from UI components" → grep changed files for DB calls in component code
- "All API calls must go through the service layer" → check for direct fetch/axios calls in components
- Any project-specific constraint in `decisions.yaml`

## AC Verification

After the deep review, verify the minimum bar:

1. Re-read each acceptance criterion from `ticket.md`
2. For each AC, identify the specific code that satisfies it
3. If any AC lacks coverage, that's a rejection

## Run Tests and Lint

Run these independently to verify the build agent's work in a fresh context:


1. Tests: `npm test`
2. Lint: `npm run lint`


Show the output as evidence. If tests can't run (missing deps, broken environment), this is a BLOCK, not an approval.

## Review Artifact

Write `review.md` in the ticket directory with this structure:

```markdown
## Review — TKT-{ID}

### Verdict: Approved / Approved with Notes / Rejected / Blocked

### Files Reviewed
- `path/to/file.js` — {what changed, what you verified}

### Code Concerns
- {any issues found — broken callers, performance issues, LLM mistakes, etc.}
- {or "None found" if clean}

### Decision Violations
- {any violations of .bobby/decisions.yaml entries}
- {or "None" if decisions.yaml doesn't exist or no violations found}

### AC Verification
- [x] AC 1: {how it's satisfied}
- [x] AC 2: {how it's satisfied}

### Test/Lint Output
- Tests: {pass/fail, count}
- Lint: {pass/fail, summary}

### Notes
- {anything the next agent or human should know}
```

## Decision

### Approve
All checks pass, no concerns:
1. Write `review.md` in the ticket directory
2. **Commit any changes** you made (lint fixes, debug cleanup): `TKT-{ID}: review fixes`
3. Add comment: `bobby ticket comment {ID} --by bobby-review "Approved: {summary}"`
4. If you discovered a pattern future reviews should catch: `bobby learn bobby-review "pattern" "description"`
5. Move to testing: `bobby ticket move {ID} test`

### Approve with Notes
Code works and ACs are met, but you have observations worth recording — minor style drift, a pattern that could become a problem, a suggestion for future work. These do NOT block the ticket:
1. Write `review.md` with notes in the "Code Concerns" and "Notes" sections
2. **Commit any changes** you made: `TKT-{ID}: review fixes`
3. Add comment: `bobby ticket comment {ID} --by bobby-review "Approved with notes: {summary}. Notes: {observations}"`
4. Move to testing: `bobby ticket move {ID} test`

### Reject
Broken code, missing ACs, or serious quality issues:
1. Write `review.md` documenting every issue found
2. Move back with specific feedback: `bobby ticket move {ID} reject "Specific issue description"`
3. Be specific — the build agent needs to know exactly what to fix

<examples>
<example label="Good rejection (specific and actionable)">
`bobby ticket move TKT-042 reject "AC #3 not met: 'Filter persists after page refresh' — tested by refreshing /leads?status=active and the filter dropdown resets to 'All'. The filterByStatus function reads URL params but doesn't call setFilter on mount. Also: getLeadsByStatus() in leads-service.js is called by DashboardWidget (line 47) which expects an array return type, but the new implementation returns an object. Fix both."`
</example>

<example label="Bad rejection (vague)">
`bobby ticket move TKT-042 reject "Filtering doesn't work properly"`
Why this fails: The build agent won't know what specifically to fix or which AC failed.
</example>
</examples>

### Block
Can't complete review — tests won't run, environment broken, missing context:
1. Write `review.md` documenting what you were able to check and what blocked you
2. `bobby ticket move {ID} block "reason"`

## If Something Goes Wrong

- If you discover a systemic pattern: `bobby learn bobby-review "pattern" "description"`

---

## Project overrides

If `.claude/skills/bobby-review/SKILL.local.md` exists, read it and follow it. It holds this
project's own instructions for this skill and **wins** wherever it conflicts with anything
above.

`SKILL.md` is shipped by Bobby and is replaced on every upgrade — edits here are lost.
`SKILL.local.md` is yours and is never overwritten.

Files in this skill

  • SKILL.md9.7 KB
  • learnings.local.md10 KB
  • learnings.md7.1 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.