Production-grade coding standards for Laravel 13 + PHP 8.4+, written as instructions for AI coding agents (Claude Code, GitHub Copilot, Cursor, Windsurf, Aider, etc.).
The goal: give any agent enough context to produce code that is readable, reusable, secure, well-typed, and consistent — without re-explaining conventions in every prompt.
agent-instructions.md— the always-loaded core: top 10 non-negotiable rules, project structure, decision tree, naming quick reference, and a routing table to the sub-docs.docs/agent-conventions/— 27 focused topic files. Agents load them on demand based on the current task.
The split keeps the always-loaded context small while letting agents pull in deep detail only when it's relevant.
Point your agent at agent-instructions.md as the primary context. It tells the agent which sub-doc to load for any given task.
Claude Code — copy agent-instructions.md into your project's CLAUDE.md, or reference it directly:
@agent-instructions.md
GitHub Copilot — rename/copy agent-instructions.md to .github/copilot-instructions.md.
Cursor / Windsurf — add as a project rule (.cursorrules / Windsurf rules) or reference in your prompt.
Any agent — paste the contents of agent-instructions.md into the system/context window. When the agent starts work, it will load the relevant sub-doc from docs/agent-conventions/ based on the task.
| Topic | File |
|---|---|
| Architecture (Action / Service / Job / Observer) | architecture.md |
| Naming conventions | naming.md |
| PHP types, SRP methods, exceptions | php-and-types.md |
| Database, models, migrations, queries | database.md |
| Controllers, Form Requests, Resources, API versioning | http-api.md |
| Security, headers, exception rendering | security.md |
| API auth (Sanctum / Passport), tokens, 2FA | api-auth.md |
| Roles, permissions, spatie/laravel-permission | permissions-roles.md |
| Outbound HTTP, retries, circuit breaker | outbound-http.md |
| Rate limiting, throttling | rate-limiting.md |
| Eager loading, caching, race conditions | performance-caching.md |
| Queues, Jobs, Events, Listeners, Observers | async.md |
| Testing (Pest / PHPUnit) | testing.md |
| Enums (bensampo/laravel-enum) | enums-bensampo.md |
| Form Requests, custom validation rules | validation-rules.md |
| Logging, config patterns | logging-config.md |
| DI, traits, comments policy, feature flags | support.md |
| File uploads, Storage, signed URLs | file-storage.md |
| Notifications, Mailables | notifications-mail.md |
| Localization (spatie/laravel-translatable) | localization.md |
| Artisan commands, scheduler | console-scheduler.md |
| Webhooks (inbound + outbound) | webhooks.md |
| Dates, time zones, money, decimals | dates-and-money.md |
| Git, branches, PR, env, deployment | git-and-deployment.md |
| Observability (Sentry, OTel, metrics) | observability.md |
| Canonical code examples | code-examples.md |
| What NOT to do | anti-patterns.md |
When rules conflict: Correctness > Readability > SRP > Performance > Cleverness.
Top non-negotiables (the full list is in agent-instructions.md):
declare(strict_types=1);at the top of every PHP file.final classby default.- Form Requests validate; controllers never inline-validate.
- Controllers return
JsonResource, never raw Eloquent models. bensampo/laravel-enum— no native PHP 8.1enum.$fillablewhitelist only; never$guarded = [].config()notenv()outsideconfig/*.php.- Business logic lives in Actions / Services; controllers stay thin.
- Method ≤ 20 lines, class ≤ 250 lines, ≤ 4 params, nesting ≤ 3.
- Constructor-inject dependencies — no
app()/resolve()/ facades in business code.
Laravel Pint · Larastan/PHPStan (level 8 new, 6+ legacy) · Pest · spatie/laravel-data · bensampo/laravel-enum · spatie/laravel-translatable · spatie/laravel-permission.
CI gates: composer validate --strict · pint --test · phpstan analyse · pest --coverage --min=80.
Fork it. The rules are opinionated — adjust the parts that don't fit your house style, but keep the structure: one always-loaded core + on-demand sub-docs. That's what keeps the agent's context budget small while still giving it deep references when it needs them.
When you change a rule, change it in one place. The core file links out to sub-docs, so there's no duplication to drift.
See CONTRIBUTING.md.
MIT.