Home Benchmarks Learn Tools News
SPONSOR

AppSignal — Stop vibe-debugging. Every exception, every backtrace, grouped so you see patterns, not noise.

↗
Skills / Review / Pre-Deploy
Review skill · v2 · 26-point audit

Turn vibe code into ship code.

Runs inside your agent. Audits 26 things AI gets wrong by default.

Install the skill ↓ Read the source →
26
Audit checks
6
IDE integrations
A–F
Output grade
cursor — agent — review-pre-deploy v2
$ agent run --skill review-pre-deploy
▼ pre-deploy review starting · 26 checks · target: src/checkout/
[01] error handling ok
[02] debug artifacts fail
! console.log left in PricingCard.tsx:42
[03] hallucinated apis fail
! @invented/use-toast is not a real npm package
[04] hardcoded values ok
[05] loading states warn
[06] accessibility ok
score 76 / 100 C
→ fix 2 errors before shipping. autopatch? [Y/n]
Works with
  • Cursor
  • Claude Code
  • Codex CLI
  • Windsurf
  • GitHub Copilot
  • Gemini CLI
What it catches

The bugs your agent leaves behind.

review-pre-deploy / checks SKILL.md · 26 checks · ship-ready
checks/
error-handling.diff •
−users.ts Before
// no error path, no status check
const data = await fetch('/api/users')
.then(r => r.json());
+users.ts After
try {
const res = await fetch('/api/users');
if (!res.ok) throw new Error(res.status);
return res.json();
} catch (e) {
reportError(e);
showErrorState(e);
}
− happy path only · silent 4xx/5xx · bad UX → + handled · observable · recoverable
hallucinations.diff •
−imports.ts Before
// not on npm — never was
import { useToast } from '@invented/use-toast';
import { useFetch } from 'react-suspense-fetch';
+imports.ts After
// real, audited, currently maintained
import { toast } from 'sonner';
import useSWR from 'swr';
− invented packages · build fails on install → + verified on npm · maintained · ships
hygiene.diff •
−card.css Before
.card {
padding: 24px;
color: #3D5A80;
border-radius: 12px;
}
 
console.log('debug:', user);
fetch('http://localhost:3000/api');
+card.css After
.card {
padding: var(--space-xl);
color: var(--color-accent);
border-radius: var(--radius-card);
}
 
// console.log removed
fetch(env.API_URL + '/api');
− magic numbers · hex literals · localhost in prod → + tokenized · clean · env-driven
smells.diff •
−page.tsx Before
<div onclick="submit()">Submit</div>
<img src="/hero.jpg">
<a href="/pricing">click here</a>
 
// exposed key in source
const API = 'sk-proj-9f2k...';
+page.tsx After
<button type="submit">Submit</button>
<img src="/hero.jpg" alt="Pricing hero">
<a href="/pricing">View pricing plans</a>
 
// keys live in env
const API = env.OPENAI_KEY;
− div onclick · missing alt · "click here" · key leaked → + semantic · labeled · descriptive · secure
Benchmarked

Proof, not vibes.

Pricing Section brief · Claude Opus 4.7 · with skill vs. without · 2026-04-21
100
Best Practices 82 → 100 baseline +18
96
Accessibility 88 → 96 baseline +8
12
Issues caught Avg flagged per run
92
With-skill grade · A vs C · 76 baseline +16
0–49 50–89 90–100
Single-run comparison. Same model and prompt, scored on Lighthouse + an internal rubric.
Install

Drop it into your IDE.

One Markdown file, zero dependencies. Pick your tool below.

1Drop the skill at this path
.cursor/skills/review-pre-deploy.md
2Or copy & paste this command
curl -fsSL https://webdeveloper.com/skills/review-pre-deploy/SKILL.md -o .cursor/skills/review-pre-deploy.md
Cursor auto-loads skills from .cursor/skills/. Open the chat and ask the agent to "run the pre-deploy review."
1Drop the skill at this path
~/.claude/skills/review-pre-deploy/SKILL.md
2Or copy & paste this command
mkdir -p ~/.claude/skills/review-pre-deploy && curl -fsSL https://webdeveloper.com/skills/review-pre-deploy/SKILL.md -o ~/.claude/skills/review-pre-deploy/SKILL.md
Claude Code discovers skills under ~/.claude/skills/. Restart the session to pick up the new file.
1Drop the skill at this path
AGENTS.md (project root) — append the skill content as a section
2Or copy & paste this command
curl -fsSL https://webdeveloper.com/skills/review-pre-deploy/SKILL.md >> AGENTS.md
Codex CLI reads instructions from AGENTS.md in the project root. Ask the agent to "review before deploy" on its next turn.
1Drop the skill at this path
.windsurf/rules/review-pre-deploy.md
2Or copy & paste this command
mkdir -p .windsurf/rules && curl -fsSL https://webdeveloper.com/skills/review-pre-deploy/SKILL.md -o .windsurf/rules/review-pre-deploy.md
Windsurf loads project rules from .windsurf/rules/. Reload the workspace and the rule will be active.
1Drop the skill at this path
.github/copilot-instructions.md
2Or copy & paste this command
mkdir -p .github && curl -fsSL https://webdeveloper.com/skills/review-pre-deploy/SKILL.md >> .github/copilot-instructions.md
Copilot reads custom instructions from .github/copilot-instructions.md. The next chat in the workspace will respect the skill.
1Drop the skill at this path
.gemini/skills/review-pre-deploy.md
2Or copy & paste this command
mkdir -p .gemini/skills && curl -fsSL https://webdeveloper.com/skills/review-pre-deploy/SKILL.md -o .gemini/skills/review-pre-deploy.md
Gemini CLI reads project skills from .gemini/skills/. Run gemini skills reload to pick up the new file.

The full SKILL.md

594 lines · plain Markdown · MIT-licensed
SKILL.md
---
name: review-pre-deploy
description: >-
  Run a structured pre-deploy review on AI-generated front-end code before it
  ships. Use after completing a feature, page, or component — before commit,
  merge, or deploy — to catch the errors that AI coding tools introduce most
  often.
---

# Pre-Deploy Review

AI coding tools write functional code fast, but "it works on my machine" is
not ship-ready. This skill is the final gate between generated code and
production. Run it after the feature is "done" — it catches the
AI-generated code that needs debugging before users see it.

This is a review skill, not a writing skill. It doesn't tell the agent how to
build — the `frontend-*` skills handle that. It tells the agent how to *audit*
what it already built.

## How to Use This Skill

After completing any feature, component, or page, run a pre-deploy review by
checking every section below in order. Fix issues before committing.

## Error Handling

### Every async operation must handle failure

AI-generated code almost always shows the happy path. Check every `fetch`,
`await`, `Promise`, and event handler for error handling:

```javascript
// AI typically generates this
const data = await fetch('/api/users').then(r => r.json());

// Ship this instead
try {
  const response = await fetch('/api/users');
  if (!response.ok) {
    throw new Error(`${response.status} ${response.statusText}`);
  }
  const data = await response.json();
} catch (error) {
  showErrorState(error);
}
```

Check for:

- `fetch` calls without `.catch()` or `try/catch`
- `async` functions that never handle rejection
- Event listeners that assume success
- JSON parsing without error handling
- Missing timeout handling for network requests

### Every user-facing state needs an error state

If a component has a loading state, it also needs an error state. If it fetches
data, it needs an empty state. Check every component:

| State | What the user sees | Often missing? |
|-------|-------------------|----------------|
| Loading | Skeleton or spinner | Rarely |
| Success | The content | Never |
| Error | Message + retry action | **Almost always** |
| Empty | "No items yet" message | **Often** |
| Offline | Cached content or message | **Almost always** |

## Debug Artifacts

### Remove all debug code before deploy

AI tools leave debug artifacts in code constantly. Search for and remove:

```javascript
// Every one of these must be removed
console.log()
console.warn()
console.error()   // unless it's intentional error logging
console.debug()
console.table()
debugger
alert()
```

Also check for:

- `TODO` and `FIXME` comments that indicate incomplete work
- Commented-out code blocks (either delete or restore)
- Hardcoded test data (`[email protected]`, `12345`, `lorem ipsum`)
- Placeholder text that was never replaced
- `localhost` URLs or hardcoded ports
- Test IDs or mock data left in production markup

## Hallucinated APIs and Dependencies

AI tools regularly invent things that do not exist: npm packages, CDN URLs,
HTTP headers, MDN paths, Tailwind classes, framework hooks. Verify every
external reference before shipping.

### Check every imported package

For every `import` statement in the diff, verify the package exists on npm
and the version is current. Common AI fabrications:

- Plausibly-named npm packages that were never published
- Real packages with hallucinated subpath imports
- Packages that were renamed or deprecated years ago
- Hooks or utilities that don't exist in the package's actual API
- Tailwind classes that look right but aren't in the codebase's config

If a package was added in this diff, run `npm view <name>` or open the
package's npm page before merging. If a hook is imported, verify it's in the
library's actual exports.

### Check every external URL

Hardcoded URLs in the diff — CDN scripts, image sources, fetch endpoints —
must resolve to a real, reachable resource:

- CDN script tags that point at dead or moved hosts
- Image `src` values for stock images that no longer exist
- API endpoints with the wrong base URL or path
- Documentation links to MDN or framework sites that 404

Prefer vendoring assets locally (under `assets/`) over loading from third-party
CDNs the AI may have made up.

## Hardcoded Values

### Extract magic numbers and strings

AI-generated code is full of hardcoded values that should be variables,
constants, or configuration:

```css
/* AI generates this */
.card { max-width: 384px; padding: 24px; border-radius: 12px; }

/* Should use design tokens */
.card {
  max-width: var(--size-card-max);
  padding: var(--space-lg);
  border-radius: var(--radius-lg);
}
```

Check for:

- Pixel values that should be design tokens (spacing, sizing, radii)
- Color hex/rgb values that should be token references
- Breakpoint values that should use the project's breakpoint scale
- API URLs that should come from environment config
- Timeout durations that should be named constants
- z-index values that should use a z-index scale

## CSS Quality

### No `!important` in component styles

AI tools add `!important` to override specificity conflicts instead of
fixing the selector. Every `!important` in component CSS is a code smell —
it cascades into maintenance debt. Fix the root cause: restructure the
selector to win by specificity or source order.

### Use design tokens for all colors

If the code has more than a few hardcoded hex, rgb, or rgba values, they
should be CSS custom properties. AI generates unique color values per
component instead of pulling from a shared palette.

### Use logical properties

AI defaults to physical CSS properties (`margin-left`, `padding-right`,
`width`). Use logical equivalents (`margin-inline-start`,
`padding-inline-end`, `inline-size`) for automatic RTL/LTR support.

### Animations need a reduced-motion query

Every `animation` or `transition` in CSS must be wrapped in
`@media (prefers-reduced-motion: no-preference)` or disabled in a
`prefers-reduced-motion: reduce` query. AI never adds this.

## Responsive Design

### Test every breakpoint, not just desktop

AI tools build for the viewport they're prompted about — usually desktop.
Check every new component at these widths:

| Width | What to check |
|-------|--------------|
| 320px | Nothing overflows, text is readable, touch targets are 44x44px minimum |
| 375px | iPhone SE — most common small phone |
| 768px | Tablet — layout transitions work |
| 1024px | Small laptop — sidebar/content ratios hold |
| 1440px | Desktop — max-width containers prevent ultra-wide stretching |

Common AI failures at small viewports:

- Horizontal overflow from fixed-width elements
- Text that's too small to read (below 16px on mobile)
- Touch targets smaller than 44x44px
- Images without `max-width: 100%`
- Flex containers that don't wrap (`flex-wrap: wrap` missing)
- Absolute positioning that breaks on narrow screens
- Modals and dropdowns that extend past the viewport

### Check `overflow` behavior

```css
/* AI often generates containers that overflow on mobile */
.container {
  overflow-x: hidden; /* Masks the problem */
}

/* Fix the actual cause instead */
.container {
  max-inline-size: 100%;
}
```

## Forms and Validation

### Every form input needs validation

AI-generated forms almost never have complete validation. Check:

- Required fields have `required` attribute AND client-side messaging
- Email fields validate format before submit
- Password fields show requirements and validate against them
- Number inputs have `min`, `max`, and `step` where appropriate
- File inputs validate type and size before upload
- Submit button disables during submission to prevent double-submit
- Form shows inline errors next to the field, not just at the top

### Test form edge cases

- Submit with all fields empty
- Submit with only whitespace in text fields
- Paste content longer than expected
- Use browser autofill — does it work?
- Submit, get error, fix, resubmit — does the error clear?

## Loading and Interaction States

### Every interactive element needs visual feedback

| Element | States to check |
|---------|----------------|
| Buttons | Default, hover, focus, active, disabled, loading |
| Links | Default, hover, focus, visited |
| Inputs | Default, focus, filled, error, disabled |
| Cards | Default, hover (if clickable) |
| Toggles | On, off, disabled |

AI-generated code typically handles 2-3 of these. Production code needs all
of them.

### Buttons must prevent double-click

```html
<button type="submit" aria-busy="false">
  Submit
</button>
```

On submit: set `aria-busy="true"`, disable the button, show a spinner. On
complete or error: restore the button. AI almost never generates this pattern.

## Images and Media

### Every image needs dimensions and alt text

Check every `<img>` element:

- `width` and `height` attributes set (prevents CLS)
- `alt` text is descriptive (content images) or empty (decorative)
- `loading="lazy"` on below-fold images
- `decoding="async"` on all images
- Images are not larger than needed (check actual display size vs file size)

### Check for missing responsive images

If an image displays at different sizes across breakpoints, it needs `srcset`
and `sizes`. A 1200px hero image served to a 320px phone is a performance
bug.

## Cross-Browser Basics

### Check feature support for new APIs

AI tools use the latest APIs without checking browser support. Audit for:

- CSS features that need fallbacks (container queries, `:has()`, `oklch`)
- JavaScript APIs that need polyfills or detection (`structuredClone`,
  `navigation`, `scheduler.yield`)
- HTML elements that behave differently across browsers (`<dialog>`,
  `popover`)

The rule: if the project's browser matrix includes Safari 16 or Firefox ESR,
verify every modern API against caniuse.com before shipping.

## Environment and Configuration

### No secrets or environment-specific values in source

Check the entire diff for:

- API keys, tokens, or passwords in source code
- `.env` values committed to the repository
- Development-only URLs that should be environment variables
- Debug flags that should be off in production
- Feature flags hardcoded as `true` instead of using a config system

## Security Smells

A static smell test on the diff. None of these are full security audits — they
catch the patterns AI tools regurgitate that never belong in production.

### Dangerous DOM injection

- `dangerouslySetInnerHTML` with any value the user could influence
- Direct `element.innerHTML = userInput` writes
- Template literals interpolating user input into HTML strings
- `document.write` calls anywhere in the diff
- `eval`, `new Function(...)`, or `setTimeout(string)` form

If any of these are used, the input must be either a literal known-safe
constant or sanitized through a vetted library before assignment.

### Exposed secrets

Regex sweep the diff for any of:

- `sk-` (OpenAI), `xoxb-` (Slack), `ghp_` / `gho_` (GitHub)
- `AKIA...` (AWS), `AIza...` (Google), `key-` followed by 30+ chars
- Anything literal that looks like a JWT (`eyJ...`)
- `.env` values committed verbatim

Move every match to environment variables before commit.

### Unsafe defaults

- `target="_blank"` links missing `rel="noopener noreferrer"`
- `fetch(...)` posts without CSRF tokens on state-changing endpoints
- Auth tokens stored in `localStorage` instead of httpOnly cookies
- Missing or wildcard `Content-Security-Policy`
- CORS configured with `Access-Control-Allow-Origin: *`

## HTML Semantics

### Use semantic elements, not div soup

AI wraps everything in `<div>`. If there are more than a few `<div>`
elements and zero `<main>`, `<nav>`, `<article>`, `<section>`, or `<aside>`
elements, the markup needs restructuring. Screen readers and search engines
rely on landmark elements.

### Use `<button>`, not `<div onclick>`

Every `<div onclick>`, `<span onclick>`, or `<div role="button">` is a bug.
Native `<button>` elements provide keyboard support, focus management, and
screen reader semantics for free. Replace them.

### No vague link text

Link text like "click here", "read more", "learn more", "here", or "link"
is meaningless out of context. Screen reader users navigate by link list.
Link text should describe the destination: "View pricing plans" not "click
here."

### Set the `lang` attribute on `<html>`

AI often generates `<html>` without `lang="en"` (or the correct language).
Screen readers use this to select the correct pronunciation engine.

## Accessibility Quick Check

### Run the 5-point check from the accessibility skill

Even if the `frontend-accessibility` skill was active during development,
verify:

1. **Tab through the page** — can you reach everything? Is focus visible?
2. **Check heading hierarchy** — h1, then h2, then h3, no skipped levels
3. **Check all images** — every `<img>` has `alt`
4. **Check all forms** — every input has a `<label>`
5. **Check color contrast** — 4.5:1 for text, 3:1 for UI elements

## Performance Quick Check

### Verify required meta tags are present

Every HTML page needs:

- `<meta charset="UTF-8">` as the first element in `<head>`
- `<meta name="viewport" content="width=device-width, initial-scale=1.0">`

AI-generated pages frequently omit one or both of these. Missing charset
causes encoding bugs. Missing viewport breaks mobile rendering.

### Verify the LCP element loads fast

- The largest above-fold element should not have `loading="lazy"`
- If *all* images on the page have `loading="lazy"`, the LCP image is
  being delayed — remove `lazy` from the hero or main visual
- Critical CSS should not be behind a render-blocking stylesheet
- No synchronous `<script>` tags in `<head>` without `defer` or `async`
- Third-party scripts should not block the main thread

## The Pre-Deploy Checklist

Run this checklist on every feature before committing:

- [ ] All `fetch`/`async` operations have error handling
- [ ] Every component has loading, error, and empty states
- [ ] No `console.log`, `debugger`, or `alert()` in production code
- [ ] No hardcoded test data, placeholder text, or localhost URLs
- [ ] Every imported npm package exists; every CDN URL resolves
- [ ] All magic numbers extracted to tokens or constants
- [ ] No `!important` in component CSS
- [ ] No hardcoded color values — all colors use design tokens
- [ ] Animations wrapped in `prefers-reduced-motion` query
- [ ] Tested at 320px, 375px, 768px, 1024px, and 1440px
- [ ] No horizontal overflow at any viewport
- [ ] All form inputs have validation and error messages
- [ ] All buttons have hover, focus, active, disabled, and loading states
- [ ] All images have width, height, alt, and appropriate loading strategy
- [ ] LCP image does NOT have `loading="lazy"`
- [ ] No render-blocking `<script>` in `<head>` without `defer`/`async`
- [ ] `<html>` has a `lang` attribute
- [ ] `<meta charset>` and `<meta viewport>` are present
- [ ] No API keys, secrets, or env-specific values in source
- [ ] No `dangerouslySetInnerHTML` / `innerHTML` writes from user input
- [ ] Heading hierarchy is correct (h1 → h2 → h3, no skips)
- [ ] No `<div onclick>` or `<span role="button">` — use `<button>`
- [ ] No vague link text ("click here", "read more", "learn more")
- [ ] Semantic elements used (`<main>`, `<nav>`, `<article>`) not just `<div>`
- [ ] Every interactive element is keyboard-accessible
- [ ] No new browser APIs used without checking caniuse.com

A feature is not done until every box is checked.

## Score Your Output

After running the checklist, score the code to decide if it's ship-ready.
Start at 100 and deduct points for each finding:

| Severity | Deduction | Examples |
|----------|-----------|----------|
| Error | -8 points | Missing error handling, `console.log` in production, `innerHTML` with user content, exposed secrets, hallucinated package, missing viewport meta |
| Warning | -3 points | Missing `alt` text, no `prefers-reduced-motion`, `!important` in CSS, vague link text, hardcoded colors |
| Info | -1 point | Physical CSS properties instead of logical, could use semantic elements |

### Grade scale

| Score | Grade | Ship? |
|-------|-------|-------|
| 90–100 | A | Ship it |
| 80–89 | B | Ship it, but fix warnings soon |
| 70–79 | C | Fix errors before shipping |
| 60–69 | D | Significant rework needed |
| 0–59 | F | Do not ship — critical issues |

Report the grade, score, and a summary of findings before marking the task
complete. Example output:

```
Pre-deploy score: 84/100 (B)
- 1 error: fetch() without error handling in UserProfile
- 3 warnings: missing alt text (2), !important in card.css (1)
- 1 info: physical CSS properties in layout.css

Fix the error before shipping. Warnings should be addressed in the next PR.
```

The goal is not a perfect 100 on every commit — it's to never ship an F.

## Anti-Patterns

**Never do these:**

- Ship code with `console.log` — it leaks internal state to anyone with
  DevTools open
- Use `overflow: hidden` to mask layout bugs — fix the actual cause
- Skip the error state because "the API is reliable" — it's not
- Use `placeholder` as the only form label — it disappears on input
- Hardcode API URLs — they will change between environments
- Assume desktop-first is fine — over 50% of web traffic is mobile
- Skip the loading state — perceived performance matters
- Leave TODO comments in production — they indicate incomplete work
- Commit commented-out code — use version control for history
- Trust that AI-generated code handles edge cases — it doesn't
- Trust that an imported package exists — verify it on npm
Pair it

Stack it with the rest of the suite.

Review08 Security Review

XSS prevention, input sanitization, secret exposure, CSP, CORS, auth token storage, CSRF.

↗
Review09 Testing Review

Behavior-first tests, error and edge-case coverage, accessibility contract tests, mock guidelines.

↗
Front-end06 Accessibility

WCAG 2.2 AA, keyboard nav, focus management, contrast, screen reader patterns, form accessibility.

↗

Changelog

V3 May 8, 2026
Added hallucinated API detection (invented packages, dead CDNs, fabricated framework hooks) and security smells (XSS sinks, exposed keys, unsafe defaults). Expanded checklist from 24 to 26 items.
V2 April 15, 2026
Added scoring system (A–F grade), CSS quality checks (!important, design tokens, logical properties, reduced-motion), HTML semantics (semantic elements, button usage, link text, lang attribute), meta tag verification (charset, viewport), and expanded the checklist from 14 to 24 items.
V1 April 15, 2026
Initial skill covering error handling audit, debug artifact removal, hardcoded value extraction, responsive design checks, form validation, loading/interaction states, image optimization, cross-browser compatibility, and the pre-deploy checklist.

FAQ

What does this skill check before deploy?

A 26-item review covering error handling, debug artifacts, hallucinated APIs and packages, hardcoded values, CSS quality (!important, design tokens, reduced-motion), HTML semantics, responsive design across five breakpoints, form validation, interaction states, image optimization, meta tags, and accessibility. The agent then scores the code A–F so you know if it’s ship-ready.

Why does AI-generated code need a pre-deploy review?

AI coding tools write functional code fast, but they consistently ship happy-path-only logic, leave debug artifacts, hardcode values instead of using design tokens, hallucinate APIs and npm packages, and skip error/loading/empty states. This skill catches those issues inside the agent’s own review loop, before they reach users.

How is this different from the frontend-* writing skills?

The frontend-* skills teach the agent how to write code correctly. This review skill teaches the agent how to audit code it already wrote — catching missing error handling, debug artifacts, hallucinated dependencies, responsive issues, and incomplete states that writing skills alone can’t prevent.

Which AI coding tools is this compatible with?

Cursor, Claude Code, Codex CLI, Windsurf, GitHub Copilot, and Gemini CLI. The skill is a single Markdown file and ships in the native format for each tool with one-click copy.

STATUS ● BUILDING THE FUTURE
MISSION MAKE AI SHIP BETTER CODE
VERSION BETA 3.0

MAKE AI SHIP BETTER CODE.

@WEBDEVELOPERHQ ↗
TERMS / PRIVACY
FRIENDS
Authentic Jobs ↗
Web Reference ↗
Ready.dev ↗
Fullres ↗
© 2026 WEB DEVELOPER / ALL RIGHTS RESERVED