CLAUDE.md Design
Master system prompt engineering and project instructions design.
What You’ll Learn
If you could change only one thing about your Claude Code setup to get dramatically better results, it would be your CLAUDE.md file. This single file shapes every decision the AI makes in your project — from coding style to architecture choices to testing approach.
By the end, you’ll understand:
- Why CLAUDE.md is the highest-leverage file in your project
- The 3-tier hierarchy of instructions
- Design principles for effective project instructions
- Scoped rules with
paths:frontmatter - Common anti-patterns that waste tokens and confuse the AI
- How to structure CLAUDE.md for different project types
The Problem
When you bring a new developer onto a project, you spend hours onboarding them: explaining the tech stack, the conventions, the testing approach, where things live, what to avoid. Without this context, they write code that works but does not fit.
Claude Code faces the same problem. Without instructions, it will:
- Use its training defaults (which may not match your stack)
- Guess at conventions (tabs vs spaces, naming patterns, test frameworks)
- Make architecture decisions that conflict with your existing patterns
- Repeat the same mistakes session after session
You could re-explain everything in every conversation. Or you could write it down once.
How It Works
The 3-Tier Hierarchy
Claude Code loads instructions from three levels, each with a different scope:
┌──────────────────────────────────────────────┐
│ Instruction Hierarchy │
│ │
│ Tier 1: User CLAUDE.md (global) │
│ ┌───────────────────────────────────────┐ │
│ │ ~/.claude/CLAUDE.md │ │
│ │ │ │
│ │ Applies to ALL projects │ │
│ │ Personal preferences, global rules │ │
│ │ Example: "Always use TypeScript strict │ │
│ │ mode. Prefer functional patterns." │ │
│ └───────────────────────────────────────┘ │
│ │
│ Tier 2: Project CLAUDE.md (repo-level) │
│ ┌───────────────────────────────────────┐ │
│ │ <project-root>/CLAUDE.md │ │
│ │ │ │
│ │ Applies to THIS project │ │
│ │ Tech stack, architecture, conventions │ │
│ │ Checked into version control │ │
│ │ Shared with the whole team │ │
│ └───────────────────────────────────────┘ │
│ │
│ Tier 3: Scoped Rules (pattern-specific) │
│ ┌───────────────────────────────────────┐ │
│ │ .claude/rules/*.md │ │
│ │ │ │
│ │ Activated by file path patterns │ │
│ │ Fine-grained instructions │ │
│ │ Example: rules for tests only, │ │
│ │ rules for API routes only │ │
│ └───────────────────────────────────────┘ │
│ │
│ Loading order: │
│ User → Project → Rules (later overrides) │
│ │
└──────────────────────────────────────────────┘
When instructions conflict between tiers, the more specific tier wins. Project CLAUDE.md overrides user CLAUDE.md, and scoped rules override project CLAUDE.md for their matching files.
What Each Tier Should Contain
Tier 1: User CLAUDE.md (~/.claude/CLAUDE.md)
Your personal defaults that apply everywhere:
# Personal Preferences
- Use TypeScript strict mode in all projects
- Prefer functional programming patterns over class-based
- Write tests before implementation (TDD)
- Use conventional commits for commit messages
- Always run the linter before considering code complete
Keep this short. It applies to every project, so anything project-specific here will cause problems.
Tier 2: Project CLAUDE.md (<project-root>/CLAUDE.md)
The core project context. This is the most important tier:
# Project: E-Commerce API
## Tech Stack
- Runtime: Node.js 20 + TypeScript 5.4
- Framework: Express 4 with express-async-errors
- Database: PostgreSQL 16 via Prisma ORM
- Testing: Vitest + Supertest
- Auth: JWT with refresh tokens
## Dev Commands
- `pnpm dev` — start dev server (port 3000)
- `pnpm test` — run all tests
- `pnpm test:watch` — watch mode
- `pnpm lint` — ESLint + Prettier check
- `pnpm db:migrate` — run Prisma migrations
- `pnpm db:seed` — seed test data
## Architecture
- Routes: src/routes/<resource>.ts
- Services: src/services/<resource>.ts (business logic)
- Models: prisma/schema.prisma (single source of truth)
- Middleware: src/middleware/ (auth, validation, error)
- Tests: src/__tests__/<resource>.test.ts
## Conventions
- All route handlers delegate to services (no business logic in routes)
- Use Zod schemas for request validation
- Error responses follow RFC 7807 (Problem Details)
- Database queries only in services, never in routes
- Every public endpoint needs an integration test
Tier 3: Scoped Rules (.claude/rules/*.md)
Rules that activate only for specific file patterns:
---
paths:
- "src/__tests__/**"
- "**/*.test.ts"
---
# Testing Rules
- Use describe/it blocks (not test())
- Each test file tests one service or route
- Use factory functions for test data, not raw objects
- Always clean up database state in afterEach
- Mock external services, never the database
The paths: frontmatter uses glob patterns. The rule only loads when the AI is working on files that match those patterns:
┌─────────────────────────────────────────────────┐
│ Scoped Rule Activation │
│ │
│ Working on src/routes/auth.ts │
│ → Loads: api-routes.md rule │
│ → Skips: testing.md rule │
│ │
│ Working on src/__tests__/auth.test.ts │
│ → Loads: testing.md rule │
│ → Skips: api-routes.md rule │
│ │
│ Working on both files simultaneously │
│ → Loads: api-routes.md AND testing.md │
│ │
└─────────────────────────────────────────────────┘
Design Principles
1. Clarity Over Cleverness
Write instructions as if explaining to a competent developer on their first day. Be explicit about the non-obvious:
# Good: Explicit and actionable
- Error responses use RFC 7807 format: { type, title, status, detail }
- Database IDs are UUIDs, never auto-increment integers
- All timestamps are ISO 8601 in UTC, converted to local time only in the frontend
# Bad: Vague and unhelpful
- Use good error handling
- Follow best practices for IDs
- Handle time correctly
2. Permissions, Not Restrictions
Tell the AI what it CAN do. Listing everything it cannot do is infinite and wastes tokens:
# Good: Grant permissions clearly
- You can modify any file in src/ directly
- You can run `pnpm test` and `pnpm lint` without asking
- You can create new files in src/services/ and src/routes/
# Bad: Endless restrictions
- Do not modify package.json
- Do not change the database schema
- Do not edit the CI configuration
- Do not touch the deployment scripts
- ... (goes on forever)
3. Structure for Scanning
The AI processes your CLAUDE.md on every conversation turn. Make it scannable with headers, tables, and short bullets:
## API Conventions
| Pattern | Example | Notes |
|---------|---------|-------|
| Route files | `src/routes/users.ts` | One file per resource |
| Service files | `src/services/users.ts` | Business logic here |
| Test files | `src/__tests__/users.test.ts` | Mirrors service structure |
| Validators | `src/validators/users.ts` | Zod schemas |
## Key Decisions
- **ORM**: Prisma (not TypeORM) — chosen for type safety
- **Auth**: JWT with 15min access + 7day refresh tokens
- **Queue**: BullMQ for background jobs (Redis-backed)
4. Include the “Why”
When a convention has a non-obvious reason, explain it. The AI makes better decisions when it understands intent:
# We use UUIDs instead of auto-increment IDs because:
# 1. Prevents ID enumeration attacks
# 2. Allows offline ID generation (mobile clients)
# 3. Safe for multi-region database replication
Anti-Patterns
Wall of Text — Dumping your entire architecture doc into CLAUDE.md. The AI has to process all of it every turn. Keep it under 200 lines for the project CLAUDE.md and use scoped rules for the rest.
Contradictory Instructions — When Tier 1 says “use Jest” and Tier 2 says “use Vitest,” the AI gets confused. Audit your tiers for conflicts.
Over-Specification — Dictating every function signature and variable name. Let the AI use judgment within your conventions. Specify the patterns, not every instance.
Obvious Instructions — Writing things like “use proper indentation” or “handle errors.” The AI already does these things. Focus CLAUDE.md on what is specific to YOUR project.
Stale Instructions — Leaving instructions about a database migration from three months ago. Review and prune regularly, just like you would with documentation.
Key Insight
CLAUDE.md is system prompt engineering for your project. The system prompt that Anthropic writes controls the AI’s general behavior. Your CLAUDE.md controls its project-specific behavior. The better your CLAUDE.md, the less you need to repeat yourself in every conversation.
Think of it this way:
Without CLAUDE.md:
Session 1: "We use Vitest, not Jest. And Prisma, not TypeORM. And..."
Session 2: "Remember, we use Vitest, not Jest. And Prisma..."
Session 3: "I already told you, we use Vitest..."
With CLAUDE.md:
Session 1: "Add a password reset endpoint" → (it already knows the stack)
Session 2: "Add rate limiting to auth routes" → (it already knows the patterns)
Session 3: "Write tests for the new service" → (it already knows the test framework)
The 3-tier hierarchy is powerful because it separates concerns: your personal preferences do not pollute the shared project config, and file-specific rules do not bloat the global context.
The scoped rules in Tier 3 are particularly valuable for large projects. Instead of loading 500 lines of instructions for every conversation, the AI only loads the 30 lines relevant to the files it is currently working on.
Hands-On Example
A Complete CLAUDE.md for a Next.js + Prisma Project
# Project: SaaS Dashboard
## Tech Stack
- Framework: Next.js 14 (App Router)
- Language: TypeScript 5.4 (strict mode)
- Database: PostgreSQL 16 via Prisma
- Auth: NextAuth.js v5 with GitHub + Google providers
- Styling: Tailwind CSS + shadcn/ui components
- Testing: Vitest (unit) + Playwright (e2e)
## Commands
- `pnpm dev` — local server at localhost:3000
- `pnpm test` — run Vitest
- `pnpm test:e2e` — run Playwright
- `pnpm lint` — ESLint check
- `pnpm db:push` — push schema changes
- `pnpm db:studio` — open Prisma Studio
## Architecture
- `app/` — Next.js pages and layouts (App Router)
- `app/api/` — API routes (Route Handlers)
- `components/` — React components (shadcn/ui based)
- `lib/` — Shared utilities and configurations
- `lib/db.ts` — Prisma client singleton
- `prisma/schema.prisma` — database schema
## Conventions
- Server Components by default; add "use client" only when needed
- API routes return NextResponse.json() with appropriate status codes
- Use server actions for form mutations (not API routes)
- Prisma queries in lib/db/ modules, not directly in components
- Tailwind classes: use cn() helper for conditional classes
- Component files: PascalCase.tsx (e.g., UserProfile.tsx)
## Current Sprint
- Implementing team invitation flow
- Migrating from pages/ to app/ router (80% done)
A Scoped Rule for API Routes
Create .claude/rules/api-routes.md:
---
paths:
- "app/api/**"
---
# API Route Rules
- Always validate request body with Zod before processing
- Return standardized error format: { error: string, code: string }
- Use middleware pattern for auth: wrap handler with withAuth()
- Rate limit public endpoints with the rateLimit() wrapper
- Log all 5xx errors with structured logging (lib/logger.ts)
- Never expose internal error messages to clients
Checking Your CLAUDE.md Effectiveness
Ask yourself these questions:
1. Could a new developer read this and start contributing?
→ If no, add more context about architecture and conventions
2. Is anything here obvious or generic?
→ If yes, remove it (saves tokens every turn)
3. Are there project-specific gotchas not mentioned?
→ If yes, add them (e.g., "the legacy user table uses
'userid' not 'user_id' — Prisma maps this in schema")
4. Is it under 200 lines?
→ If no, move file-specific rules to .claude/rules/
5. Would any instruction conflict with your global CLAUDE.md?
→ If yes, resolve the conflict explicitly
What Changed
| Without CLAUDE.md | With 3-Tier CLAUDE.md |
|---|---|
| Re-explain conventions every session | Conventions loaded automatically |
| AI guesses at stack and patterns | AI knows exact stack and patterns |
| Instructions scattered across prompts | Single source of truth, version controlled |
| Same rules for all file types | Scoped rules activate per file pattern |
| New team members get different AI behavior | Shared CLAUDE.md ensures consistency |
Next Session
With sessions stored and project instructions defined, the final piece of Module 3 is trust. Session 18 covers Permission Models and Security — a deep dive into how Claude Code’s multi-layer security model works, from sandboxing to approval gates to organizational policies.