From Ad Hoc Prompts to Project-Level Intelligence
Mental Model
A well-configured Claude Code project is like onboarding a brilliant senior engineer who already knows your architecture, conventions, and non-negotiables before writing their first line of code.
Every time you start a Claude Code session without proper configuration, you are re-explaining your project from scratch. After a week, you have wasted hours on context that could have been encoded once and reused forever.
This lesson covers the three-layer configuration system that transforms Claude Code from a capable tool into a project-aware engineering partner.
Layer 1: CLAUDE.md — The Project Constitution
CLAUDE.md (or .claude/CLAUDE.md) is the most powerful configuration file in the Claude Code ecosystem. Claude reads it automatically at the start of every session in that directory.
What belongs in CLAUDE.md:
# CLAUDE.md — Project Rules
## Architecture
- This is a Next.js 15 Pages Router app deployed as a static export to GitHub Pages.
- `output: 'export'` in next.config.js is a hard constraint — NO server-side features.
- All content lives in `content/blog/*.md`. Data is read at build time via getStaticProps.
## Tech Stack
- Framework: Next.js 15 (Pages Router only — do NOT use App Router)
- Styling: Tailwind CSS v3
- Database: Supabase (client-side only — no server API routes)
- Auth: Supabase Auth
- Deployment: GitHub Pages via `next build && next export`
## Code Conventions
- TypeScript strict mode. Never use `any` unless absolutely necessary.
- Prefer named exports over default exports for components.
- All API types must be defined in `lib/types.ts`.
- Use absolute imports via `@/` prefix, not relative `../../`.
## What Claude MUST NOT Do
- Never use `git commit` or `git push`. The human handles the Git workflow.
- Never add `console.log` statements to production code.
- Never modify `package.json` without explicit permission.
- Never create files outside of `components/`, `pages/`, `lib/`, or `content/`.
## Testing
- There are no automated tests. The build (`npm run build`) is the validation step.
- Always run `npx tsc --noEmit` after making TypeScript changes.
The CLAUDE.md File Hierarchy:
Claude reads files in this order, with later files overriding earlier ones:
~/.claude/CLAUDE.md ← Global: applies to ALL projects
↓
/your-repo/CLAUDE.md ← Project: applies to this repo
↓
/your-repo/src/CLAUDE.md ← Directory: applies to src/ only
This layering is powerful. Put your personal preferences (preferred editor commands, your name for commit attribution) in the global file. Put project-specific architecture and constraints in the repo file. Put subsystem-specific rules in subdirectory files.
Layer 2: .claude/settings.json — Behavioral Controls
The settings file controls how Claude Code behaves at the session level:
{
"permissions": {
"allow": [
"Bash(npm run *)",
"Bash(npx tsc --noEmit)",
"Bash(git status)",
"Bash(git diff *)",
"Read(**/*.md)",
"Read(**/*.ts)",
"Read(**/*.tsx)"
],
"deny": [
"Bash(git commit*)",
"Bash(git push*)",
"Bash(rm -rf *)",
"Bash(sudo *)"
]
}
}
Key permission patterns:
| Pattern | What it allows |
|---|---|
Bash(npm run *) |
Any npm run script |
Bash(git diff *) |
Read-only git operations |
Read(**/*.ts) |
Read any TypeScript file |
Bash(rm -rf *) |
DENY this — prevents accidental deletion |
Layer 3: .claudeignore — Physical Boundaries
While CLAUDE.md tells Claude what to do, .claudeignore tells Claude what it physically cannot see. This is your security perimeter.
# === Build Artifacts & Dependencies ===
.next/
out/
dist/
build/
node_modules/
.venv/
venv/
target/
# === Secrets & Credentials (CRITICAL) ===
.env
.env.local
.env.*.local
*.pem
*.key
id_rsa
id_ed25519
credentials.json
service-account.json
*.secret
# === Large Binary & Data Files ===
public/images/
*.jpg
*.jpeg
*.png
*.gif
*.mp4
*.pdf
*.zip
*.tar.gz
# === Generated & Cache Files ===
*.log
tsconfig.tsbuildinfo
.eslintcache
.next/cache/
# === Test Fixtures (too large to reason about) ===
__fixtures__/
__snapshots__/
test-results/
The "Why" behind each category:
- Build artifacts: Minified code confuses Claude and wastes tokens
- Secrets: Non-negotiable. Physical exclusion > "I won't read that"
- Large binaries: Images and PDFs consume context without adding reasoning value
- Generated files: Claude shouldn't try to edit auto-generated code
Real-World Configuration: A Production-Ready Template
Here is a battle-tested CLAUDE.md for a typical backend Java Spring Boot microservice:
# Project: Payment Processing Service
## System Context
This is a Spring Boot 3.2 microservice handling payment transactions for
an e-commerce platform. It processes ~50,000 transactions/day.
## Architecture Constraints
- Java 21 with Virtual Threads (Project Loom). Use VirtualThreadTaskExecutor.
- PostgreSQL via Spring Data JPA. Never use native queries unless JPA is provably insufficient.
- All financial amounts are BigDecimal. NEVER use double or float for money.
- All external API calls have 3s timeouts and use Resilience4j circuit breakers.
- Secrets are injected via AWS Secrets Manager — never hardcode credentials.
## Package Structure
com.payments/ api/ ← REST controllers only. No business logic. service/ ← Business logic. Stateless services only. repository/ ← Spring Data repos. Query methods preferred over JPQL. domain/ ← JPA entities. Immutable where possible. config/ ← Spring configuration classes. dto/ ← Request/Response DTOs. Use records.
## Test Coverage Requirements
- Every public service method needs a unit test.
- Run `./mvnw test` to verify before marking a task complete.
- Use @Testcontainers for any test touching a real PostgreSQL connection.
## What Claude MUST NOT Do
- Never modify database migration scripts in src/main/resources/db/migration/.
- Never use @Autowired field injection — use constructor injection only.
- Never suppress unchecked cast warnings without a comment explaining why.
- Never commit changes (./mvnw deploy or git push).
Measuring the Impact
Here is how proper configuration changes the session dynamics:
| Without CLAUDE.md | With CLAUDE.md |
|---|---|
| 3–5 messages to orient Claude to the stack | Claude knows the stack immediately |
| Claude might suggest Pages Router refactors | Claude respects App Router constraints |
Claude might propose console.log debugging |
Claude follows the observability standards |
| Claude might commit accidentally | Permission deny prevents git commit |
Claude reads node_modules/ (wasted tokens) |
.claudeignore blocks it physically |
The net effect: less prompt engineering on your side, higher accuracy on Claude's side.
Checklist: Production-Ready Claude Code Configuration
Before you start your next session, verify:
-
CLAUDE.mddescribes the framework, constraints, and "never do" rules -
.claudeignoreexcludes secrets, build artifacts, and large binaries -
settings.jsondeniesgit commit,git push, andrm -rf - Architecture decisions are documented (not just "we use Next.js" but "why we use Pages Router")
- Code conventions are specific enough to be actionable
Key Takeaways
- CLAUDE.md is the constitutional law of your project — Claude reads it at the start of every session.
- Layered rules (global → project → directory) let you set defaults at your machine level and override per-repo.
- .claudeignore physically prevents Claude from reading secrets, build artifacts, and large binary files.