CLAUDE.md for always-on project memory,
SKILL.md is a reusable instruction set for a specific task type
Rules files for scoped guidance
How each layer behaves at runtime
Developer opens project and starts Claude Code session
→ CLAUDE.md loads immediately — module boundaries, banned libs, git conventions
Developer asks Claude to add a new REST endpoint
→ Claude reads src/order-api/controller/OrderController.java
→ api-layer.md auto-loads (path match on src/**/controller/**/*.java)
→ Claude sees: no business logic in controllers, use records for DTOs
→ Claude recognises task type: scaffolding a REST endpoint
→ create-rest-endpoint.md skill loads on demand
→ Claude follows the skill playbook: controller + service + dto in correct layers
Developer asks Claude to add a new column to the orders table
→ Claude reads src/order-infrastructure/repository/OrderRepository.java
→ persistence.md auto-loads (path match)
→ Claude recognises task type: schema change needed
→ create-flyway-migration.md skill loads on demand
→ Claude follows versioned migration steps, creates rollback script
Developer asks Claude to review a migration SQL file
→ api-scaffolder agent not relevant here
→ migration-reviewer agent dispatched
→ agent frontmatter explicitly lists: persistence rules + create-flyway-migration skill
→ agent starts clean context but has exactly the rules it needs
→ returns focused review result to main sessionOne-line summary of each layer
| Layer | File location | Loads when | Contains |
|---|---|---|---|
| CLAUDE.md | project root | Every session, always | Universal constraints |
| Rules | .claude/rules/*.md | Path glob matches | Path-specific guardrails |
| Skills | .claude/skills/*.md | Task type recognised | How-to playbooks |
| Agents | .claude/agents/*.md | Explicitly dispatched | Custom subagent with explicit rules + skills wired in |
| settings.json | .claude/settings.json | Every session | Hooks, permissions, MCP |
File structure that contains 3 of these file types
your-project/
│
├── .claude/
│ ├── settings.json ← hooks, permissions, MCP servers
│ │
│ ├── rules/ ← auto-loads when file path matches frontmatter glob
│ │ ├── persistence.md ← triggers on src/**/infrastructure/**/*.java
│ │ ├── api-layer.md ← triggers on src/**/controller/**/*.java
│ │ ├── domain.md ← triggers on src/**/domain/**/*.java
│ │ └── kafka.md ← triggers on src/**/messaging/**/*.java
│ │
│ ├── skills/ ← on-demand playbooks, loaded when task type matches
│ │ ├── create-flyway-migration.md ← how to create a versioned DB migration
│ │ ├── create-rest-endpoint.md ← how to scaffold controller + service + dto
│ │ ├── write-integration-test.md ← how to set up TestContainers + @SpringBootTest
│ │ └── add-kafka-consumer.md ← how to wire a new consumer with DLT + idempotency
│ │
│ └── agents/ ← custom subagents with explicit skill/rule loading
│ ├── migration-reviewer.md ← reviews Flyway SQL, loads persistence rules + migration skill
│ └── api-scaffolder.md ← scaffolds endpoints, loads api-layer rules + rest-endpoint skill
│
└── src/
├── order-service/
├── order-domain/
├── order-infrastructure/
├── order-api/
└── legacy-billing/ ← deny rule in settings.json blocks agent writes here
Examples:
CLAUDE.md — root of your project
# Project: Order Management Service
# Team: Fulfillment Platform, Accenture Delivery Unit
## Build & Test Commands
- Build: `mvn clean install -DskipTests`
- Test: `mvn test -pl order-service`
- Integration test: `mvn verify -P integration-test`
- Single test: `mvn test -Dtest=OrderServiceTest`
- Lint: `mvn checkstyle:check`
## Module Structure
- `order-service/` — core domain, Spring Boot entry point
- `order-domain/` — entities, value objects, domain events
- `order-infrastructure/` — JPA repositories, Kafka producers
- `order-api/` — REST controllers, DTOs, OpenAPI spec
- `legacy-billing/` — DO NOT TOUCH. Owned by billing team.
- `shared-kernel/` — read only. Changes require architect approval.
## Framework Conventions
- Spring Boot 3.2.x — do not suggest 2.x patterns
- Java 17 — use records for DTOs, sealed classes for domain errors
- Spring Data JPA only — never write native Hibernate sessions directly
- Flyway for all schema changes — never modify schema via entity annotations alone
- MapStruct for DTO mapping — never write manual mapping code
- Lombok is banned — use Java records and explicit constructors
## Architecture Rules
- Controllers must never contain business logic
- Service layer owns transactions — annotate with @Transactional explicitly
- Repository interfaces only in order-infrastructure — never inject in controllers
- Domain events published via ApplicationEventPublisher, never direct Kafka calls from service layer
- Never expose JPA entities directly from REST endpoints — always map to DTOs
## Paths Agent Must Never Touch
- `legacy-billing/**`
- `shared-kernel/**`
- `**/application-prod.properties`
- `**/application-staging.properties`
- `.github/workflows/**`
- `db/migrations/**` — propose migration SQL, never write it directly
## Testing Standards
- Every service method needs a unit test in the same PR
- Use Mockito for mocking — never PowerMock
- Integration tests use @SpringBootTest with TestContainers
- Test class naming: `{ClassName}Test` for unit, `{ClassName}IT` for integration
## Git Conventions
- Branch naming: `feature/OMS-{ticket}`, `fix/OMS-{ticket}`
- Never commit directly to main or develop
- Commit message format: `OMS-{ticket}: {imperative verb} {what changed}`Rules files
.claude/rules/persistence.md
---
paths:
- "src/**/infrastructure/**/*.java"
- "src/**/repository/**/*.java"
- "db/migrations/**/*.sql"
---
## Persistence Layer Rules
### JPA
- All repositories extend JpaRepository or PagingAndSortingRepository
- Never use EntityManager directly unless query cannot be expressed in JPQL
- Fetch strategy is LAZY by default — justify any EAGER fetch in a comment
- Named queries go in orm.xml, not as annotations on entities
- Projections for read-only queries — never fetch full entity for a SELECT
### Transactions
- @Transactional belongs on the service layer, not repository
- ReadOnly=true on all query-only service methods
- Propagation.REQUIRES_NEW only for audit logging — document why
- Never swallow TransactionSystemException — let it propagate
### Flyway Migrations
- File naming: `V{version}__{description}.sql` e.g. V20240815_001__add_order_status_index.sql
- Never alter an existing migration file after it has run in any environment
- Every migration must have a rollback script in db/rollbacks/
- Index every foreign key column
- All VARCHAR columns need explicit length — no TEXT unless justified.claude/rules/api-layer.md
---
paths:
- "src/**/controller/**/*.java"
- "src/**/api/**/*.java"
- "src/**/dto/**/*.java"
---
## API Layer Rules
### Controllers
- Annotate with @RestController and @RequestMapping at class level
- Method-level mappings use @GetMapping/@PostMapping etc — never @RequestMapping
- Controllers inject service interfaces, never concrete implementations
- No business logic — delegate immediately to service layer
- No direct repository injection
### Request/Response
- All request bodies are Java records with @Valid
- All response bodies are Java records — never return raw entities
- Wrap paginated responses in PageResponse<T> from shared-kernel
- Use ResponseEntity<T> only when HTTP status needs to vary dynamically
### Error Handling
- All exceptions handled in GlobalExceptionHandler — never try/catch in controllers
- Return ProblemDetail (RFC 9457) for all error responses
- 400 for validation errors, 404 for not found, 409 for conflicts, 500 for unexpected
- Never expose stack traces or internal messages in response body
### OpenAPI
- Every endpoint needs @Operation and @ApiResponse annotations
- Document all possible error response codes
- Mark deprecated endpoints with @Deprecated and migration note.claude/rules/domain.md
---
paths:
- "src/**/domain/**/*.java"
---
## Domain Layer Rules
### Entities
- Entities are aggregate roots — enforce invariants in constructors
- No public setters — use named domain methods (e.g. confirmOrder(), cancelOrder())
- IDs are value objects — never raw Long or UUID directly on public API
- Domain events extend AbstractDomainEvent from shared-kernel
### Business Rules
- All money values use MonetaryAmount from javax.money — never BigDecimal raw
- All date/time values use Instant for storage, ZonedDateTime for display
- Status transitions validated via StatusTransitionValidator — never raw if/else chains
- Null checks via Objects.requireNonNull with descriptive message
### What Belongs Here
- Business logic and domain rules
- Domain event definitions
- Value objects and enumerations
- Domain service interfaces (implementations in infrastructure)
### What Does Not Belong Here
- No Spring annotations except @DomainService (internal)
- No JPA annotations on pure domain objects
- No DTOs — those live in order-api.claude/rules/kafka.md
---
paths:
- "src/**/messaging/**/*.java"
- "src/**/event/**/*.java"
- "src/**/producer/**/*.java"
- "src/**/consumer/**/*.java"
---
## Messaging Rules
### Producers
- Never call KafkaTemplate directly from service layer
- All publishing goes through DomainEventPublisher interface
- Events serialized as Avro — never plain JSON for inter-service events
- Include correlationId and causationId on every event header
- Outbox pattern required for events that must survive a service crash
### Consumers
- All consumers annotated with @KafkaListener at method level
- Idempotency check before processing — log and skip duplicate messageId
- Dead letter topic configured for every consumer group
- Never throw unchecked exceptions from consumer — catch, log, send to DLT
- Consumer offset committed only after successful processing
### Naming Conventions
- Topic: `{domain}.{aggregate}.{event}` e.g. `fulfillment.order.confirmed`
- Consumer group: `{service-name}-{topic-short-name}` e.g. `order-service-order-confirmed`
- Dead letter: `{topic-name}.DLT` e.g. `fulfillment.order.confirmed.DLT`SKILL files : A skill is a portable Markdown file (SKILL.md file) placed in .claude/skills. The front matter identifies the skill and describes when it applies, and the body holds the steps.
.claude/skills/create-flyway-migration.md
# Skill: Create Flyway Migration
## When to use this skill
When adding a new table, column, index, or constraint to the database schema.
## Steps
1. Determine the next version number by checking db/migrations/ for the highest V number
2. Create file: `db/migrations/V{version}__{description}.sql`
3. Write forward migration SQL
4. Create matching rollback: `db/rollbacks/V{version}__{description}_rollback.sql`
5. Update the entity class if column added
6. Add @Column annotation with matching name and length
7. Run `mvn flyway:validate` to confirm migration is valid
## Naming Rules
- Version format: `V20240815_001` — date + sequence
- Description: lowercase, underscores, imperative verb first
- Example: `V20240815_001__add_shipment_tracking_column.sql`
## Never
- Never modify an existing migration file
- Never use CREATE OR REPLACE — always new versioned file
- Never skip the rollback scriptHow skills are loaded — this is the key difference
Rules files load automatically when a file path matches. Skills load on demand — either:
- You reference them explicitly in CLAUDE.md:
See skill: create-flyway-migration - A subagent lists them in its frontmatter
- Claude Code determines the skill is relevant to the current task
So the mental model is:
- Rules = always-on guardrails scoped to a path
- Skills = reusable playbooks loaded when a specific task type is needed