- 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.
- To run tests, ALWAYS delegate to the
test-runnersubagent via Task tool. Do not runvendor/bin/sail artisan testdirectly — it pollutes your context with long output. - 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.
- If you made changes to CSS/Javascript files or added new Tailwind classes in Blade, run
npm run buildafter all front-end changes are finished.
This project uses the mem0 skill for persistent memory across sessions. ACTIVELY use mem0 — do not wait to be asked. The skill handles the API mechanics;
- In PHP, use
matchoperator overswitchwhenever possible - Generate Enums always in the folder
app/Enums, not in the mainapp/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.
- Always run Laravel-related CLI commands using Sail: prefix commands with
./vendor/bin/sail.- Use
./vendor/bin/sail artisan migrateinstead ofphp artisan migrate - Use
./vendor/bin/sail artisan testinstead ofphp artisan test - Use
./vendor/bin/sail artisan make:model Userinstead ofphp artisan make:model User - Use
./vendor/bin/sail composer installinstead ofcomposer install - Use
./vendor/bin/sail npm run buildinstead ofnpm run build
- Use
- Never assume global PHP, Composer, or Node execution. Always run commands inside the Sail container.
- Eloquent Observers should be registered in Eloquent Models with PHP Attributes, and not in AppServiceProvider. Example:
#[ObservedBy([UserObserver::class])]withuse Illuminate\Database\Eloquent\Attributes\ObservedBy;on top - Aim for "slim" Controllers/Components and put larger logic pieces in Service classes
- Use Laravel helpers instead of
usesection classes. Examples: useauth()->id()instead ofAuth::id()and addingAuthin theusesection. Other examples: useredirect()->route()instead ofRedirect::route(), orstr()->slug()instead ofStr::slug(). - Don't use
whereKey()orwhereKeyNot(), use specific fields likeid. Example: instead of->whereKeyNot($currentUser->getKey()), use->where('id', '!=', $currentUser->id). - Don't add
::query()when running Eloquentcreate()statements. Example: instead ofUser::query()->create(), useUser::create(). - When adding columns in a migration, update the model's
$fillablearray to include those new attributes. - Never chain multiple migration-creating commands (e.g.,
make:model -m,make:migration) with&∨— 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. - Don't create Controllers with just one method which just returns
view(). Instead, useRoute::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 ofselectedandcheckedHTML attributes. Good example: @selected(old('status') === App\Enums\ProjectStatus::Pending->value). Bad example: {{ old('status') === App\Enums\ProjectStatus::Pending->value ? 'selected' : '' }}.
- Use Service classes to encapsulate reusable business logic, keeping Controllers and Livewire Components slim.
- Service classes MUST be created in the
app/Services/folder. - If a Service is used in only ONE method of a Controller or Component, inject it directly into that method via type-hinting. If it is used in MULTIPLE methods, initialize it in the Constructor (or
mount()/boot()for Livewire Components). - The same injection rule applies to both traditional Controllers and Livewire Components — use
mount()orboot()to inject Services in Components when needed across multiple methods, or inject directly into the action method. - Services MUST NOT contain presentation logic (views, redirects, flash messages). Return data or throw exceptions, and let the Controller/Component decide how to present the result.
- Services MUST be independently testable — avoid coupling with
request(),session(), orauth()directly. Receive those values as parameters instead.
Regra de ouro: Laravel AI SDK (
laravel/ai) já é a camada de abstração. Não envelope o SDK atrás de interfaces/DTOs custom em nome de "testabilidade" — a testabilidade vem do container.Sempre que for tocar em código de LLM/Agent, ative a skill
ai-sdk-development(.claude/skills/ai-sdk-development/SKILL.md).
- Localização: Agents moram em
app/Ai/Agents/. Nunca emapp/Services/. A pastaapp/Services/Ai/não deve existir. - Contratos obrigatórios: toda Agent class MUST
implements Laravel\Ai\Contracts\Agent. Se retorna JSON estruturado, tambémimplements Laravel\Ai\Contracts\HasStructuredOutput. Sempreuse Laravel\Ai\Promptable. - System prompt: uma
public const SYSTEM_PROMPTretornada porinstructions(): string. Não embutir o prompt inline em$this->prompt(...). - Schema: definido em
schema(\Illuminate\Contracts\JsonSchema\JsonSchema $schema): arrayusando o builder tipado —$schema->object(fn ($s) => [...]),$schema->string()->enum([...])->nullable()->required(),$schema->array()->max(N)->items(...). Proibido retornar arrays JSON-Schema crus (['type' => 'object', 'properties' => ...]). - Métodos públicos por fluxo: ex.
analyzeText(string $query): StructuredAgentResponse,analyzeImage(string $imagePath): StructuredAgentResponse. Chamam$this->prompt(prompt: ..., attachments: ..., model: (string) config('worthly.llm.model'))diretamente. Não crie classesPromptBuilder/ProductAnalysisPromptseparadas. - Anexos: sempre via objetos do SDK —
\Laravel\Ai\Files\Image::fromStorage($path, disk: ...),Files\Pdf::fromStorage(...), etc. Nunca passar paths como string solta dentro de arrays. - Proibido criar:
- Interface
LlmClient(ou similar) envolvendo o SDK. - DTO
LlmResponse(ou similar) reembrulhandoStructuredAgentResponse. Use o retorno do SDK direto ($response->toArray(),$response->object). - Qualquer wrapper que chame
agent(...)->prompt(...)por baixo de uma fachada custom.
- Interface
- Service ↔ Agent: Services em
app/Services/orquestram (transação, persistência, quota, mapeamento de exceção). A chamada LLM mora dentro do Agent, não no Service. O Service injeta o Agent pelo construtor. - Erros do provider: capture
Throwableda chamada do Agent no Service e re-lance como exceção de domínio (ex.:LlmProviderException). Não vaze tipos do SDK para fora do Service. - Testabilidade — esta é a única forma correta:
Não existe
$fake = new class extends ProductReviewer { public function analyzeText(string $query): StructuredAgentResponse { /* canned */ } }; $this->app->instance(ProductReviewer::class, $fake);
LlmClientpara mockar. Não useMockeryno SDK. Se sentir necessidade de "abstrair para testar", pare e releia este bloco. - Configuração de modelo: sempre
(string) config('worthly.llm.model')(ou config equivalente do projeto) dentro do Agent. Não hardcode string de modelo.
- Models MUST define the
$fillableproperty correctly for all mass-assignable attributes. - When adding new columns via migration, you MUST update the corresponding Model
$fillablearray. - Relationships MUST follow Laravel naming conventions (
user(),orders(),profile(), etc.). - Relationship methods MUST use correct return types (
HasMany,BelongsTo,HasOne, etc.). - All relationships MUST have their inverse defined when applicable.
- If
UserhasManyOrder, thenOrderMUST definebelongsTo(User::class). - If
UserhasOneProfile, thenProfileMUST definebelongsTo(User::class).
- If
- Do not assume foreign key naming. Explicitly define foreign keys if they don't follow Laravel conventions.
- If a column represents a domain concept backed by an Enum, the Model MUST cast it using
$casts.
-
Check database schema - Use
database-schematool to understand:- Which columns have defaults
- Which columns are nullable
- Foreign key relationship names
-
Verify relationship names - Read the model file to confirm:
- Exact relationship method names (not assumed from column names)
- Return types and related models
-
Test realistic states - Don't assume:
- Empty model = all nulls (check for defaults)
user_idforeign key =user()relationship (could beauthor(),employer(), etc.)- When testing form submissions that redirect back with errors, assert that old input is preserved using
assertSessionHasOldInput().
=== foundation rules ===
The Laravel Boost guidelines are specifically curated by Laravel maintainers for this application. These guidelines should be followed closely to ensure the best experience when building Laravel applications.
This application is a Laravel application and its main Laravel ecosystems package & versions are below. You are an expert with them all. Ensure you abide by these specific packages & versions.
- php - 8.5
- laravel/ai (AI) - v0
- laravel/framework (LARAVEL) - v13
- laravel/prompts (PROMPTS) - v0
- laravel/sail (SAIL) - v1
- laravel/sanctum (SANCTUM) - v4
- laravel/boost (BOOST) - v2
- laravel/mcp (MCP) - v0
- laravel/pail (PAIL) - v1
- laravel/pint (PINT) - v1
- pestphp/pest (PEST) - v4
- phpunit/phpunit (PHPUNIT) - v12
This project has domain-specific skills available in **/skills/**. You MUST activate the relevant skill whenever you work in that domain—don't wait until you're stuck.
- You must follow all existing code conventions used in this application. When creating or editing a file, check sibling files for the correct structure, approach, and naming.
- Use descriptive names for variables and methods. For example,
isRegisteredForDiscounts, notdiscount(). - Check for existing components to reuse before writing a new one.
- Do not create verification scripts or tinker when tests cover that functionality and prove they work. Unit and feature tests are more important.
- Stick to existing directory structure; don't create new base folders without approval.
- Do not change the application's dependencies without approval.
- If the user doesn't see a frontend change reflected in the UI, it could mean they need to run
vendor/bin/sail npm run build,vendor/bin/sail npm run dev, orvendor/bin/sail composer run dev. Ask them.
- You must only create documentation files if explicitly requested by the user.
- Be concise in your explanations - focus on what's important rather than explaining obvious details.
=== boost rules ===
- Laravel Boost is an MCP server with tools designed specifically for this application. Prefer Boost tools over manual alternatives like shell commands or file reads.
- Use
database-queryto run read-only queries against the database instead of writing raw SQL in tinker. - Use
database-schemato inspect table structure before writing migrations or models. - Use
get-absolute-urlto resolve the correct scheme, domain, and port for project URLs. Always use this before sharing a URL with the user. - Use
browser-logsto read browser logs, errors, and exceptions. Only recent logs are useful, ignore old entries.
- Always use
search-docsbefore making code changes. Do not skip this step. It returns version-specific docs based on installed packages automatically. - Pass a
packagesarray to scope results when you know which packages are relevant. - Use multiple broad, topic-based queries:
['rate limiting', 'routing rate limiting', 'routing']. Expect the most relevant results first. - Do not add package names to queries because package info is already shared. Use
test resource table, notfilament 4 test resource table.
- Use words for auto-stemmed AND logic:
rate limitmatches both "rate" AND "limit". - Use
"quoted phrases"for exact position matching:"infinite scroll"requires adjacent words in order. - Combine words and phrases for mixed queries:
middleware "rate limit". - Use multiple queries for OR logic:
queries=["authentication", "middleware"].
- Run Artisan commands directly via the command line (e.g.,
vendor/bin/sail artisan route:list). Usevendor/bin/sail artisan listto discover available commands andvendor/bin/sail artisan [command] --helpto check parameters. - Inspect routes with
vendor/bin/sail artisan route:list. Filter with:--method=GET,--name=users,--path=api,--except-vendor,--only-vendor. - Read configuration values using dot notation:
vendor/bin/sail artisan config:show app.name,vendor/bin/sail artisan config:show database.default. Or read config files directly from theconfig/directory. - To check environment variables, read the
.envfile directly.
- Execute PHP in app context for debugging and testing code. Do not create models without user approval, prefer tests with factories instead. Prefer existing Artisan commands over custom tinker code.
- Always use single quotes to prevent shell expansion:
vendor/bin/sail artisan tinker --execute 'Your::code();'- Double quotes for PHP strings inside:
vendor/bin/sail artisan tinker --execute 'User::where("active", true)->count();'
- Double quotes for PHP strings inside:
=== php rules ===
- Always use curly braces for control structures, even for single-line bodies.
- Use PHP 8 constructor property promotion:
public function __construct(public GitHub $github) { }. Do not leave empty zero-parameter__construct()methods unless the constructor is private. - Use explicit return type declarations and type hints for all method parameters:
function isAccessible(User $user, ?string $path = null): bool - Use TitleCase for Enum keys:
FavoritePerson,BestLake,Monthly. - Prefer PHPDoc blocks over inline comments. Only add inline comments for exceptionally complex logic.
- Use array shape type definitions in PHPDoc blocks.
=== deployments rules ===
- Laravel can be deployed using Laravel Cloud, which is the fastest way to deploy and scale production Laravel applications.
=== sail rules ===
- This project runs inside Laravel Sail's Docker containers. You MUST execute all commands through Sail.
- Start services using
vendor/bin/sail up -dand stop them withvendor/bin/sail stop. - Open the application in the browser by running
vendor/bin/sail open. - Always prefix PHP, Artisan, Composer, and Node commands with
vendor/bin/sail. Examples:- Run Artisan Commands:
vendor/bin/sail artisan migrate - Install Composer packages:
vendor/bin/sail composer install - Execute Node commands:
vendor/bin/sail npm run dev - Execute PHP scripts:
vendor/bin/sail php [script]
- Run Artisan Commands:
- View all available Sail commands by running
vendor/bin/sailwithout arguments.
=== laravel/core rules ===
- Use
vendor/bin/sail artisan make:commands to create new files (i.e. migrations, controllers, models, etc.). You can list available Artisan commands usingvendor/bin/sail artisan listand check their parameters withvendor/bin/sail artisan [command] --help. - If you're creating a generic PHP class, use
vendor/bin/sail artisan make:class. - Pass
--no-interactionto all Artisan commands to ensure they work without user input. You should also pass the correct--optionsto ensure correct behavior.
- When creating new models, create useful factories and seeders for them too. Ask the user if they need any other things, using
vendor/bin/sail artisan make:model --helpto check the available options.
- For APIs, default to using Eloquent API Resources and API versioning unless existing API routes do not, then you should follow existing application convention.
- When generating links to other pages, prefer named routes and the
route()function.
- When creating models for tests, use the factories for the models. Check if the factory has custom states that can be used before manually setting up the model.
- Faker: Use methods such as
$this->faker->word()orfake()->randomDigit(). Follow existing conventions whether to use$this->fakerorfake(). - When creating tests, make use of
vendor/bin/sail artisan make:test [options] {name}to create a feature test, and pass--unitto create a unit test. Most tests should be feature tests.
- If you receive an "Illuminate\Foundation\ViteException: Unable to locate file in Vite manifest" error, you can run
vendor/bin/sail npm run buildor ask the user to runvendor/bin/sail npm run devorvendor/bin/sail composer run dev.
=== pint/core rules ===
- If you have modified any PHP files, you must run
vendor/bin/sail bin pint --dirty --format agentbefore finalizing changes to ensure your code matches the project's expected style. - Do not run
vendor/bin/sail bin pint --test --format agent, simply runvendor/bin/sail bin pint --format agentto fix any formatting issues.
=== pest/core rules ===
- This project uses Pest for testing. Create tests:
vendor/bin/sail artisan make:test --pest {name}. - The
{name}argument should not include the test suite directory. Usevendor/bin/sail artisan make:test --pest SomeFeatureTestinstead ofvendor/bin/sail artisan make:test --pest Feature/SomeFeatureTest. - Run tests:
vendor/bin/sail artisan test --compactor filter:vendor/bin/sail artisan test --compact --filter=testName. - Do NOT delete tests without approval.