Laravel is convention heavy, which helps an agent right up until conventions change between major versions, and Laravel 11 moved a lot: no HTTP kernel, a slimmer app skeleton, and middleware plus routing registered in bootstrap/app.php. An agent needs the major version, the queue and cache drivers in use, and whether the frontend is Blade, Livewire, or Inertia, because those three lead to completely different code for the same feature. Eloquent's ergonomics are also its trap: the easy way to write a relationship access is usually the way that generates a query per row.
Save this as AGENTS.md in your project root, and symlink CLAUDE.md to it so Claude Code reads the same rules. Adapt the commands to match your repository before committing it.
# AGENTS.md
This is a subscription SaaS built with Laravel, Eloquent, and Stripe via Cashier.
## Project
Stack: PHP 8.3, Laravel 11, MySQL, Redis queues, Laravel Cashier, Inertia with Vue 3, Vite, Pest, Pint, Larastan.
Layout:
- `routes/web.php`, `routes/api.php`, `routes/console.php`
- `app/Http/Controllers/` thin controllers, one action group per resource
- `app/Http/Requests/` form request validation
- `app/Http/Middleware/`
- `app/Actions/` single purpose invokable classes holding business logic
- `app/Models/` Eloquent models, relationships, casts, scopes
- `app/Policies/` authorization
- `app/Jobs/` queued work, `app/Events/` and `app/Listeners/`
- `database/migrations/`, `database/factories/`, `database/seeders/`
- `resources/js/Pages/` Inertia pages, `resources/js/Components/`
- `config/` framework and package configuration
Entry points: `routes/web.php`, `app/Providers/AppServiceProvider.php`, `config/cashier.php`.
## Commands
```bash
composer install
npm install
php artisan serve # dev server on :8000
npm run dev # vite dev server
npm run build # production assets
php artisan migrate # apply migrations
php artisan migrate:fresh --seed # local reset only
php artisan make:model Invoice -mfR # model, migration, factory, request, controller
php artisan queue:work # process jobs
php artisan schedule:work # run the scheduler locally
php artisan test # full suite
php artisan test --filter=SubscriptionTest
./vendor/bin/pint # format to PSR-12
./vendor/bin/phpstan analyse # static analysis
php artisan optimize:clear # clear config, route, view caches
```
Generate classes with artisan rather than creating files by hand, so namespaces and stubs stay correct.
## Code style
- Controllers are thin. Validation goes in a form request, authorization in a policy, business logic in an action.
- Never call `request()` outside a controller or middleware. Pass data down explicitly.
- No queries in Blade or in an Inertia page component. Load relations eagerly with `with()` in the controller.
- Guard against N+1 by keeping `Model::preventLazyLoading()` enabled in non production environments.
- Use route model binding rather than manual `find()` plus 404 handling.
- Mass assignment: define `$fillable` explicitly, never `$guarded = []`.
- Money is stored in integer minor units, formatted only at the view layer.
- Anything slower than a database write goes into a queued job, not an inline call.
- Follow PSR-12 through Pint. Typed properties, typed arguments, and return types everywhere.
- Config values are read through `config()`, never `env()` outside `config/`.
## Boundaries
Do not touch without explicit instruction:
- Existing files in `database/migrations/`. Migrations are append only once applied.
- `.env` and any credential. New keys go in `.env.example` and a `config/` file.
- `composer.lock` and `package-lock.json`. Use `composer require` and `npm install <pkg>`.
- Cashier tables, subscription records, and Stripe price identifiers.
- `.github/workflows/`, deployment scripts, and server provisioning files.
Needs human review: policies and gates, anything in `app/Jobs/` that touches billing, webhook handling, and any migration that drops or renames a column.
Do not run `migrate:fresh` against anything but the local database.
## Testing
- `php artisan test` runs Pest. Use `--filter` to run one test while iterating.
- Tests use `RefreshDatabase` against a dedicated test connection. Never point tests at the development database.
- Required tests: every route (happy path plus authorization failure), every policy, every job, and all billing state transitions.
- Build data with factories in `database/factories/`. Seeders are for local development only.
- Fake external services with `Http::fake()`, `Queue::fake()`, `Mail::fake()`. Do not hit Stripe in tests, use Cashier's test helpers.
- A bug fix ships with a regression test.
## Git workflow
- Branch from `main`: `feat/short-description`, `fix/short-description`.
- Conventional commits: `feat(billing): add annual plan upgrade path`.
- Migrations ship in the same commit as the code that depends on them.
- Run Pint before committing so formatting never appears in a review diff.
- PR description lists migrations, queue changes, new config keys, and any artisan command needed at deploy.
- Never commit to `main`.
Each of these is worth a line in your rules file, because the model will otherwise repeat it every session.
Asked for a feature, an agent writes the validation, the Stripe call, the model writes, and the notification into one controller method, because that is the shortest path to working code. The logic then cannot be reused from a command or a queued job and is painful to test. Add to your rules file: 'Controllers validate and delegate only. Business logic lives in a single purpose action or service class under app/Actions, and the controller method should be under about fifteen lines.'
The agent returns Post::all() from the controller and then reads $post->author->name in the Blade view, which is one extra query per row and looks perfectly clean in both files. Nothing fails, the page just gets slower as data grows. Write: 'Every query that feeds a loop must eager load its relationships with with(). Enable Model::preventLazyLoading in the non-production service provider so this throws during development.'
Agents skip Form Requests and mass assign whatever arrived, relying on $fillable as the only guard. That couples your validation to nothing and turns any new fillable column into an unintended write surface. Add: 'Every write endpoint has a dedicated FormRequest class. Pass $request->validated() into the model, never $request->all() or $request->input() collections.'
Agents create app/Http/Kernel.php to register middleware, add providers to config/app.php, or edit RouteServiceProvider to define route groups. In Laravel 11 and later those files are gone and the same registration happens in bootstrap/app.php, so the added code is simply never executed. State the version in your rules file and add: 'Middleware, exception handling, and routing configuration are registered in bootstrap/app.php. Do not create app/Http/Kernel.php.'
Agents call Mail::send or a third party HTTP client directly in the controller, so the user waits on an external service and a timeout becomes a failed request instead of a retry. Laravel's queue exists for exactly this and costs one interface to adopt. Add: 'Outbound email, webhooks, and third party API calls go into a job implementing ShouldQueue and are dispatched, never executed inline in a controller or an Eloquent event.'
Asked to add a column, an agent often finds the original create_table migration and edits it, which works on its own machine after a fresh migrate:fresh and leaves every teammate and every deployed environment without the column. Write the rule as an absolute: 'Never modify a migration that has been committed. Schema changes always get a new timestamped migration, and migrate:fresh is never suggested for an environment with real data.'
MCP gives the agent access to systems outside your codebase. These are the ones that pay off in a Laravel project.
| Server | What it does | Why here |
|---|---|---|
| Filesystem MCP server | Scoped read and write access to the application directory. | Laravel spreads one feature across routes, controllers, requests, models, and migrations, so the agent needs to see all five to place code correctly. |
| Git MCP server | History, diffs, and blame. | Blame on composer.json and the app skeleton tells the agent which Laravel major version's conventions this codebase actually follows. |
| A MySQL or Postgres MCP server | Schema inspection and read queries against the application database. | Real schema access stops the agent from guessing column names that Eloquent's magic accessors would otherwise hide until runtime. |
| Playwright MCP server | Drives a browser through the running application. | Blade, Livewire, and Inertia flows involve session state and redirects that only a real browser round trip exercises. |
| Sentry MCP server | Reads issues and stack traces from your Sentry project. | Failed queue jobs and exception traces are where Laravel bugs actually surface, well after the request that caused them. |
Connect
Connect Claude to any app. Send emails, create issues, post messages, update databases - take real actions across Gmail, Slack, GitHub, Notion, and 1000+ services.
great_cto
Claude Code plugin: 7 specialised subagents (tech-lead, senior-dev, qa-engineer, security-officer, devops, l3-support, project-auditor) orchestrating a full SDLC pipeline — architecture, TDD, 12-angle code review, QA, security audit, deploy. 11 project archetypes auto-detected, 13 compliance frameworks (GDPR/PCI-DSS/HIPAA/SOC2/ISO 27001), self-improving knowledge layer that learns from every incident.
iOS Simulator
Enables Claude to interact with iOS Simulator for testing and debugging iOS applications.
Playwright Browser Automation
Model-invoked Playwright automation for testing and validating web applications.
pypict-claude-skill
Design comprehensive test cases using PICT (Pairwise Independent Combinatorial Testing) for requirements or code, generating optimized test suites with pairwise coverage.
subagent-driven-development
Dispatches independent subagents for individual tasks with code review checkpoints between iterations for rapid, controlled development.
Rules files help, but they cannot fix sprawling architecture. A conventional Laravel codebase gets more out of an agent than a clever one does.