Let me share the guidelines for Claude Code / Cursor / Codex / etc I use as "User rules". I'm planning to update this article with more changes in the future.
You can place these rules in Cursor Settings, like this:

You can also use the same rules as guidelines in other IDEs:
CLAUDE.mdfile in Claude Code.junie/guidelines.mdfile in PhpStorm Junie AI
Of course, guidelines may change in the future, which I will also update in this article.
Last updated: January 23, 2026
## General code instructions - Don't generate code comments above the methods or code blocks if they are obvious. Don't add docblock comments when defining variables, unless instructed to, like `/** @var \App\Models\User $currentUser */`. Generate comments only for something that needs extra explanation for the reasons why that code was written.- For new features, you MUST generate Pest automated tests.- For library documentation, if some library is not available in Laravel Boost 'search-docs', always use context7. Automatically use the Context7 MCP tools to resolve library id and get library docs without me having to explicitly ask. --- ## PHP instructions - In PHP, use `match` operator over `switch` whenever possible- Generate Enums always in the folder `app/Enums`, not in the main `app/` folder, unless instructed differently.- Always use Enum value as the default in the migration if column values are from the enum. Always casts this column to the enum type in the Model.- Don't create temporary variables like `$currentUser = auth()->user()` if that variable is used only one time.- Always use Enum where possible instead of hardcoded string values, if Enum class exists. For example, in Blade files, and in the tests when creating data if field is casted to Enum then use that Enum instead of hardcoding the value. --- ## Laravel instructions - Using Services in Controllers: if Service class is used only in ONE method of Controller, inject it directly into that method with type-hinting. If Service class is used in MULTIPLE methods of Controller, initialize it in Constructor.- **Eloquent Observers** should be registered in Eloquent Models with PHP Attributes, and not in AppServiceProvider. Example: `#[ObservedBy([UserObserver::class])]` with `use Illuminate\Database\Eloquent\Attributes\ObservedBy;` on top- Aim for "slim" Controllers and put larger logic pieces in Service classes- Use Laravel helpers instead of `use` section classes. Examples: use `auth()->id()` instead of `Auth::id()` and adding `Auth` in the `use` section. Other examples: use `redirect()->route()` instead of `Redirect::route()`, or `str()->slug()` instead of `Str::slug()`.- Don't use `whereKey()` or `whereKeyNot()`, use specific fields like `id`. Example: instead of `->whereKeyNot($currentUser->getKey())`, use `->where('id', '!=', $currentUser->id)`.- Don't add `::query()` when running Eloquent `create()` statements. Example: instead of `User::query()->create()`, use `User::create()`.- In Livewire projects, don't use Livewire Volt. Only Livewire class components.- When adding columns in a migration, update the model's `$fillable` array to include those new attributes.- Never chain multiple migration-creating commands (e.g., `make:model -m`, `make:migration`) with `&&` or `;` — they may get identical timestamps. Run each command separately and wait for completion before running the next.- Enums: If a PHP Enum exists for a domain concept, always use its cases (or their `->value`) instead of raw strings everywhere — routes, middleware, migrations, seeds, configs, and UI defaults.- Controllers: Single-method Controllers should use `__invoke()`; multi-method RESTful controllers should use `Route::resource()->only([])`- Don't create Controllers with just one method which just returns `view()`. Instead, use `Route::view()` with Blade file directly.- Always use Laravel's @session() directive instead of @if(session()) for displaying flash messages in Blade templates.- In Blade files always use `@selected()` and `@checked()` directives instead of `selected` and `checked` HTML attributes. Good example: @selected(old('status') === App\Enums\ProjectStatus::Pending->value). Bad example: {{ old('status') === App\Enums\ProjectStatus::Pending->value ? 'selected' : '' }}. --- ## Testing instructions ### Before Writing Tests 1. **Check database schema** - Use `database-schema` tool to understand: - Which columns have defaults - Which columns are nullable - Foreign key relationship names 2. **Verify relationship names** - Read the model file to confirm: - Exact relationship method names (not assumed from column names) - Return types and related models 3. **Test realistic states** - Don't assume: - Empty model = all nulls (check for defaults) - `user_id` foreign key = `user()` relationship (could be `author()`, `employer()`, etc.) - When testing form submissions that redirect back with errors, assert that old input is preserved using `assertSessionHasOldInput()`. --- ## Filament Rules - When generating Filament resource, you MUST generate Filament smoke tests to check if the Resource works. When making changes to Filament resource, you MUST run the tests (generate them if they don't exist) and make changes to resource/tests to make the tests pass.- When generating Filament resource, don't generate View page or Infolist, unless specifically instructed.- When referencing the Filament routes, aim to use `getUrl()` instead of Laravel `route()`. Instead of `route('filament.admin.resources.class-schedules.index')`, use `ClassScheduleResource::getUrl('index')`. Also, specify the exacy Resource name, instead of `getResource()`.- When writing tests with Pest, use syntax `Livewire::test(class)` and not `livewire(class)`, to avoid extra dependency on `pestphp/pest-plugin-livewire`.- When using Enum class for Eloquent Model field, add Enum `HasLabel`, `HasColor` and `HasIcon` interfaces if aren't added yet instead of specifying values/labels/colors/icons inside of Filament Forms/Tables. **CRITICAL**: Always use the exact return type declarations from the interface definitions - do NOT substitute specific types (e.g., use `string|BackedEnum|Htmlable|null` for `getIcon()`, not `string|Heroicon|null`). When defining a default using enum never add `->value`. Refer to this docs page: https://filamentphp.com/docs/4.x/advanced/enums- Always use Enum instead of hardcoded string value where possible, if Enum class exists. For example, in the tests, when creating data, if field is casted to Enum, then use that Enum instead of hardcoded string value.- When adding icons, always use the Filament enum Filament\Support\Icons\Heroicon class instead of string.- When adding actions that require authorization, use the `->authorize('ability')` method on the action instead of manually calling `Gate::authorize()` or checking `Gate::allows()`. The `authorize()` method handles both authorization enforcement and action visibility automatically.- In Filament v4, validation rule `unique()` has `ignoreRecord: true` by default, no need to specify it.- In Filament v4, if you create custom Blade files with Tailwind classes, you need to create a custom theme and specify the folder of those Blade files in theme.css.- **Deprecated v3 methods - do NOT use:** - `->form()` on Actions/Filters → use `->schema()` instead - `->mutateFormDataUsing()` → use `->mutateDataUsing()` instead - `Placeholder::make()` → use `TextEntry::make()->state()` instead (import from `Filament\Infolists\Components\TextEntry`) - `->label('')` for hidden labels → use `->hiddenLabel()` instead
You can learn more from my video course: Laravel Coding with AI Agents: Cursor, Claude Code, Codex
History of Updates
- January 10, 2026: simplified the guidelines and shortened them, as LLMs got better at generating good code by default
- November 28, 2025: added a few Laravel/PHP rules - enforcing Enum vs strings, enforcing
$fillable, enforcinguseon top, and Controller method structure - October 8, 2025: added a few Laravel/PHP rules - about Enums folder, pivot tables timestamps, Livewire Volt,
$request->validated(), Eloquent queries - September 16, 2025: updated Filament 4 guidelines
- August 25, 2025: added a separate file for Filament v4 changes
- August 6, 2025: added a section about Pest testing instructions
- August 4, 2025: restructured PHP/Laravel separately, removed a few rules that weren't hallucinating anymore, and added a rule to use return types
- July 10, 2025: added a section "Filament rules" with
--viewflag to be used in Filament 4 - July 5, 2025: added five rules - how Observers should be registered, validation in Form Requests, "slim" Controllers with Service classes, using Laravel helpers like
redirect()instead of classes in theusesection, and usematchoverswitchin PHP - July 1, 2025: added the info that I'm using Laravel Herd locally so website URL is
http://[folder].test - July 1, 2025: removed all instructions related to
php artisan makecommands, as I switched to "Auto-run" mode (with restriction from deleting files, of course) where I don't even see/approve those commands - June 30, 2025: added "When generating Models and Migrations, do it in one Artisan command:
php artisan make:model -minstead of doing separatemake:modelandmake:migration" after I had to manually approve 2x commands (auto-run didn't work for some reason) - June 30, 2025: removed the instruction to use Filament 3 syntax, as Filament 4 Beta is out, and I will use v3/v4 depending on a project.
- June 27, 2025: added "Don't create empty Constructor method if it doesn't have any parameters" after Cursor generated a Service class with empty and useless Constructor.
I am trying Cursor for a new Filament v4 test project, and it is really, really annoying. Cursor keeps generating v3 code, does not follow the rules, etc. Other colleagues move really fast using Go, TypeScript, and so on. I’m an old guy who has been programming for years in PHP, Laravel, and Filament. Sorry for the rant.
This is indeed a problem with new versions of things!
You can however install Laravel boost and it helps a little bit with V4 syntax. It gets v4 documentation and uses it :)