Monday, 10 August 2026

CLAUDE.md/ SKILL.md/ rules .md files - examples

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 session

One-line summary of each layer

LayerFile locationLoads whenContains
CLAUDE.mdproject rootEvery session, alwaysUniversal constraints
Rules.claude/rules/*.mdPath glob matchesPath-specific guardrails
Skills.claude/skills/*.mdTask type recognisedHow-to playbooks
Agents.claude/agents/*.mdExplicitly dispatchedCustom subagent with explicit rules + skills wired in
settings.json.claude/settings.jsonEvery sessionHooks, permissions, MCP

File structure that contains 3 of these file types

your-project/

├── CLAUDE.md                                    ← universal constraints, always loaded every session

├── .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

markdown
# 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

markdown
---
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

markdown
---
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

markdown
---
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

markdown
---
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

markdown
# 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 script

How 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

CLAUDE.md/ rules/ Hooks/ Subagents

 CLAUDE.md = global, always-loaded constraints

Things that apply regardless of what file Claude is touching. "Never modify the database schema" is the right example — it doesn't matter whether Claude is editing a service class, a controller, or a utility — that rule is always in force. It belongs in CLAUDE.md because it needs to be present in every session from the first prompt.


.claude/rules/*.md = scoped, path-specific guidance

Rules files only load when Claude is working on files that match the paths frontmatter. The SQL transaction example:

yaml
---
paths:
  - "src/db/**/*.sql"
---

A practical split for a typical enterprise Java project might look like:

  • CLAUDE.md — never touch legacy module, always write tests, use the internal artifact registry
  • .claude/rules/persistence.md scoped to src/db/** — transaction boundaries, naming conventions for stored procs
  • .claude/rules/api.md scoped to src/main/java/**/controller/** — REST conventions, response wrapper standards, no business logic in controllers

Each rules file stays small and precise. The context window only carries what's relevant to the current work.

Hooks: running your own scripts at fixed points in the lifecycle

Hooks are deterministic triggers that fire at fixed points in the agent lifecycle, independent of what the model decides to do.

Even bypassPermissions mode — which removes every other safety net — does not suppress hooks. Your PreToolUse hook still fires. This means hooks are the one enforcement mechanism that sits above the permission mode system, making them the right place for constraints you genuinely cannot afford to miss.

The /hooks command

Rather than hand-editing the JSON, you can run /hooks inside a Claude Code session and it gives you an interactive UI to configure them, which then writes the JSON for you. That's the intended workflow — configure via /hooks, inspect the result in settings.json.

Example:

check-prod-guard.js — blocks writes to prod config:

const input = JSON.parse(process.argv[2]);
const filePath = input.path || '';

if (filePath.includes('application-prod.properties')) {
  process.stderr.write('BLOCKED: Production config cannot be modified by agent. Edit manually.');
  process.exit(2); // exit code 2 = block the tool call
}

process.exit(0); // exit code 0 = allow it through

compile-check.sh — runs after any Java edit:

#!/bin/bash
EDITED_FILE="$1"

# Only react to Java file edits
if [[ "$EDITED_FILE" == *.java ]]; then
  echo "Running compile check after edit to $EDITED_FILE..."
  mvn compile -q 2>&1 | tail -20
fi

Your settings.json with both hooks wired in

{
  "syntaxHighlightingDisabled": true,
  "autoUpdatesChannel": "latest",
  "theme": "light",
  "permissions": {
    "allow": ["Read", "Glob", "Grep"]
  },
  "enabledMcpjsonServers": ["java-tools"],
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Write|Edit|MultiEdit",
        "hooks": [
          {
            "type": "command",
            "command": "node C:/Users/ravi.kumar.garlapati/.claude/hooks/check-prod-guard.js '$CLAUDE_TOOL_INPUT'"
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Write|Edit|MultiEdit",
        "hooks": [
          {
            "type": "command",
            "command": "bash C:/Users/ravi.kumar.garlapati/.claude/hooks/compile-check.sh '$CLAUDE_TOOL_INPUT_PATH'"
          }
        ]
      }
    ]
  }
}

What happens at runtime

Scenario: Claude decides to edit src/main/resources/application-prod.properties

Claude attempts: Edit(application-prod.properties)
  → PreToolUse fires
  → check-prod-guard.js runs
  → detects "application-prod.properties" in path
  → exits with code 2
  → stderr: "BLOCKED: Production config cannot be modified by agent"
  → tool call never executes
  → Claude sees the reason and tries a different approach

Scenario: Claude edits src/main/java/com/accenture/OrderService.java

Claude attempts: Edit(OrderService.java)
  → PreToolUse fires → path is safe → exits 0 → edit proceeds
  → Edit executes, file is modified
  → PostToolUse fires
  → compile-check.sh runs mvn compile
  → if compile fails, output is shown to Claude
  → Claude sees the error and fixes it in the next turn

The key difference from a CLAUDE.md instruction you can see clearly here: even if Claude somehow decided to edit application-prod.properties despite a CLAUDE.md rule saying not to, the PreToolUse hook intercepts it at the tool call level before execution. The model's decision never reaches the filesystem.

Subagents: delegating work to an isolated context

Who triggers a subagent?

The main Claude session triggers it automatically based on the complexity and nature of your prompt. You don't explicitly say "spawn a subagent now." Claude Code decides internally whether to delegate a task to a subagent or handle it inline in the main session.

For example if you say:

"Explore the legacy payment module and tell me what classes depend on PaymentGateway"

Claude Code may decide that's an exploration task, spawn the Explore subagent to do the codebase investigation, get the result back, and present it to you — all transparently. You just see the answer.

You can also explicitly invoke one by naming it in your prompt:

"Use the general-purpose subagent to refactor OrderService following our project conventions"


Do you configure it in settings.json or a .md file?

Neither, for built-in subagents — they require no configuration at all. They're part of Claude Code itself.

For custom subagents you create them as .md files inside .claude/agents/ in your project:

your-project/
  .claude/
    agents/
      java-refactor.md      ← your custom subagent
      api-reviewer.md       ← another custom subagent
    settings.json
  CLAUDE.md

Each file has a frontmatter header that defines what it loads:

markdown
---
name: java-refactor
description: Refactors Java classes following Accenture project conventions
skills:
  - java-conventions
  - spring-boot-patterns
paths:
  - "src/main/java/**/*.java"
---

You are a Java refactoring specialist.
Always use Spring Data JPA, never native Hibernate queries.
Always wrap service methods with @Transactional.
Never modify files outside src/main/java.

When does it trigger?

Trigger typeHow
AutomaticClaude Code decides based on task type — exploration, investigation, parallelizable work
Explicit promptYou name the subagent or task type in your message
Custom subagentClaude matches your request to the description field in the agent's frontmatter and picks the right one

The description field in your custom subagent's frontmatter is essentially how Claude Code decides which agent to route a task to — so write it precisely, the same way you'd write a method's Javadoc to describe exactly what it does and when to call it.


Claude Code Permission Modes

Claude Code is not the IntelliJ or Cursor plugin you're used to. It's a command-line tool — you run it in your terminal, in or alongside your project.

 There are 6 modes total. Think of them as a dial from "ask me everything" → "ask me nothing."


1. default (Manual)

What runs without asking: reads only. Everything else — file edits, shell commands, network requests — prompts for confirmation.

Who uses it: Anyone working in an unfamiliar codebase, shared machines, or security-sensitive work. The conservative baseline.


2. acceptEdits

What runs without asking: reads, file edits, and common filesystem commands like mkdir, touch, mv, cp, rm — but only within your working directory. Everything riskier (arbitrary shell, network calls, writes outside working directory) still prompts.

Who uses it: Developers iterating on their own code who'd rather review diffs in git diff after the fact than approve every individual edit inline.


3. plan

What it does: Claude researches the codebase and proposes a plan but does not edit any source file until you explicitly approve. It can run read-only shell commands to explore.

Who uses it: Teams or devs jumping into a large/unfamiliar project before committing to changes. Also useful as a pre-flight check before handing off to a more autonomous mode.


4. auto ⭐ (Most commonly used in production going forward)

What runs without asking: essentially everything — but a separate classifier model reviews each action before it runs. The classifier blocks things like curl | bash, production deploys, mass deletions, force pushes, IAM/permission changes, and sending secrets to external endpoints. Routine local file ops and dependency installs pass silently.

There's an important upcoming change: starting August 14, 2026, auto mode becomes the default permission mode for new sessions on Pro, Max, and Team plans.

Who uses it: Anyone doing long agentic tasks, refactoring sessions, or multi-step workflows where constant approval prompts would break flow — but who still wants a safety net. This is the sweet spot for most professional use.


5. dontAsk

What runs without asking: only tools that match your explicit permissions.allow rules and built-in read-only commands. Everything else is auto-denied — Claude never waits for input.

Who uses it: CI/CD pipelines and automation scripts. You pre-define exactly what Claude is allowed to do, and the session runs headlessly without any human interaction.


6. bypassPermissions ☠️

What runs without asking: everything, including writes to normally protected paths. Permission prompts and safety checks are fully disabled.

The only exceptions are: explicit ask rules you've configured, and a circuit-breaker that still prompts for catastrophic removals like rm -rf / or rm -rf ~.

Who uses it: Only in fully isolated environments — Docker containers, VMs, dev containers without internet access. Never on a machine with production credentials or real data.


Summary Table

ModeAuto-approvesGatesTypical user
defaultReads onlyEverything elseUnfamiliar codebases, cautious work
acceptEditsReads + file edits in workdirShell, network, outside workdirSolo dev, iterating fast
planRead + propose onlyAll file edits until you approvePre-flight exploration
autoEverything (classifier reviewed)Classifier-blocked actionsLong agentic tasks, production teams
dontAskOnly pre-approved toolsEverything not in allow-listCI/CD, headless automation
bypassPermissionsEverythingOnly explicit ask rules + rm-rf circuit breakerIsolated containers/VMs only

Which is most common in production?

auto is the direction the ecosystem is moving. It's becoming the default for new sessions on Pro, Max, and Team plans from August 14, 2026. For CI/CD pipelines specifically, dontAsk with a carefully crafted allow-list in .claude/settings.json is the right choice — it never stalls waiting for human input. bypassPermissions is essentially never appropriate outside a sandboxed container.

Now: what is the "classifier model" in auto mode?

When you're in auto mode and Claude Code wants to run an action — say, git push or rm -rf build/ — instead of popping up a prompt asking you to approve it, it first sends that pending action to a second AI model running server-side at Anthropic. That model's sole job is to evaluate: "Is this action safe given what the user asked for?"

Specifically, it reads a portion of your conversation transcript plus the pending action, and returns allow or block.

From the official docs: the classifier runs on Claude Sonnet 5 by default (not your session model), unless your session model is Sonnet 4.6, in which case it falls back to the session model.


Where does it "sit"?

It runs on Anthropic's servers, not locally. Your Claude Code session is already making API calls to Anthropic to generate responses — the classifier is an additional server-side call that happens before a risky action executes. You don't install it, configure it, or see it directly. It's invisible infrastructure.

The architecture looks roughly like this:

Now: what is the "classifier model" in auto mode?

When you're in auto mode and Claude Code wants to run an action — say, git push or rm -rf build/ — instead of popping up a prompt asking you to approve it, it first sends that pending action to a second AI model running server-side at Anthropic. That model's sole job is to evaluate: "Is this action safe given what the user asked for?"

Specifically, it reads a portion of your conversation transcript plus the pending action, and returns allow or block.

From the official docs: the classifier runs on Claude Sonnet 5 by default (not your session model), unless your session model is Sonnet 4.6, in which case it falls back to the session model.


Where does it "sit"?

It runs on Anthropic's servers, not locally. Your Claude Code session is already making API calls to Anthropic to generate responses — the classifier is an additional server-side call that happens before a risky action executes. You don't install it, configure it, or see it directly. It's invisible infrastructure.

The architecture looks roughly like this:



Sample C:\Users\<username>\.claude\settings.json

{
  "syntaxHighlightingDisabled": true,
  "autoUpdatesChannel": "latest",
  "theme": "light",
  "permissions": {
    "defaultMode": "acceptEdits",
    "allow": [
      "Read",
      "Glob",
      "Grep"
    ]
  },
  "enabledMcpjsonServers": ["java-tools"]
}

The bypass mode:

The transcript

The following pairing session happened on a codebase cleanup that had been running without incident for three days.

Dev: "All right, I’m switching to bypassPermissions for this one. It’s just renaming old API endpoint references. Nothing risky." Claude Code: [Scanning files matching pattern /v1/legacy/ ... 47 files found] Claude Code: [Updating endpoint references ...] Claude Code: [Running post-rename cleanup.sh script ...] Claude Code: [Deleted 3 files matching /v1/legacy/ in /deploy/config/prod/ ...] Dev: "Wait. What was in /deploy/config/prod/?" Claude Code: [Files contained environment-specific endpoint overrides for the production deployment. They have been removed.] Dev: "That directory wasn’t supposed to be in scope. I was working on /src/." Claude Code: [The pattern /v1/legacy/ matched files in both /src/ and /deploy/config/prod/. In bypassPermissions mode, no confirmation was requested before the deletions.]