Examples: Bad vs Good CLAUDE.md

Learn what makes a CLAUDE.md effective by seeing real examples of bad vs good patterns.


Example 1: The Vague Project Description

❌ Bad

# My App

This is a cool web app I'm building. It does some stuff with users and data.

Problems:

  • No tech stack mentioned
  • "Cool" and "stuff" are useless descriptors
  • Claude has no idea what this actually does

✅ Good

# TaskFlow - Team Task Management

A SaaS task management tool for remote teams. Users create projects, assign tasks, and track progress in real-time.

## Tech Stack
- Backend: Node.js 20 + Express + PostgreSQL via Prisma
- Frontend: React 18 + TypeScript + TailwindCSS
- Real-time: WebSockets (Socket.io)
- Auth: JWT tokens via Supabase
- Deployment: Docker containers on AWS ECS

Why it's good:

  • Clear one-sentence description
  • Specific tech stack with versions
  • Claude knows exactly what kind of application this is

Example 2: The Wishful Thinking Rules

❌ Bad

## Code Style
- Write clean code
- Use good variable names
- Make it performant
- Follow best practices

Problems:

  • "Clean," "good," "best practices" are subjective
  • No actionable guidance
  • Claude can't verify compliance

✅ Good

## Code Style
- TypeScript strict mode — no `any` types, ever
- Variables: descriptive nouns (e.g., `userEmail` not `data`)
- Functions: start with verbs (e.g., `getUserById`, not `user`)
- Async/await only — never use `.then()` chains
- Imports: absolute paths with `@/` alias, never relative `../../`
- Max function length: 50 lines. If longer, extract functions.

Why it's good:

  • Specific, measurable rules
  • Examples provided
  • Claude can check compliance automatically

Example 3: The Missing Structure

❌ Bad

# My Project

Built with React and Node.js.

The code is in the src folder.

Problems:

  • Doesn't explain how src is organized
  • Claude will have to explore every time
  • No guidance on where to put new code

✅ Good

## Project Structure

/src /api - Express route handlers (thin, no business logic) /services - Business logic layer (all domain operations) /db - Database access via Prisma (all queries here) /lib - Shared utilities (logger, config, http client) /types - TypeScript type definitions /middleware - Express middleware (auth, error handling) /tests - Mirror structure of /src /prisma - Database schema and migrations


### Architecture Rules
- API routes call services, never access DB directly
- Services return `Result<T, AppError>` (never throw)
- All cross-service communication via event bus
- Database queries only in /db repositories

### Key Files
- Server entry: /src/server.ts
- Auth middleware: /src/middleware/auth.ts
- DB schema: /prisma/schema.prisma
- Environment config: /src/lib/config.ts

Why it's good:

  • Visual directory structure
  • Explains what goes in each directory
  • Architecture rules prevent common mistakes
  • Key files listed for easy reference

Example 4: The Ambiguous Commands

❌ Bad

## Commands

Run the app and do the tests.

Problems:

  • What's the actual command?
  • How to install dependencies?
  • How to run in dev vs production?

✅ Good

## Development Commands

```bash
# Install dependencies
bun install

# Start dev server (hot reload on port 3000)
bun run dev

# Run tests once
bun test

# Run tests in watch mode
bun test --watch

# Lint
bun run lint

# Type check
bun run typecheck

# Build for production
bun run build

# Database migrations
bunx prisma migrate dev        # Dev: create and apply
bunx prisma migrate deploy     # Prod: apply only

Workflow

  1. After making changes, run bun test before committing
  2. Never commit if tests fail
  3. Run bun run lint to auto-fix style issues

**Why it's good:**
- Exact commands copy-pasteable
- Explains what each does
- Includes workflow guidance

---

## Example 5: The Toothless Restrictions

### ❌ Bad

```markdown
## Rules

- Don't do bad things
- Try not to use console.log
- Avoid making mistakes

Problems:

  • "Try not to" isn't enforceable
  • "Bad things" is meaningless
  • No consequences specified

✅ Good

## Never Do This

- ❌ Never use `console.log` — use `logger.info()` from /src/lib/logger.ts
- ❌ Never commit .env files — use .env.example as template
- ❌ Never push directly to main — always create a PR
- ❌ Never use `any` in TypeScript — use `unknown` if type is truly unknown
- ❌ Never write raw SQL — use Prisma client methods
- ❌ Never use `var` — use `const` (preferred) or `let`
- ❌ Never add dependencies without checking bundle size impact

If I tell you to do any of these, push back and explain why it violates our rules.

Why it's good:

  • Absolute rules (Never, not "try to avoid")
  • Explains the alternative for each
  • Empowers Claude to push back

Example 6: The Missing Context

❌ Bad

# E-Commerce Site

We sell products online.

Problems:

  • No mention of scale, constraints, or special considerations
  • Claude doesn't know what's important
  • Missing domain-specific terminology

✅ Good

# ShopFast - Multi-Vendor E-Commerce Platform

An e-commerce marketplace where independent vendors list products. Platform handles payments, takes 15% commission, and manages vendor payouts.

## Scale & Constraints
- ~10k active vendors
- ~100k daily active users
- Payment processing via Stripe Connect
- Payout schedule: monthly, 1st of each month
- Must support multi-currency (USD, EUR, GBP)

## Domain Glossary
- **Vendor** = businesses selling on our platform (not just any user)
- **Commission** = our 15% fee on each sale
- **Payout** = monthly payment from platform to vendor
- **Settlement** = the batch processing of all payouts
- **Float** = money held between sale and payout

## Critical Constraints
- Financial: All money math uses integer cents (never floats)
- Security: Vendor data is isolated (RLS in PostgreSQL)
- Compliance: GDPR-compliant data exports within 30 days
- Performance: Product search must return under 200ms (indexed)

Why it's good:

  • Provides business context
  • Defines domain-specific terms
  • Lists scale and critical constraints
  • Prevents common mistakes (float math for money)

Example 7: The Git Disaster Waiting to Happen

❌ Bad

## Git

Use git for version control.

Problems:

  • No branching strategy
  • No commit conventions
  • No protection against dangerous operations

✅ Good

## Git Workflow

### Branch Naming
- Feature: `feat/short-description`
- Bug fix: `fix/short-description`
- Hotfix: `hotfix/critical-issue`

### Commit Messages
Use conventional commits:

feat(scope): add user export feature fix(auth): resolve token refresh race condition chore(deps): update dependencies docs(readme): add setup instructions


Keep first line under 72 characters.

### Protected Operations
- ✅ Always create a PR for main/develop
- ✅ Always run tests before committing
- ✅ Always pull before push
- ❌ Never `git push --force` to main/develop
- ❌ Never `git commit --no-verify` (bypasses hooks)
- ❌ Never merge main into feature branches (use rebase)

### Workflow
1. Create feature branch from develop
2. Make changes, commit frequently
3. Run full test suite
4. Create PR (requires 1 approval + passing CI)
5. After approval, squash merge to develop

Why it's good:

  • Clear branching strategy
  • Commit message format specified
  • Dangerous operations explicitly forbidden
  • Complete workflow documented

Example 8: The Testing Void

❌ Bad

## Testing

We have some tests. Run them sometimes.

Problems:

  • No guidance on what to test
  • No test structure
  • No coverage expectations

✅ Good

## Testing Standards

### Test Organization
- Unit tests: colocated with source (e.g., `user.service.test.ts` next to `user.service.ts`)
- Integration tests: `/tests/integration/`
- E2E tests: `/tests/e2e/`

### What to Test

**Unit tests:**
- All service methods
- Pure utility functions
- Complex business logic
- Edge cases and error handling

**Integration tests:**
- Database operations (use test DB)
- API endpoints (full request/response cycle)
- Auth flows

**E2E tests:**
- Critical user journeys (signup, purchase, payout)
- Cross-feature workflows

### Coverage Requirements
- Minimum: 80% overall coverage
- Critical paths: 100% (payment, auth, payout)
- New features: include tests in the same PR

### Test Patterns
```typescript
// Always use AAA pattern
describe('UserService', () => {
  it('should create user with valid data', async () => {
    // Arrange
    const userData = { email: 'test@test.com', ... }

    // Act
    const result = await userService.create(userData)

    // Assert
    expect(result.success).toBe(true)
  })
})

Running Tests

  • Before committing: bun test
  • Watch mode while developing: bun test --watch
  • CI must be green before merge

**Why it's good:**
- Defines what to test and where
- Sets coverage expectations
- Provides test pattern template
- Integrates testing into workflow

---

## Common Patterns to Avoid

### ❌ Platitudes
```markdown
Write high-quality code.
Be efficient.
Think about the user.

These mean nothing. Be specific.

❌ Contradictions

Use TypeScript strict mode.
It's okay to use `any` sometimes.

Pick one. Be consistent.

❌ Information Without Context

The webhook handler is at /api/webhooks/stripe.ts

Why is this important? When would Claude need this?

Better:

## Critical Files
- Stripe webhooks: /api/webhooks/stripe.ts
  - Handles: payment_intent.succeeded, subscription updates
  - Must respond within 30 seconds or Stripe retries
  - Updates DB and triggers notification emails

❌ Commands Without Explanation

Run: npm run special-build

What does this do? When should it be used?

Better:

Build Commands:
- `npm run build` - Standard production build
- `npm run build:debug` - Build with source maps (larger, for debugging prod issues)
- `npm run build:analyze` - Build + bundle analysis (use to check bundle size)

The Test: Would a New Team Member Understand?

A good CLAUDE.md should let a new developer (or Claude) understand your project without asking questions.

Read your CLAUDE.md and ask:

  • Could someone build a new feature with just this context?
  • Are the rules specific enough to be enforced?
  • Is the project structure clear?
  • Are commands copy-pasteable?
  • Are forbidden patterns explicit?

If not, keep refining.


Your Turn

Take your current CLAUDE.md and check it against these examples. Find at least 3 places where you're being vague, and make them specific.

Vague → Specific transformations to look for:

  • "Good naming" → "Variables are nouns, functions start with verbs"
  • "Use the logger" → "Never use console.log — use logger.info() from /lib/logger.ts"
  • "Files are in src" → Full directory tree with explanations
  • "Run tests" → Exact command with flags and when to use it
  • "Don't break things" → Explicit list of forbidden operations

Your CLAUDE.md should be your project's source of truth. Make it count.