Browse 158 rules, 25 knowledge articles, and 25 prompt templates across security, performance, architecture, and quality.
158 rules
Never commit API keys, passwords, tokens, or credentials to version control. Once a secret is in git history, it is permanently exposed — even deleting the file doesn't remove it from history, and anyone who cloned the repo has a copy forever.
Each commit should contain exactly one logical change. Commits that mix refactoring, bug fixes, and features together make git bisect useless, code review painful, and reverting a single change impossible without losing everything else in the commit.
Write commit messages that explain WHY a change was made, not just WHAT changed. "fix bug" tells future-you nothing — "fix: prevent duplicate form submission on slow connections" tells you the context, the cause, and the scope without reading any code.
Minimize use of arbitrary values like [w-347px], [color:#1a2b3c]. Arbitrary values bypass Tailwind's design tokens, making the design system meaningless and creating one-off values that are impossible to maintain consistently.
Use Tailwind's responsive prefixes (sm:, md:, lg:) and theme tokens instead of arbitrary pixel values. Arbitrary values ([w-347px]) bypass the design system, creating inconsistent spacing/sizing that doesn't adapt to different screen sizes.
When the same combination of Tailwind utilities appears in 3+ places, extract it to a component or @apply directive. Duplicated utility strings mean a design change (like spacing or color) requires finding and updating every copy — miss one and you have an inconsistent UI.
Text must meet WCAG AA contrast ratio: 4.5:1 for normal text, 3:1 for large text. Low-contrast text is unreadable for users with low vision, color blindness, or anyone using a screen in bright sunlight — affecting up to 8% of male users (color blindness alone).
Every interactive element must be operable via keyboard alone (Tab, Enter, Space, Escape). Users with motor disabilities, RSI, or broken trackpads cannot use a mouse — if your app requires mouse interaction, those users are completely locked out.
Every <img> must have a meaningful alt attribute. Without alt text, screen readers either skip the image entirely or read the raw filename ("DSC_0042.jpg"), leaving visually impaired users completely unable to understand the content.
Use semantic HTML elements (<nav>, <main>, <article>, <button>) instead of generic <div> and <span> with click handlers. Screen readers and assistive technology rely on semantic elements to understand page structure — a <div onClick> looks like nothing to a blind user.
Apply rate limiting to all public-facing API endpoints. Without rate limits, a single attacker can overwhelm your server, exhaust your database connections, or brute-force authentication — taking down the service for all users.
Return semantically correct HTTP status codes (400 for bad input, 401 for unauthenticated, 403 for unauthorized, 404 for missing, 500 for server errors). Using 200 for everything hides errors from monitoring, breaks caching, and makes debugging impossible.
Validate and sanitize all request input (body, query params, headers) before processing. Unvalidated input is the root cause of injection attacks, data corruption, and crashes from malformed data.
Avoid `as Type` assertions — they tell TypeScript "trust me" and skip validation. If the runtime value doesn't match, your code crashes with no type error to warn you.
Model mutually exclusive states with discriminated unions, not optional fields. Optional fields allow impossible states (e.g., `status: 'success'` with `error: 'failed'`) that compile but crash at runtime.
Use `unknown` instead of `any` for values with uncertain types. Unlike `any`, `unknown` forces you to narrow the type before using it, keeping type safety intact.
Enable all strict flags in tsconfig.json (strict: true). Without strict mode, TypeScript allows null access, implicit any, and unchecked function calls that will crash at runtime.
Never use `any` as a type annotation. `any` disables all type checking for that value and everything it touches, spreading through your codebase like a virus — one `any` can silently disable type safety across dozens of files.
Extract event handlers defined inline in JSX to named functions or useCallback. Inline functions create new references every render, breaking React.memo and causing unnecessary child re-renders.
Wrap expensive calculations in useMemo and expensive component creation in React.memo. Without memoization, expensive work runs on every render even when inputs haven't changed, causing UI jank and dropped frames.
Version your API from day one (URL prefix, header, or query param). Without versioning, any breaking change forces all clients to update simultaneously or breaks them without warning.
Add database indexes for columns used in WHERE, JOIN, and ORDER BY clauses. Without indexes, the database scans every row in the table for every query — a table with 1M rows takes seconds instead of milliseconds.
Never use SELECT * in production code. SELECT * fetches every column including large text/blob fields you don't need, wastes bandwidth, breaks when columns are added, and prevents the database from using covering indexes.
Always use parameterized queries or prepared statements, never string concatenation. String-interpolated SQL is the #1 cause of SQL injection — an attacker can modify your query to read, modify, or delete your entire database.
BeforeMerge scans your pull requests against these rules automatically. Get actionable feedback before code ships to production.