Software Engineer at Supabase
March 19, 2026
Here's my personal, opinionated code-review skill for code agents. You can ask your agent to install it.
---
name: code-review
description: Run a structured code review on the current branch's changes. Use when asked to "review my code", "review my changes", "check my PR", "run a code review", or "review this branch". Covers formatting, type safety, duplication, readability, test coverage, and comment quality. Always use this skill when the user wants a code review — don't just eyeball it.
---
# Studio Code Review
Perform a thorough code review on the changed files in the current branch. Work through each check below in order, fixing issues as you find them rather than just reporting them.
## Review Checklist
### 1. Prettier + TypeScript
Run formatting and type checks on the changed files only.
```bash
# From the repo root
npx prettier --check <changed files>
npx tsc --noEmit
```
Fix any prettier violations. Report any TypeScript errors — if they're in code you touched, fix them.
### 2. No Type Assertions
Search for type assertions (`as any`, `as SomeType`, `!` non-null assertions) in the changed files. These are a red flag — they silence the type system instead of satisfying it.
When you find one, ask: *why does this assertion exist?* The right fix is usually one of:
- Validate the value at runtime (zod works well for external data) and let TypeScript infer the narrowed type
- Fix the upstream type so the assertion isn't needed
- Use a proper type guard
Avoid mechanical "add zod everywhere" — use the approach that best fits the context.
### 3. Duplicate Code and Types
Look across the diff for:
- Repeated logic that could be shared (a function, a hook, a util)
- Types defined more than once for the same shape
- Copy-pasted blocks with minor variations
Consolidate where it makes sense. Don't over-abstract — three similar lines are fine; a pattern repeated four or more times probably warrants a shared helper.
### 4. Readable Conditions
Complex boolean expressions are hard to reason about. When you see an `if` statement (or ternary) with multiple conditions joined by `&&` / `||`, especially with negations, extract it to a named constant that explains the intent:
```ts
// Hard to scan
if (!isLoading && user !== null && user.role !== 'guest') { ... }
// Clear intent
const canAccessDashboard = !isLoading && user !== null && user.role !== 'guest'
if (canAccessDashboard) { ... }
```
Apply this when the expression has 3+ conditions, involves negation, or when the intent isn't immediately obvious from the raw conditions alone. Simple two-part conditions are usually fine as-is.
### 5. Test Coverage with Vitest
For each changed file, ask: *is there logic here that could fail silently?* If yes, write a test.
Good candidates:
- Utility functions with branching logic
- Data transformations or formatters
- Custom hooks with non-trivial state
- Validation logic
Tests live next to the file they test:
```
my-module.tsx ← source
my-module.test.tsx ← tests (same directory)
```
Don't write tests for things that are trivially correct or are better covered by E2E tests. Focus on logic that's easy to get wrong and cheap to verify.
### 6. Logic Out of React Components
React components should describe UI, not implement business logic. If a component contains complex data transformations, multi-step calculations, or branching logic, move that logic to a utility function outside the component.
This makes the logic:
- Testable in isolation (no render needed)
- Reusable by other components
- Easier to read in both places
```tsx
// Before: logic buried in component
function UserCard({ user }) {
const label = user.subscriptions.filter(s => !s.expired).length > 1
? `${user.subscriptions.filter(s => !s.expired).length} active plans`
: 'Free tier'
return <div>{label}</div>
}
// After: logic extracted and testable
function getSubscriptionLabel(subscriptions: Subscription[]): string {
const active = subscriptions.filter(s => !s.expired)
return active.length > 1 ? `${active.length} active plans` : 'Free tier'
}
function UserCard({ user }) {
return <div>{getSubscriptionLabel(user.subscriptions)}</div>
}
```
### 7. Comment Quality
Remove comments that just restate what the next line does — they add noise and go stale:
```ts
// Bad: says what, not why
// Increment counter
count++
// Increment retry count before re-entering the queue
// to prevent infinite retries when the handler always throws
count++
```
Keep comments that explain *why* something non-obvious is done that way. Delete the rest. If you're unsure whether a comment adds value, it probably doesn't.
---
## Output Format
After completing all checks, give a brief summary:
- What you fixed (with file references)
- Any issues you found but couldn't fix, and why
- Anything the author should know or decide
Keep it concise. The user can see the diff.