The Anatomy of a Bad Rule
Most developers write their first CLAUDE.md rules like this:
## Rules - Write clean code - Follow best practices - Be concise
These are useless. Claude already tries to write clean code. "Best practices" is undefined. "Be concise" is subjective. These rules consume tokens without changing Claude's behavior.
Specificity: The First Principle
Every rule should answer: what specifically should change about Claude's default behavior?
# Bad - Use TypeScript properly # Good - Enable TypeScript strict mode with noUncheckedIndexedAccess and exactOptionalPropertyTypes - Never use `any` — use `unknown` and narrow with type guards - Prefer interface over type for object shapes - Use `as const` for enum-like objects
Explain the Why
Rules with rationale are more effective than bare commands. Claude can apply a rule more consistently — and adapt it to novel situations — when it understands the intent.
## Error Handling
Always use typed error results instead of throwing:
```ts
// Preferred pattern — avoids untyped thrown errors
type Result<T> = { ok: true; value: T } | { ok: false; error: string }
```
Why: Our API routes need predictable error shapes for the frontend client.
Throwing errors produces inconsistent HTTP responses.Constraints Over Permissions
Claude makes sensible default choices. Your rules are most valuable when they constrain Claude away from valid-but-wrong choices for your project.
## Constraints - NEVER install new npm packages without asking first - NEVER modify prisma/schema.prisma without running `prisma db push` after - NEVER use relative imports — always use the @ alias - NEVER add console.log to production code (use the logger in lib/logger.ts)
Ordering Your Rules
Structure your CLAUDE.md from most-to-least important:
- Critical constraints — things that will break the build or cause security issues
- Tech stack — framework, libraries, versions
- Code style — naming, patterns, idioms
- File structure — where things live
- Commands — how to run and build the project
- Domain context — business logic rules
Code Examples as Rules
The most effective rules show Claude a pattern, not just a principle. Include short before/after examples for your most important conventions.
## API Route Pattern
Always use this structure for API routes:
```ts
export async function GET(req: NextRequest) {
try {
// ... implementation
return NextResponse.json(data)
} catch (error) {
console.error('[GET /api/route]', error)
return NextResponse.json({ error: 'Internal server error' }, { status: 500 })
}
}
```
Don't forget: validate input with Zod before processing.Keeping Rules Current
Stale rules cause confusion. When you upgrade a library, change an architectural pattern, or drop a tool, update CLAUDE.md immediately.
A monthly CLAUDE.md review is a healthy habit. Ask: does every rule still apply? Have we introduced new patterns that should be documented? Remove anything that's no longer true.