Rule Writing

CLAUDE.md for Laravel Projects

Laravel provides Eloquent, Blade, queues, and artisan — AI bypasses them all with raw patterns. Rules for the Laravel Way: Eloquent, Form Requests, Livewire, and artisan.

8 min read·May 8, 2025

Laravel includes Eloquent, Blade, queues, and artisan — AI bypasses all of them

Eloquent relationships, Form Requests, Livewire, queues, and the Laravel Way

Why Laravel Needs Rules That Enforce the Laravel Way

Laravel is PHP's most popular framework — opinionated, batteries-included, and designed around conventions that make developers productive. AI assistants ignore these conventions: raw PDO queries instead of Eloquent, manual validation instead of Form Requests, procedural PHP instead of Blade components, and synchronous processing instead of queues. The code works but carries Laravel's overhead without using its features.

Laravel's strength is its ecosystem: Eloquent for ORM, Blade for templates, Livewire for reactive UI, Sanctum/Passport for auth, Horizon for queues, Telescope for debugging. AI that doesn't use these is writing vanilla PHP with extra steps. Your rules ensure the AI uses what Laravel provides.

These rules target Laravel 11+ with PHP 8.3+. Laravel 11 simplified the project structure (no Http/Kernel, streamlined config) — specify your version to prevent AI from generating older structural patterns.

Rule 1: Eloquent ORM for Everything

The rule: 'Use Eloquent for all database operations. Never use raw DB::statement() or PDO unless Eloquent genuinely can't express the query. Use relationships: hasMany, belongsTo, hasOne, belongsToMany, hasManyThrough. Use scopes for reusable query conditions: scopeActive, scopeRecent. Use eager loading (with()) to prevent N+1 queries. Use Eloquent collections for data manipulation.'

For query patterns: 'Use where(), orWhere(), whereIn(), whereHas() for filtering. Use orderBy(), latest(), oldest() for sorting. Use paginate() for pagination — never manual LIMIT/OFFSET. Use firstOrCreate(), updateOrCreate() for upserts. Use chunk() or lazy() for processing large datasets without memory issues.'

For model design: 'Keep models focused: fillable for mass assignment protection, casts for type casting, appends for computed attributes. Use accessors and mutators (Attribute::make) for data transformation. Use model events or observers for side effects. Fat models are okay in Laravel — extract to actions/services only when the model exceeds 300 lines.'

  • Eloquent for all DB — never raw DB:: unless Eloquent can't express it
  • Relationships: hasMany, belongsTo, belongsToMany — always defined on models
  • Eager loading: with() on every query that accesses relationships
  • Scopes for reusable conditions: scopeActive, scopePublished, scopeRecent
  • paginate() for lists — chunk()/lazy() for large datasets — never all()
⚠️ N+1 Is Laravel's #1 Bug

AI generates Eloquent loops that trigger N+1 queries. Always use with() for eager loading: User::with('orders')->get(). Install Laravel Debugbar to catch N+1 in development — every loop over relationships without eager loading is a performance bug.

Rule 2: Form Requests for Validation

The rule: 'Use Form Request classes for all input validation: php artisan make:request StoreUserRequest. Define rules in the rules() method. Define authorization in the authorize() method. Type-hint the Form Request in the controller: public function store(StoreUserRequest $request). Never use $request->validate() inline in controllers — Form Requests are Laravel's validation standard.'

For validation rules: 'Use Laravel's built-in validation rules: required, email, unique:users,email, min:8, max:255, exists:roles,id. Use custom rules for complex validation: php artisan make:rule. Use sometimes for conditional validation. Use prepareForValidation() to normalize input before validation.'

For error handling: 'Form Requests automatically return 422 with validation errors for API requests, and redirect back with errors for web requests. Use $request->validated() to get only validated data — never $request->all() (it includes unvalidated fields). Use $request->safe() for a safe bag of validated data.'

Rule 3: Blade Components and Livewire

The rule: 'Use Blade components for reusable UI: <x-button>, <x-modal>, <x-alert>. Define components in app/View/Components/ with corresponding Blade templates. Use anonymous components (resources/views/components/) for simple components without a class. Use slots for flexible content: {{ $slot }}, {{ $title }}. Never use raw PHP in Blade templates — use directives: @if, @foreach, @auth, @can.'

For Livewire: 'Use Livewire for interactive server-rendered UI — forms, search, filters, data tables. Livewire components handle state on the server — no JavaScript needed for most interactions. Use wire:model for two-way binding, wire:click for actions, wire:loading for loading states. Use Alpine.js (bundled with Livewire) for client-side interactivity that doesn't need the server.'

AI generates React or Vue components in Laravel projects. Livewire provides the same interactivity with server-rendered HTML — no build step, no API layer, no JavaScript state management. For most CRUD applications, Livewire is simpler and more productive than an SPA.

  • Blade components: <x-button>, <x-modal> — reusable, typed props
  • Anonymous components for simple cases — class components for logic
  • Livewire for interactive UI — server state, no JS framework needed
  • wire:model for binding, wire:click for actions, wire:loading for states
  • Alpine.js for client-side only — @click, x-show, x-data for simple JS
💡 Livewire Over React

For CRUD apps, Livewire provides React-level interactivity with server-rendered HTML — no build step, no API layer, no JS state management. AI reaches for React/Vue from training data. Livewire is Laravel's recommended approach.

Rule 4: Queues for Async Processing

The rule: 'Use queues for any operation that takes more than 200ms: email sending, PDF generation, external API calls, file processing, report generation. Define jobs: php artisan make:job ProcessPayment. Dispatch with: ProcessPayment::dispatch($order). Use Redis or database as the queue driver. Never process long-running operations synchronously in HTTP requests — the user waits.'

For reliability: 'Implement retries: public $tries = 3. Implement backoff: public $backoff = [10, 60, 300]. Implement failure handling: public function failed(Throwable $exception). Use rate limiting: Redis::throttle for API rate limits. Use unique jobs (ShouldBeUnique) to prevent duplicate processing.'

For monitoring: 'Use Laravel Horizon for Redis queue monitoring — it provides a dashboard for job throughput, runtime, failures, and queue depth. Configure Horizon workers per queue: default, high, low priority queues. Set up alerts for failed jobs and queue backlogs.'

ℹ️ 200ms Rule

Any operation over 200ms belongs in a queue: email, PDF generation, external APIs, file processing. The user shouldn't wait for these. Dispatch a job, return immediately, process in the background.

Rule 5: Artisan and Laravel Conventions

The rule: 'Use artisan generators for all scaffolding: make:model, make:controller, make:migration, make:request, make:job, make:event, make:listener, make:policy. Follow Laravel naming: singular models (User), plural tables (users), resource controllers (UserController), Form Requests (StoreUserRequest, UpdateUserRequest). Use route model binding for automatic model resolution.'

For configuration: 'Use config() helper, not env() directly in code — env() only in config files. Use Laravel's encryption for sensitive config values. Use .env for local config, environment variables in production. Use config caching in production: php artisan config:cache.'

For API resources: 'Use API Resources for response formatting: php artisan make:resource UserResource. Resources transform Eloquent models to JSON with explicit field selection — preventing accidental exposure of internal fields. Use resource collections for paginated responses: UserResource::collection($users).'

  • Artisan generators for all scaffolding — consistent naming and structure
  • Singular models (User), plural tables (users), resource controllers (UserController)
  • Route model binding: Route::get('/users/{user}', ...) auto-resolves User
  • API Resources for response formatting — never return models directly
  • config() in code, env() only in config files — config:cache in production

Complete Laravel Rules Template

Consolidated rules for Laravel 11+ projects.

  • Eloquent for all DB: relationships, scopes, eager loading — never raw queries
  • Form Requests for validation — $request->validated() — never $request->all()
  • Blade components for UI — Livewire for interactivity — Alpine.js for client-side
  • Queues for async: email, API calls, file processing — Horizon for monitoring
  • Artisan generators — Laravel naming conventions — route model binding
  • API Resources for JSON responses — never return Eloquent models directly
  • config() not env() in code — .env for local, env vars for production
  • Pint for formatting — Larastan for static analysis — Pest for testing