From c9755c7834d8413310ef9e3a0c7269577ef5d2dd Mon Sep 17 00:00:00 2001 From: Sebastian Fix Date: Mon, 2 Mar 2026 21:06:48 +0100 Subject: [PATCH 1/5] Heavily updated package to v1.2.0 --- .github/prompts/actions.prompt.yml | 16 - .github/prompts/albatros.prompt.yml | 16 - .github/prompts/blade.prompt.yml | 16 - .github/prompts/commands.prompt.yml | 16 - .github/prompts/controllers.prompt.yml | 16 - .github/prompts/design.prompt.yml | 16 - .github/prompts/docuware.prompt.yml | 16 - .github/prompts/dto.prompt.yml | 16 - .github/prompts/dusk.prompt.yml | 16 - .github/prompts/enums.prompt.yml | 16 - .github/prompts/events.prompt.yml | 16 - .github/prompts/exceptions.prompt.yml | 16 - .github/prompts/formrequests.prompt.yml | 17 -- .github/prompts/general.prompt.yml | 16 - .github/prompts/helperfunctions.prompt.yml | 16 - .github/prompts/helpers.prompt.yml | 16 - .github/prompts/interfaces.prompt.yml | 16 - .github/prompts/jobs.prompt.yml | 16 - .github/prompts/livewire.prompt.yml | 16 - .github/prompts/middleware.prompt.yml | 16 - .github/prompts/migrations.prompt.yml | 16 - .github/prompts/models.prompt.yml | 16 - .github/prompts/observers.prompt.yml | 16 - .github/prompts/pesttesting.prompt.yml | 16 - .github/prompts/php.prompt.yml | 16 - .github/prompts/phpstan.prompt.yml | 16 - .github/prompts/phpunit.prompt.yml | 16 - .github/prompts/policies.prompt.yml | 16 - .github/prompts/requests.prompt.yml | 16 - .github/prompts/resources.prompt.yml | 16 - .github/prompts/routing.prompt.yml | 16 - .github/prompts/saloon.prompt.yml | 16 - .github/prompts/services.prompt.yml | 16 - .github/prompts/tailwind.prompt.yml | 16 - .github/prompts/traits.prompt.yml | 16 - .github/prompts/translations.prompt.yml | 16 - .github/scripts/validate-skill-response.sh | 133 --------- .github/workflows/ci.yml | 30 -- .github/workflows/skill-integration.yml | 85 ------ .github/workflows/skills-validation.yml | 34 +++ .gitignore | 4 + AGENTS.md | 120 ++++++++ README.md | 280 +++++++++++++----- RULES.md | 7 + composer.json | 38 +-- .../mermaid/phpstan-analysis-flow.mmd | 13 + docs/concepts/mermaid/skill-template-flow.mmd | 7 + docs/skills/template-skill.md | 167 +++++++++++ phpunit.xml.dist | 19 ++ prompts/skill-validation.md | 51 ++++ refactor.md | 118 -------- resources/boost/skills/actions/SKILL.md | 97 ++++-- resources/boost/skills/albatros/SKILL.md | 5 + resources/boost/skills/blade/SKILL.md | 4 + resources/boost/skills/commands/SKILL.md | 5 + resources/boost/skills/controllers/SKILL.md | 96 ++++-- resources/boost/skills/design/SKILL.md | 4 + resources/boost/skills/documentation/SKILL.md | 118 ++++++++ resources/boost/skills/docuware/SKILL.md | 5 + resources/boost/skills/dto/SKILL.md | 5 + resources/boost/skills/dusk/SKILL.md | 4 + resources/boost/skills/enums/SKILL.md | 5 + resources/boost/skills/events/SKILL.md | 5 + resources/boost/skills/exceptions/SKILL.md | 5 + resources/boost/skills/formrequests/SKILL.md | 4 + resources/boost/skills/general/SKILL.md | 9 + .../boost/skills/helperfunctions/SKILL.md | 5 + resources/boost/skills/helpers/SKILL.md | 5 + resources/boost/skills/interfaces/SKILL.md | 5 + resources/boost/skills/jobs/SKILL.md | 5 + resources/boost/skills/livewire/SKILL.md | 4 + resources/boost/skills/middleware/SKILL.md | 4 + resources/boost/skills/migrations/SKILL.md | 5 + resources/boost/skills/models/SKILL.md | 90 ++++-- resources/boost/skills/observers/SKILL.md | 5 + resources/boost/skills/pesttesting/SKILL.md | 4 + resources/boost/skills/php/SKILL.md | 5 + resources/boost/skills/phpstan/SKILL.md | 81 +++-- resources/boost/skills/phpunit/SKILL.md | 4 + resources/boost/skills/policies/SKILL.md | 5 + resources/boost/skills/requests/SKILL.md | 4 + resources/boost/skills/resources/SKILL.md | 4 + resources/boost/skills/routing/SKILL.md | 5 + resources/boost/skills/saloon/SKILL.md | 5 + resources/boost/skills/services/SKILL.md | 86 ++++-- resources/boost/skills/tailwind/SKILL.md | 4 + resources/boost/skills/traits/SKILL.md | 5 + resources/boost/skills/translations/SKILL.md | 4 + scripts/sync-guidelines.php | 45 --- scripts/validate-skills.php | 74 ----- src/CodingGuidelinesServiceProvider.php | 33 --- src/Composer/RefactorCommandPlugin.php | 60 ---- src/Console/SyncRefactorCommand.php | 33 --- src/Support/RefactorCommandSynchronizer.php | 53 ---- tests/Feature/SkillValidationTest.php | 87 ++++++ tests/Pest.php | 7 + tests/Support/Agents/SkillQualityAgent.php | 76 +++++ tests/TestCase.php | 23 ++ 98 files changed, 1456 insertions(+), 1433 deletions(-) delete mode 100644 .github/prompts/actions.prompt.yml delete mode 100644 .github/prompts/albatros.prompt.yml delete mode 100644 .github/prompts/blade.prompt.yml delete mode 100644 .github/prompts/commands.prompt.yml delete mode 100644 .github/prompts/controllers.prompt.yml delete mode 100644 .github/prompts/design.prompt.yml delete mode 100644 .github/prompts/docuware.prompt.yml delete mode 100644 .github/prompts/dto.prompt.yml delete mode 100644 .github/prompts/dusk.prompt.yml delete mode 100644 .github/prompts/enums.prompt.yml delete mode 100644 .github/prompts/events.prompt.yml delete mode 100644 .github/prompts/exceptions.prompt.yml delete mode 100644 .github/prompts/formrequests.prompt.yml delete mode 100644 .github/prompts/general.prompt.yml delete mode 100644 .github/prompts/helperfunctions.prompt.yml delete mode 100644 .github/prompts/helpers.prompt.yml delete mode 100644 .github/prompts/interfaces.prompt.yml delete mode 100644 .github/prompts/jobs.prompt.yml delete mode 100644 .github/prompts/livewire.prompt.yml delete mode 100644 .github/prompts/middleware.prompt.yml delete mode 100644 .github/prompts/migrations.prompt.yml delete mode 100644 .github/prompts/models.prompt.yml delete mode 100644 .github/prompts/observers.prompt.yml delete mode 100644 .github/prompts/pesttesting.prompt.yml delete mode 100644 .github/prompts/php.prompt.yml delete mode 100644 .github/prompts/phpstan.prompt.yml delete mode 100644 .github/prompts/phpunit.prompt.yml delete mode 100644 .github/prompts/policies.prompt.yml delete mode 100644 .github/prompts/requests.prompt.yml delete mode 100644 .github/prompts/resources.prompt.yml delete mode 100644 .github/prompts/routing.prompt.yml delete mode 100644 .github/prompts/saloon.prompt.yml delete mode 100644 .github/prompts/services.prompt.yml delete mode 100644 .github/prompts/tailwind.prompt.yml delete mode 100644 .github/prompts/traits.prompt.yml delete mode 100644 .github/prompts/translations.prompt.yml delete mode 100755 .github/scripts/validate-skill-response.sh delete mode 100644 .github/workflows/ci.yml delete mode 100644 .github/workflows/skill-integration.yml create mode 100644 .github/workflows/skills-validation.yml create mode 100644 AGENTS.md create mode 100644 docs/concepts/mermaid/phpstan-analysis-flow.mmd create mode 100644 docs/concepts/mermaid/skill-template-flow.mmd create mode 100644 docs/skills/template-skill.md create mode 100644 phpunit.xml.dist create mode 100644 prompts/skill-validation.md delete mode 100644 refactor.md create mode 100644 resources/boost/skills/documentation/SKILL.md delete mode 100644 scripts/sync-guidelines.php delete mode 100644 scripts/validate-skills.php delete mode 100644 src/CodingGuidelinesServiceProvider.php delete mode 100644 src/Composer/RefactorCommandPlugin.php delete mode 100644 src/Console/SyncRefactorCommand.php delete mode 100644 src/Support/RefactorCommandSynchronizer.php create mode 100644 tests/Feature/SkillValidationTest.php create mode 100644 tests/Pest.php create mode 100644 tests/Support/Agents/SkillQualityAgent.php create mode 100644 tests/TestCase.php diff --git a/.github/prompts/actions.prompt.yml b/.github/prompts/actions.prompt.yml deleted file mode 100644 index 8365cbe..0000000 --- a/.github/prompts/actions.prompt.yml +++ /dev/null @@ -1,16 +0,0 @@ -messages: - - role: system - content: | - You are a Laravel developer. Apply these guidelines exactly: - - {{skill_content}} - - Respond with only the requested code. No explanations unless asked. - - role: user - content: | - Write a CreateInvoice Action class. It receives an Order, creates an Invoice, and returns it. - Use execute() method and constructor dependency injection. No HTTP concerns. -model: openai/gpt-4o-mini -modelParameters: - temperature: 0.2 - maxCompletionTokens: 512 diff --git a/.github/prompts/albatros.prompt.yml b/.github/prompts/albatros.prompt.yml deleted file mode 100644 index a7f257d..0000000 --- a/.github/prompts/albatros.prompt.yml +++ /dev/null @@ -1,16 +0,0 @@ -messages: - - role: system - content: | - You are a Laravel developer. Apply these guidelines exactly: - - {{skill_content}} - - Respond with only the requested code. No explanations unless asked. - - role: user - content: | - Write an AlbatrosConnector extending Saloon Connector. Use config('albatros.base_url'), Mandant header, Bearer token. - Use Cache for reference data. German domain terms in DTOs are acceptable. -model: openai/gpt-4o-mini -modelParameters: - temperature: 0.2 - maxCompletionTokens: 512 diff --git a/.github/prompts/blade.prompt.yml b/.github/prompts/blade.prompt.yml deleted file mode 100644 index 4f7402f..0000000 --- a/.github/prompts/blade.prompt.yml +++ /dev/null @@ -1,16 +0,0 @@ -messages: - - role: system - content: | - You are a Laravel developer. Apply these guidelines exactly: - - {{skill_content}} - - Respond with only the requested code. No explanations unless asked. - - role: user - content: | - Write a Blade component that displays a user's name and email. Use {{ }} for escaped output. - No inline style or script tags. Use x-component syntax. -model: openai/gpt-4o-mini -modelParameters: - temperature: 0.2 - maxCompletionTokens: 384 diff --git a/.github/prompts/commands.prompt.yml b/.github/prompts/commands.prompt.yml deleted file mode 100644 index 7339676..0000000 --- a/.github/prompts/commands.prompt.yml +++ /dev/null @@ -1,16 +0,0 @@ -messages: - - role: system - content: | - You are a Laravel developer. Apply these guidelines exactly: - - {{skill_content}} - - Respond with only the requested code. No explanations unless asked. - - role: user - content: | - Write an Artisan command invoices:send-reminders with required email argument and --dry-run option. - Delegate to SendInvoiceReminderAction. Return self::SUCCESS or self::FAILURE. Validate input. -model: openai/gpt-4o-mini -modelParameters: - temperature: 0.2 - maxCompletionTokens: 512 diff --git a/.github/prompts/controllers.prompt.yml b/.github/prompts/controllers.prompt.yml deleted file mode 100644 index 0b30014..0000000 --- a/.github/prompts/controllers.prompt.yml +++ /dev/null @@ -1,16 +0,0 @@ -messages: - - role: system - content: | - You are a Laravel developer. Apply these guidelines exactly: - - {{skill_content}} - - Respond with only the requested code. No explanations unless asked. - - role: user - content: | - Write an invokable StoreInvoiceController that receives StoreInvoiceRequest, calls a CreateInvoice action, - and returns a JsonResponse with InvoiceResource. No business logic in the controller. -model: openai/gpt-4o-mini -modelParameters: - temperature: 0.2 - maxCompletionTokens: 512 diff --git a/.github/prompts/design.prompt.yml b/.github/prompts/design.prompt.yml deleted file mode 100644 index f658312..0000000 --- a/.github/prompts/design.prompt.yml +++ /dev/null @@ -1,16 +0,0 @@ -messages: - - role: system - content: | - You are a Laravel developer. Apply these guidelines exactly: - - {{skill_content}} - - Respond with only the requested code. No explanations unless asked. - - role: user - content: | - Write an anonymous Blade button component with @props for variant and size. Merge $attributes with defaults. - Use min-h-[44px] for touch target, focus-visible:ring-2. Mobile-first. -model: openai/gpt-4o-mini -modelParameters: - temperature: 0.2 - maxCompletionTokens: 512 diff --git a/.github/prompts/docuware.prompt.yml b/.github/prompts/docuware.prompt.yml deleted file mode 100644 index 513e1c3..0000000 --- a/.github/prompts/docuware.prompt.yml +++ /dev/null @@ -1,16 +0,0 @@ -messages: - - role: system - content: | - You are a Laravel developer. Apply these guidelines exactly: - - {{skill_content}} - - Respond with only the requested code. No explanations unless asked. - - role: user - content: | - Write a DocuWareService that wraps the DocuWare connector. Constructor accepts optional connector for testability. - Use config('laravel-docuware.credentials.*') not env(). Include fetchDocument or similar method signature. -model: openai/gpt-4o-mini -modelParameters: - temperature: 0.2 - maxCompletionTokens: 512 diff --git a/.github/prompts/dto.prompt.yml b/.github/prompts/dto.prompt.yml deleted file mode 100644 index 5579d6b..0000000 --- a/.github/prompts/dto.prompt.yml +++ /dev/null @@ -1,16 +0,0 @@ -messages: - - role: system - content: | - You are a Laravel developer. Apply these guidelines exactly: - - {{skill_content}} - - Respond with only the requested code. No explanations unless asked. - - role: user - content: | - Write a readonly CustomerData DTO with id, name, email. Include fromArray() factory that handles - PascalCase and snake_case API field names. Use nullable for optional fields. -model: openai/gpt-4o-mini -modelParameters: - temperature: 0.2 - maxCompletionTokens: 512 diff --git a/.github/prompts/dusk.prompt.yml b/.github/prompts/dusk.prompt.yml deleted file mode 100644 index 8f92d68..0000000 --- a/.github/prompts/dusk.prompt.yml +++ /dev/null @@ -1,16 +0,0 @@ -messages: - - role: system - content: | - You are a Laravel developer. Apply these guidelines exactly: - - {{skill_content}} - - Respond with only the requested code. No explanations unless asked. - - role: user - content: | - Write a Dusk test that logs in, visits /invoices/create, uses dusk="" selectors, calls assertNoJavaScriptErrors(). - Use DatabaseTruncation. Use loginAs(), waitForText, never pause(). -model: openai/gpt-4o-mini -modelParameters: - temperature: 0.2 - maxCompletionTokens: 512 diff --git a/.github/prompts/enums.prompt.yml b/.github/prompts/enums.prompt.yml deleted file mode 100644 index 85984b1..0000000 --- a/.github/prompts/enums.prompt.yml +++ /dev/null @@ -1,16 +0,0 @@ -messages: - - role: system - content: | - You are a Laravel developer. Apply these guidelines exactly: - - {{skill_content}} - - Respond with only the requested code. No explanations unless asked. - - role: user - content: | - Write a Status enum with Draft, Active, Archived. Include label() and color() methods using match expressions. - Use backed string enum. -model: openai/gpt-4o-mini -modelParameters: - temperature: 0.2 - maxCompletionTokens: 512 diff --git a/.github/prompts/events.prompt.yml b/.github/prompts/events.prompt.yml deleted file mode 100644 index 2c67ac5..0000000 --- a/.github/prompts/events.prompt.yml +++ /dev/null @@ -1,16 +0,0 @@ -messages: - - role: system - content: | - You are a Laravel developer. Apply these guidelines exactly: - - {{skill_content}} - - Respond with only the requested code. No explanations unless asked. - - role: user - content: | - Write an InvoicePaid event (plain data container with Invoice) and a SendInvoicePaidNotification listener. - Event uses Dispatchable, SerializesModels. Listener has single responsibility. Use past-tense for event name. -model: openai/gpt-4o-mini -modelParameters: - temperature: 0.2 - maxCompletionTokens: 512 diff --git a/.github/prompts/exceptions.prompt.yml b/.github/prompts/exceptions.prompt.yml deleted file mode 100644 index 493c99b..0000000 --- a/.github/prompts/exceptions.prompt.yml +++ /dev/null @@ -1,16 +0,0 @@ -messages: - - role: system - content: | - You are a Laravel developer. Apply these guidelines exactly: - - {{skill_content}} - - Respond with only the requested code. No explanations unless asked. - - role: user - content: | - Write an InvoiceAlreadyPaidException that extends RuntimeException. It receives an Invoice as readonly property - and sets a clear message via parent::__construct(). Use a named failure state. -model: openai/gpt-4o-mini -modelParameters: - temperature: 0.2 - maxCompletionTokens: 384 diff --git a/.github/prompts/formrequests.prompt.yml b/.github/prompts/formrequests.prompt.yml deleted file mode 100644 index 50dd9f9..0000000 --- a/.github/prompts/formrequests.prompt.yml +++ /dev/null @@ -1,17 +0,0 @@ -messages: - - role: system - content: | - You are a Laravel developer. Apply these guidelines exactly: - - {{skill_content}} - - Respond with only the requested code. No explanations unless asked. - - role: user - content: | - Write a StoreInvoiceRequest with authorize() and rules() returning array-based rules. - Rules: order_id required exists in orders, amount required numeric min 0. - Add PHPDoc @return for rules(). -model: openai/gpt-4o-mini -modelParameters: - temperature: 0.2 - maxCompletionTokens: 512 diff --git a/.github/prompts/general.prompt.yml b/.github/prompts/general.prompt.yml deleted file mode 100644 index eb0559e..0000000 --- a/.github/prompts/general.prompt.yml +++ /dev/null @@ -1,16 +0,0 @@ -messages: - - role: system - content: | - You are a Laravel developer. Apply these guidelines exactly: - - {{skill_content}} - - Respond with only the requested code. No explanations unless asked. - - role: user - content: | - Add a Stripe API key to the Laravel config and show how to read it in a controller. - Use the correct helper for config access. Show the config file addition and one line of controller code. -model: openai/gpt-4o-mini -modelParameters: - temperature: 0.2 - maxCompletionTokens: 512 diff --git a/.github/prompts/helperfunctions.prompt.yml b/.github/prompts/helperfunctions.prompt.yml deleted file mode 100644 index 9106477..0000000 --- a/.github/prompts/helperfunctions.prompt.yml +++ /dev/null @@ -1,16 +0,0 @@ -messages: - - role: system - content: | - You are a Laravel developer. Apply these guidelines exactly: - - {{skill_content}} - - Respond with only the requested code. No explanations unless asked. - - role: user - content: | - Write PHP code to filter an array of users to only active ones, then get their email addresses as a comma-separated string. - Use Laravel Arr and Str helpers instead of native PHP functions. -model: openai/gpt-4o-mini -modelParameters: - temperature: 0.2 - maxCompletionTokens: 512 diff --git a/.github/prompts/helpers.prompt.yml b/.github/prompts/helpers.prompt.yml deleted file mode 100644 index 9916643..0000000 --- a/.github/prompts/helpers.prompt.yml +++ /dev/null @@ -1,16 +0,0 @@ -messages: - - role: system - content: | - You are a Laravel developer. Apply these guidelines exactly: - - {{skill_content}} - - Respond with only the requested code. No explanations unless asked. - - role: user - content: | - Write a DateHelper class with a static format() method that accepts a date and format string, returns formatted string or null. - Use Carbon. No business logic, no database queries. PascalCase with Helper suffix. -model: openai/gpt-4o-mini -modelParameters: - temperature: 0.2 - maxCompletionTokens: 384 diff --git a/.github/prompts/interfaces.prompt.yml b/.github/prompts/interfaces.prompt.yml deleted file mode 100644 index 1474d0a..0000000 --- a/.github/prompts/interfaces.prompt.yml +++ /dev/null @@ -1,16 +0,0 @@ -messages: - - role: system - content: | - You are a Laravel developer. Apply these guidelines exactly: - - {{skill_content}} - - Respond with only the requested code. No explanations unless asked. - - role: user - content: | - Write a PaymentGateway interface in app/Contracts/ with charge(Order, int) and refund(string, int) methods. - Return a PaymentResult. No implementation. Clear noun describing the capability. -model: openai/gpt-4o-mini -modelParameters: - temperature: 0.2 - maxCompletionTokens: 384 diff --git a/.github/prompts/jobs.prompt.yml b/.github/prompts/jobs.prompt.yml deleted file mode 100644 index 49b05f9..0000000 --- a/.github/prompts/jobs.prompt.yml +++ /dev/null @@ -1,16 +0,0 @@ -messages: - - role: system - content: | - You are a Laravel developer. Apply these guidelines exactly: - - {{skill_content}} - - Respond with only the requested code. No explanations unless asked. - - role: user - content: | - Write a ProcessInvoicePaymentJob that implements ShouldQueue. Delegate to ProcessInvoicePayment action. - Use Dispatchable, InteractsWithQueue, Queueable, SerializesModels. Set tries, backoff, queue. Add failed() method. -model: openai/gpt-4o-mini -modelParameters: - temperature: 0.2 - maxCompletionTokens: 512 diff --git a/.github/prompts/livewire.prompt.yml b/.github/prompts/livewire.prompt.yml deleted file mode 100644 index 54e63c7..0000000 --- a/.github/prompts/livewire.prompt.yml +++ /dev/null @@ -1,16 +0,0 @@ -messages: - - role: system - content: | - You are a Laravel developer. Apply these guidelines exactly: - - {{skill_content}} - - Respond with only the requested code. No explanations unless asked. - - role: user - content: | - Write a Livewire InvoiceList component with search property, #[Computed] invoices(), and wire:model/wire:click. - Keep logic in PHP, template declarative. Use wire:model for search binding. -model: openai/gpt-4o-mini -modelParameters: - temperature: 0.2 - maxCompletionTokens: 512 diff --git a/.github/prompts/middleware.prompt.yml b/.github/prompts/middleware.prompt.yml deleted file mode 100644 index 290c471..0000000 --- a/.github/prompts/middleware.prompt.yml +++ /dev/null @@ -1,16 +0,0 @@ -messages: - - role: system - content: | - You are a Laravel developer. Apply these guidelines exactly: - - {{skill_content}} - - Respond with only the requested code. No explanations unless asked. - - role: user - content: | - Write an EnsureUserIsSubscribed middleware. If user is not subscribed, return 403 JSON response. - Otherwise call $next($request). Clear descriptive name. No business logic inside. -model: openai/gpt-4o-mini -modelParameters: - temperature: 0.2 - maxCompletionTokens: 384 diff --git a/.github/prompts/migrations.prompt.yml b/.github/prompts/migrations.prompt.yml deleted file mode 100644 index da7aeb7..0000000 --- a/.github/prompts/migrations.prompt.yml +++ /dev/null @@ -1,16 +0,0 @@ -messages: - - role: system - content: | - You are a Laravel developer. Apply these guidelines exactly: - - {{skill_content}} - - Respond with only the requested code. No explanations unless asked. - - role: user - content: | - Write a migration to create an invoices table with id, order_id (foreign key), status (string default draft), amount (decimal), timestamps. - Use foreignId()->constrained()->cascadeOnDelete(). Include both up() and down() methods. -model: openai/gpt-4o-mini -modelParameters: - temperature: 0.2 - maxCompletionTokens: 512 diff --git a/.github/prompts/models.prompt.yml b/.github/prompts/models.prompt.yml deleted file mode 100644 index 3ad494e..0000000 --- a/.github/prompts/models.prompt.yml +++ /dev/null @@ -1,16 +0,0 @@ -messages: - - role: system - content: | - You are a Laravel developer. Apply these guidelines exactly: - - {{skill_content}} - - Respond with only the requested code. No explanations unless asked. - - role: user - content: | - Write a minimal Invoice Eloquent model with guarded, casts as method, and a belongsTo Order relationship. - Use typed return type on the relationship. Include section comment headers. -model: openai/gpt-4o-mini -modelParameters: - temperature: 0.2 - maxCompletionTokens: 512 diff --git a/.github/prompts/observers.prompt.yml b/.github/prompts/observers.prompt.yml deleted file mode 100644 index 6596e0b..0000000 --- a/.github/prompts/observers.prompt.yml +++ /dev/null @@ -1,16 +0,0 @@ -messages: - - role: system - content: | - You are a Laravel developer. Apply these guidelines exactly: - - {{skill_content}} - - Respond with only the requested code. No explanations unless asked. - - role: user - content: | - Write a UserObserver with created() that sends WelcomeNotification, and updated()/deleted() that clear cache. - Use Observer suffix. Only define methods you need. No business logic. -model: openai/gpt-4o-mini -modelParameters: - temperature: 0.2 - maxCompletionTokens: 384 diff --git a/.github/prompts/pesttesting.prompt.yml b/.github/prompts/pesttesting.prompt.yml deleted file mode 100644 index 15faa12..0000000 --- a/.github/prompts/pesttesting.prompt.yml +++ /dev/null @@ -1,16 +0,0 @@ -messages: - - role: system - content: | - You are a Laravel developer. Apply these guidelines exactly: - - {{skill_content}} - - Respond with only the requested code. No explanations unless asked. - - role: user - content: | - Write a Pest test it('creates an invoice for the given order') with AAA pattern and Arrange/Act/Assert comments. - Use uses(RefreshDatabase::class), postJson, assertCreated(), expect()->toBe(). Plain English description. -model: openai/gpt-4o-mini -modelParameters: - temperature: 0.2 - maxCompletionTokens: 512 diff --git a/.github/prompts/php.prompt.yml b/.github/prompts/php.prompt.yml deleted file mode 100644 index e46c1b9..0000000 --- a/.github/prompts/php.prompt.yml +++ /dev/null @@ -1,16 +0,0 @@ -messages: - - role: system - content: | - You are a Laravel developer. Apply these guidelines exactly: - - {{skill_content}} - - Respond with only the requested code. No explanations unless asked. - - role: user - content: | - Write a process(Order $order) method with early returns. If !$order->isPaid() throw exception and return. - If !$order->hasItems() throw and return. Then happy-path logic. No else/elseif. Use guard clauses. -model: openai/gpt-4o-mini -modelParameters: - temperature: 0.2 - maxCompletionTokens: 512 diff --git a/.github/prompts/phpstan.prompt.yml b/.github/prompts/phpstan.prompt.yml deleted file mode 100644 index 4bcab75..0000000 --- a/.github/prompts/phpstan.prompt.yml +++ /dev/null @@ -1,16 +0,0 @@ -messages: - - role: system - content: | - You are a Laravel developer. Apply these guidelines exactly: - - {{skill_content}} - - Respond with only the requested code. No explanations unless asked. - - role: user - content: | - Write a method process(Order $order): Invoice with full type hints. Add PHPDoc @return array> for a rules() method. - Use union types instead of mixed. No @phpstan-ignore. -model: openai/gpt-4o-mini -modelParameters: - temperature: 0.2 - maxCompletionTokens: 512 diff --git a/.github/prompts/phpunit.prompt.yml b/.github/prompts/phpunit.prompt.yml deleted file mode 100644 index 4f079f8..0000000 --- a/.github/prompts/phpunit.prompt.yml +++ /dev/null @@ -1,16 +0,0 @@ -messages: - - role: system - content: | - You are a Laravel developer. Apply these guidelines exactly: - - {{skill_content}} - - Respond with only the requested code. No explanations unless asked. - - role: user - content: | - Write a feature test test_user_can_create_invoice. Use RefreshDatabase, factories, actingAs. - Assert 201 and assertDatabaseHas. Use test_ prefix and : void return type. -model: openai/gpt-4o-mini -modelParameters: - temperature: 0.2 - maxCompletionTokens: 512 diff --git a/.github/prompts/policies.prompt.yml b/.github/prompts/policies.prompt.yml deleted file mode 100644 index fdfb351..0000000 --- a/.github/prompts/policies.prompt.yml +++ /dev/null @@ -1,16 +0,0 @@ -messages: - - role: system - content: | - You are a Laravel developer. Apply these guidelines exactly: - - {{skill_content}} - - Respond with only the requested code. No explanations unless asked. - - role: user - content: | - Write an InvoicePolicy with viewAny (admin only), view (owner or admin), create (authenticated). - Use Policy suffix. Standard ability names. -model: openai/gpt-4o-mini -modelParameters: - temperature: 0.2 - maxCompletionTokens: 512 diff --git a/.github/prompts/requests.prompt.yml b/.github/prompts/requests.prompt.yml deleted file mode 100644 index 4584210..0000000 --- a/.github/prompts/requests.prompt.yml +++ /dev/null @@ -1,16 +0,0 @@ -messages: - - role: system - content: | - You are a Laravel developer. Apply these guidelines exactly: - - {{skill_content}} - - Respond with only the requested code. No explanations unless asked. - - role: user - content: | - Write a StoreInvoiceRequest with authorize() using can('create', Invoice::class) and rules() with array-based definitions. - Add PHPDoc @return for rules(). Never use $request->validate() in controller. -model: openai/gpt-4o-mini -modelParameters: - temperature: 0.2 - maxCompletionTokens: 512 diff --git a/.github/prompts/resources.prompt.yml b/.github/prompts/resources.prompt.yml deleted file mode 100644 index c7e6db8..0000000 --- a/.github/prompts/resources.prompt.yml +++ /dev/null @@ -1,16 +0,0 @@ -messages: - - role: system - content: | - You are a Laravel developer. Apply these guidelines exactly: - - {{skill_content}} - - Respond with only the requested code. No explanations unless asked. - - role: user - content: | - Write a UserResource extending JsonResource. Return id, name, email, posts (whenLoaded), created_at (formatted). - Use whenLoaded for relations. Use when() for conditional admin-only secret field. -model: openai/gpt-4o-mini -modelParameters: - temperature: 0.2 - maxCompletionTokens: 512 diff --git a/.github/prompts/routing.prompt.yml b/.github/prompts/routing.prompt.yml deleted file mode 100644 index 5265a06..0000000 --- a/.github/prompts/routing.prompt.yml +++ /dev/null @@ -1,16 +0,0 @@ -messages: - - role: system - content: | - You are a Laravel developer. Apply these guidelines exactly: - - {{skill_content}} - - Respond with only the requested code. No explanations unless asked. - - role: user - content: | - Write API routes for invoices: index and store. Use auth:sanctum middleware, apiResource, and resourceful route names. - Group them properly. Use kebab-case for URL. -model: openai/gpt-4o-mini -modelParameters: - temperature: 0.2 - maxCompletionTokens: 384 diff --git a/.github/prompts/saloon.prompt.yml b/.github/prompts/saloon.prompt.yml deleted file mode 100644 index 9d01368..0000000 --- a/.github/prompts/saloon.prompt.yml +++ /dev/null @@ -1,16 +0,0 @@ -messages: - - role: system - content: | - You are a Laravel developer. Apply these guidelines exactly: - - {{skill_content}} - - Respond with only the requested code. No explanations unless asked. - - role: user - content: | - Write a StripeConnector extending Saloon Connector with resolveBaseUrl and defaultHeaders. - Write a ListChargesRequest for GET. No Http::get() or raw HTTP. Use Saloon pattern. -model: openai/gpt-4o-mini -modelParameters: - temperature: 0.2 - maxCompletionTokens: 512 diff --git a/.github/prompts/services.prompt.yml b/.github/prompts/services.prompt.yml deleted file mode 100644 index f8524a3..0000000 --- a/.github/prompts/services.prompt.yml +++ /dev/null @@ -1,16 +0,0 @@ -messages: - - role: system - content: | - You are a Laravel developer. Apply these guidelines exactly: - - {{skill_content}} - - Respond with only the requested code. No explanations unless asked. - - role: user - content: | - Write a PaymentService that orchestrates CreateInvoice, ChargePaymentMethod, SendPaymentConfirmation actions. - Method processOrderPayment(Order) uses DB::transaction. Inject actions via constructor. No Manager/Handler suffix. -model: openai/gpt-4o-mini -modelParameters: - temperature: 0.2 - maxCompletionTokens: 512 diff --git a/.github/prompts/tailwind.prompt.yml b/.github/prompts/tailwind.prompt.yml deleted file mode 100644 index 460c1e7..0000000 --- a/.github/prompts/tailwind.prompt.yml +++ /dev/null @@ -1,16 +0,0 @@ -messages: - - role: system - content: | - You are a Laravel developer. Apply these guidelines exactly: - - {{skill_content}} - - Respond with only the requested code. No explanations unless asked. - - role: user - content: | - Write the resources/css/app.css for Tailwind v4 with @theme directive setting --color-primary-500 and --font-sans. - Include @source for views and Livewire. No custom CSS classes. -model: openai/gpt-4o-mini -modelParameters: - temperature: 0.2 - maxCompletionTokens: 384 diff --git a/.github/prompts/traits.prompt.yml b/.github/prompts/traits.prompt.yml deleted file mode 100644 index dcf4a2e..0000000 --- a/.github/prompts/traits.prompt.yml +++ /dev/null @@ -1,16 +0,0 @@ -messages: - - role: system - content: | - You are a Laravel developer. Apply these guidelines exactly: - - {{skill_content}} - - Respond with only the requested code. No explanations unless asked. - - role: user - content: | - Write an Archivable trait with archive(), unarchive(), isArchived() methods for models with archived_at. - Use -able suffix. Single responsibility. No complex business logic. -model: openai/gpt-4o-mini -modelParameters: - temperature: 0.2 - maxCompletionTokens: 384 diff --git a/.github/prompts/translations.prompt.yml b/.github/prompts/translations.prompt.yml deleted file mode 100644 index b9ca04c..0000000 --- a/.github/prompts/translations.prompt.yml +++ /dev/null @@ -1,16 +0,0 @@ -messages: - - role: system - content: | - You are a Laravel developer. Apply these guidelines exactly: - - {{skill_content}} - - Respond with only the requested code. No explanations unless asked. - - role: user - content: | - Write lang/en/invoices.php with create_success key using :name placeholder. - Show usage with __('invoices.create_success', ['name' => $name]). Use namespaced keys. -model: openai/gpt-4o-mini -modelParameters: - temperature: 0.2 - maxCompletionTokens: 384 diff --git a/.github/scripts/validate-skill-response.sh b/.github/scripts/validate-skill-response.sh deleted file mode 100755 index 2de934a..0000000 --- a/.github/scripts/validate-skill-response.sh +++ /dev/null @@ -1,133 +0,0 @@ -#!/bin/bash -# Validates AI response against skill-specific rules. -# Usage: validate-skill-response.sh -# Exits 0 if valid, 1 if invalid. - -skill="$1" -response="$2" - -if [ -z "$response" ]; then - echo "::error::[$skill] Empty response" - exit 1 -fi - -case "$skill" in - general) - echo "$response" | grep -q 'env(' && { echo "::error::[$skill] Should use config() not env()"; exit 1; } - echo "$response" | grep -q 'config(' || { echo "::error::[$skill] Missing config()"; exit 1; } - ;; - helperfunctions) - echo "$response" | grep -qE 'Arr::|Str::|collect\(' || { echo "::error::[$skill] Should use Laravel helpers"; exit 1; } - ;; - models) - echo "$response" | grep -qE 'extends Model|BelongsTo|HasMany|HasOne' || { echo "::error::[$skill] Needs Model with relationship"; exit 1; } - ;; - controllers) - echo "$response" | grep -qE '__invoke|JsonResponse' || { echo "::error::[$skill] Needs invokable or JsonResponse"; exit 1; } - ;; - migrations) - echo "$response" | grep -qE 'foreignId|constrained|cascadeOnDelete' || { echo "::error::[$skill] Needs proper foreign key"; exit 1; } - echo "$response" | grep -qE 'function (up|down)\s*\(\)' || { echo "::error::[$skill] Needs up() and down()"; exit 1; } - ;; - routing) - echo "$response" | grep -qE 'Route::|Route::apiResource|middleware' || { echo "::error::[$skill] Needs Route definitions"; exit 1; } - ;; - formrequests|requests) - echo "$response" | grep -qE 'authorize\(\)|rules\(\)' || { echo "::error::[$skill] Needs authorize and rules"; exit 1; } - ;; - actions) - echo "$response" | grep -q 'execute(' || { echo "::error::[$skill] Action needs execute()"; exit 1; } - echo "$response" | grep -qE 'InvoiceAction|UserHandler' && { echo "::error::[$skill] Avoid vague names"; exit 1; } || true - ;; - commands) - echo "$response" | grep -qE 'self::SUCCESS|self::FAILURE' || { echo "::error::[$skill] Must return SUCCESS or FAILURE"; exit 1; } - ;; - dto) - echo "$response" | grep -q 'fromArray' || { echo "::error::[$skill] DTO needs fromArray()"; exit 1; } - echo "$response" | grep -q 'readonly' || { echo "::error::[$skill] DTO should be readonly"; exit 1; } - ;; - enums) - echo "$response" | grep -qE 'label\(\)|color\(\)' || { echo "::error::[$skill] Enum needs label() and color()"; exit 1; } - echo "$response" | grep -q 'match' || true - ;; - events) - echo "$response" | grep -qE 'Dispatchable|SerializesModels' || true - ;; - exceptions) - echo "$response" | grep -q 'Exception' || { echo "::error::[$skill] Needs Exception suffix"; exit 1; } - ;; - helpers) - echo "$response" | grep -qE 'Helper|format' || true - ;; - interfaces) - echo "$response" | grep -q 'interface' || { echo "::error::[$skill] Needs interface"; exit 1; } - ;; - jobs) - echo "$response" | grep -qE 'ShouldQueue|Dispatchable|Queueable' || { echo "::error::[$skill] Job needs queue traits"; exit 1; } - ;; - middleware) - echo "$response" | grep -q '\$next(\$request)' || { echo "::error::[$skill] Middleware must call next"; exit 1; } - ;; - observers) - echo "$response" | grep -qE 'Observer|created|updated' || { echo "::error::[$skill] Needs Observer and lifecycle methods"; exit 1; } - ;; - policies) - echo "$response" | grep -qE 'viewAny|view|create' || { echo "::error::[$skill] Policy needs ability methods"; exit 1; } - ;; - resources) - echo "$response" | grep -qE 'whenLoaded|when\(|JsonResource' || { echo "::error::[$skill] Resource needs whenLoaded/when"; exit 1; } - ;; - services) - echo "$response" | grep -qE 'DB::transaction|Service' || { echo "::error::[$skill] Service needs DB::transaction or Service class"; exit 1; } - ;; - traits) - echo "$response" | grep -q 'trait' || { echo "::error::[$skill] Needs trait"; exit 1; } - ;; - blade) - echo "$response" | grep -q '{{' || { echo "::error::[$skill] Blade needs {{ }} escaping"; exit 1; } - ;; - design) - echo "$response" | grep -qE '\$attributes|@props|min-h-\[44px\]' || true - ;; - livewire) - echo "$response" | grep -qE 'wire:model|wire:click|Computed' || { echo "::error::[$skill] Livewire needs wire: or Computed"; exit 1; } - ;; - tailwind) - echo "$response" | grep -qE '@theme|@source|tailwind' || { echo "::error::[$skill] Needs @theme or Tailwind setup"; exit 1; } - ;; - translations) - echo "$response" | grep -qE '__\(|trans\(' || { echo "::error::[$skill] Needs __() or trans()"; exit 1; } - ;; - phpunit) - echo "$response" | grep -qE 'test_|assertStatus|assertDatabaseHas|RefreshDatabase' || { echo "::error::[$skill] Needs test structure"; exit 1; } - ;; - pesttesting) - echo "$response" | grep -qE 'it\(|expect\(|assertCreated|Arrange|Act|Assert' || { echo "::error::[$skill] Needs Pest syntax"; exit 1; } - ;; - phpstan) - echo "$response" | grep -qE 'array mainAgent[MainAgent] + mainAgent --> architectAgent[ArchitectAgent] + mainAgent --> backendImpl[BackendImplementationAgent] + mainAgent --> frontendImpl[FrontendImplementationAgent] + mainAgent --> implementationAgent[ImplementationAgent] + mainAgent --> refactorAgent[RefactorAgent] + mainAgent --> testAgent[TestAgent] + mainAgent --> reviewAgent[ReviewAgent] + mainAgent --> documentationAgent[DocumentationAgent] + architectAgent --> mainAgent + backendImpl --> mainAgent + frontendImpl --> mainAgent + implementationAgent --> mainAgent + refactorAgent --> mainAgent + testAgent --> mainAgent + reviewAgent --> mainAgent + documentationAgent --> mainAgent + mainAgent --> outputNode["Output (code/plan/review/docs)"] +``` + +- **MainAgent** is typically Claude Desktop, Claude Terminal, or an internal orchestrator. +- Each role is a **prompted mode** of the same underlying model, not a separate codebase. +- All roles query the same Boost MCP index; they just apply different responsibilities when reading and editing code. + +--- + +### Example Prompts + +You can adapt these snippets directly in Claude Desktop/Terminal or other agents: + +- **ArchitectAgent** + - “Act as **ArchitectAgent** for this Laravel project. Using `RULES.md` and the `general`, `models`, `migrations`, `routing`, `actions`, and `services` skills from `codebar-ag/coding-guidelines`, design the architecture for this feature: …” + +- **BackendImplementationAgent** + - “Act as **BackendImplementationAgent**. Follow the `controllers`, `actions`, `services`, `models`, `formrequests`, `middleware`, and `phpstan` skills to implement the backend for this feature design without changing Blade, Livewire, or Tailwind unless explicitly requested: …” + +- **FrontendImplementationAgent** + - “Act as **FrontendImplementationAgent**. Using the `controllers` (response shaping only), `resources`, `blade`, `design`, `livewire`, `tailwind`, and `translations` skills, implement or update the frontend for this feature, assuming the backend contracts are already in place. If a minimal backend adjustment is required, describe it but do not implement it: …” + +- **ImplementationAgent** + - “Act as **ImplementationAgent**. Implement this small, self-contained feature end-to-end using the relevant skills, keeping changes tightly scoped and aligned with the existing architecture: …” + +- **RefactorAgent** + - “Act as **RefactorAgent**. Using the `controllers`, `actions`, `services`, and `models` skills, refactor this legacy code to match the guidelines. Keep behaviour the same and work in small, reviewable steps: …” + +- **TestAgent** + - “Act as **TestAgent**. Apply the `phpunit`, `pesttesting`, and `phpstan` skills to improve test coverage and static analysis for these changes: …” + +- **ReviewAgent** + - “Act as **ReviewAgent**. Using `RULES.md` and all skills, review this diff and produce: (1) a short assessment, (2) a file‑grouped refactor plan, and (3) a few copy‑pasteable suggestions.” + +- **DocumentationAgent** + - “Act as **DocumentationAgent**. Using `RULES.md`, the `documentation` skill, and any relevant feature skills, update `README.md` and other docs to reflect this change. Focus on behaviour, examples, and how to apply the guidelines in practice, not internal implementation details: …” + diff --git a/README.md b/README.md index 5938257..ff41396 100644 --- a/README.md +++ b/README.md @@ -1,89 +1,191 @@ # codebar Solutions AG Coding Guidelines -Shared Laravel coding guidelines and skills for codebar-ag projects. A Composer package that ships 36 skills for consistent conventions across PHP, Laravel, testing, frontend, and services. +Shared Laravel coding and architecture guidelines for codebar-ag projects, optimized for AI-assisted development with Laravel Boost, Claude CI, and Claude Desktop/Terminal. **Rule index:** See [RULES.md](RULES.md) for the full rule structure and file reference. --- -## Skills Overview +## Requirements -Skills are reusable convention guides that assistants use when working with your codebase. Each skill includes Rules, Examples, Anti-Patterns, and References. - -| Category | Skills | Description | -|----------|--------|-------------| -| **Laravel** | General, HelperFunctions, Models, Controllers, Migrations, Routing, FormRequests | Framework conventions, config/logging, Eloquent, routes, validation | -| **Backend** | Actions, Commands, DTO, Enums, Events, Exceptions, Helpers, Interfaces, Jobs, Middleware, Observers, Policies, Requests, Resources, Services, Traits | PHP architecture, single-purpose classes, API resources, queue jobs | -| **Frontend** | Blade, Design, Livewire, Tailwind, Translations | Templates, design system, components, Tailwind CSS, i18n | -| **Testing** | PHPUnit, PestTesting, PHPStan, Dusk | Unit/feature tests, static analysis, browser tests | -| **Services** | Saloon, DocuWare, Albatros | External API integrations (Saloon, DocuWare, Albatros) | - -**Total: 36 skills.** +- **PHP:** ^8.4 +- **Laravel:** 12.x (Illuminate 12 components) +- **Laravel Boost:** ^2.2 (installed automatically as a dependency) --- -## Implementation Guide - -### Prerequisites +## Installation -- A Laravel project where you want to use these guidelines -- [Laravel Boost](https://github.com/laravel/boost) (required for skill discovery) - -### Step 1: Install Laravel Boost +### 1. Require the package In your Laravel project: -```bash -composer require laravel/boost --dev -php artisan boost:install -``` - -### Step 2: Add this package - ```bash composer require codebar-ag/coding-guidelines --dev ``` -### Step 3: Sync skills +This will also install `laravel/boost` as a dependency. + +### 2. Install and sync Boost ```bash +php artisan boost:install php artisan boost:update ``` -Boost automatically discovers skills from `vendor/codebar-ag/coding-guidelines/resources/boost/skills/` when the package is installed. +Laravel Boost automatically discovers skills from `vendor/codebar-ag/coding-guidelines/resources/boost/skills/` when the package is installed. -### Step 4: Activate MCP (optional) +--- -If your editor supports MCP (Model Context Protocol), configure it to use the Boost MCP server for full context. See the [Laravel Boost documentation](https://laravel.com/docs/boost) for your editor's setup. +## Usage + +Once the package is installed and `boost:update` has run: + +- **Laravel Boost** exposes all skills under `resources/boost/skills/**/SKILL.md` to AI assistants that integrate with Boost. +- **Claude CI** can use these skills and `RULES.md` when reviewing pull requests. +- **Claude Desktop & Claude Terminal (PhpStorm or other editors)** can follow the same guidelines when you point them at this package. + +No extra configuration is required beyond installing the package and running the Boost commands. + +--- + +## Multi‑agent usage with Laravel Boost + +Laravel Boost acts as the **index** between your Laravel project and AI agents. +This package provides the **skills and rules** for that index; the agents are *personas* you prompt in your tools. + +See `AGENTS.md` for full details. In short, you have five roles: + +- **ArchitectAgent**: designs features (routes, models, actions, services, events). +- **ImplementationAgent**: implements and updates code according to the skills. +- **RefactorAgent**: brings existing code into guideline compliance safely. +- **TestAgent**: improves tests and static analysis. +- **ReviewAgent**: reviews changes and proposes refactors (used in CI). + +### Example prompts (Claude Desktop / Terminal) + +Copy‑paste and adapt these when talking to Claude Desktop/Terminal with Boost enabled: + +- **ArchitectAgent** + + ```text + Act as ArchitectAgent for this Laravel project. + + Use RULES.md and the skills under resources/boost/skills/**/SKILL.md from codebar-ag/coding-guidelines. + + For this feature, especially apply the general, models, migrations, routing, actions, and services skills. + Design the routes, models, actions, and services needed to implement this ticket: + - [paste ticket or description] + ``` + +- **ImplementationAgent** + + ```text + Act as ImplementationAgent. + + Use RULES.md and the controllers, formrequests, actions, services, resources, blade, livewire, tailwind, and translations skills. + + Starting from this design, implement the feature without changing unrelated behaviour: + - [paste design or current code] + ``` + +- **RefactorAgent** + + ```text + Act as RefactorAgent. + + Using the controllers, actions, services, models, and helpers skills, refactor this legacy code to follow the guidelines. + Keep behaviour the same, work in small, reviewable steps, and explain each batch of changes briefly: + - [paste code or file paths] + ``` + +- **TestAgent** + + ```text + Act as TestAgent. + + Apply the phpunit, pesttesting, phpstan, and dusk skills to improve tests and static analysis for these changes. + Propose concrete test files and assertions, and any PHPStan configuration updates needed: + - [paste diff or files] + ``` + +- **ReviewAgent** + + ```text + Act as ReviewAgent. + + Using RULES.md and all skills under resources/boost/skills/**/SKILL.md, review this diff and produce: + 1) a short assessment, + 2) a file‑grouped refactor plan, and + 3) a few copy‑pasteable suggestions. + + - [paste diff or PR description] + ``` + + +--- + +## What’s included + +Conceptually, this package covers: -### Step 5: Refactor command (Cursor) +- **Laravel conventions**: routes, controllers, configuration, models, migrations, form requests, helper functions. +- **Backend architecture**: actions, services, DTOs, enums, events, exceptions, helpers, interfaces, jobs, middleware, observers, policies, requests, resources, traits. +- **Frontend & UI**: Blade templates, design system, Livewire components, Tailwind CSS, translations. +- **Testing & quality**: PHPUnit, Pest, PHPStan, Dusk and testing best practices. +- **External services**: Saloon integrations, DocuWare, Albatros and other service boundaries. -To run a full codebase refactor against all guidelines: +Each area is implemented as a dedicated skill so AI assistants can follow focused, repeatable guidance. -1. Install or update this package with Composer -2. The package automatically syncs `refactor.md` to `.cursor/commands/refactor.md` -3. In Cursor, type `/refactor` and run the command +--- + +## Skills overview + +Skills are reusable convention and workflow guides that assistants use when working with your codebase. Each skill includes rules, examples, anti‑patterns, and often a step‑by‑step process and checklists. + +| Category | Skills | Description | +|----------|--------|-------------| +| **Laravel** | General, HelperFunctions, Models, Controllers, Migrations, Routing, FormRequests | Framework conventions, config/logging, Eloquent, routes, validation | +| **Backend** | Actions, Commands, DTO, Enums, Events, Exceptions, Helpers, Interfaces, Jobs, Middleware, Observers, Policies, Requests, Resources, Services, Traits | PHP architecture, single-purpose classes, API resources, queue jobs | +| **Frontend** | Blade, Design, Livewire, Tailwind, Translations | Templates, design system, components, Tailwind CSS, i18n | +| **Testing** | PHPUnit, PestTesting, PHPStan, Dusk | Unit/feature tests, static analysis, browser tests | +| **Services** | Saloon, DocuWare, Albatros | External API integrations (Saloon, DocuWare, Albatros) | + +**Total: 36 skills.** + +--- + +## Full guidelines + +For a complete, human-readable view of the guidelines: + +- Start with **[RULES.md](RULES.md)** for the overall structure, categories, and skill index. +- Drill into individual skills under `resources/boost/skills/{skill-name}/SKILL.md`: + - Each skill defines when to apply it, core rules, examples, and anti‑patterns. + - Newer skills (for example `phpstan`) follow a workflow-style template with sections like **When to Apply**, **Preconditions**, **Process**, **Checklists**, and **Troubleshooting**. + +Projects can treat `RULES.md` as the canonical index and the `SKILL.md` files as detailed playbooks. + +--- -The prompt instructs the AI to discover all skills, map them to your codebase, analyze for violations, and refactor for full compliance. Use it when newly adopting guidelines or to cross-check AI implementations. +## Keeping guidelines up to date -If Composer plugins are restricted in your environment, run the fallback command manually: +Update the package and refresh Boost’s view of the skills with: ```bash -php artisan guidelines:sync-refactor-command +composer update codebar-ag/coding-guidelines +php artisan boost:update ``` -You may need to allow the plugin once in Composer config: -`composer config allow-plugins.codebar-ag/coding-guidelines true` - -If `/refactor` does not appear in Cursor immediately, reload the Cursor window once. +--- -### Step 6: Override skills locally (optional) +## Project overrides To customize a skill for your project, create a file at `.ai/skills/{skill-name}/SKILL.md`. Your local version takes precedence over the package default. Example: override the Models skill: -``` +```text your-project/ ├── .ai/ │ └── skills/ @@ -91,42 +193,84 @@ your-project/ │ └── SKILL.md ← Your custom version ``` -### Alternative: Sync full repo - -To sync the complete guidelines repo (`.github/prompts`, `RULES.md`, etc.) into a `guidelines/` directory for reference, add to your `composer.json`: - -```json -"scripts": { - "sync-guidelines": "php vendor/codebar-ag/coding-guidelines/scripts/sync-guidelines.php" -} -``` - -Then run `composer sync-guidelines`. This clones or pulls the repo into `guidelines/` at your project root and copies `refactor.md` to `.cursor/commands/refactor.md` for use with Cursor slash commands. - -This sync script is optional and mainly useful when you mirror the full guidelines repo; normal package install/update already auto-syncs `/refactor`. +Project overrides can also adjust the `compatible_agents` frontmatter for a skill to fit your local workflows. +See `RULES.md` for the agent/phase mapping and the `compatible_agents` convention. --- -## How It Works +## How it works + +This package places skills in `resources/boost/skills/{skill-name}/SKILL.md`. Laravel Boost v2.2+ automatically discovers skills from vendor packages when you run `boost:update`. No custom sync commands or Laravel service providers are required—Boost handles discovery directly from the vendor path. -This package places skills in `resources/boost/skills/{skill-name}/SKILL.md`. Laravel Boost v2.2+ automatically discovers skills from vendor packages when you run `boost:update`. No custom sync commands — Boost handles everything. +When you install this package via Composer, `laravel/boost` is automatically installed as a dependency, so you do not need a separate Composer require for Boost. | Source | Path | |--------|------| -| This package | `vendor/codebar-ag/coding-guidelines/resources/boost/skills/` | +| This package (default skills) | `vendor/codebar-ag/coding-guidelines/resources/boost/skills/` | | Project overrides | `.ai/skills/{skill-name}/SKILL.md` | +In day-to-day application work you typically only touch: + +- `RULES.md` (as a reference) +- Your own `.ai/skills/{skill-name}/SKILL.md` overrides +- The skills in this package for **reading** (not editing in `vendor/`) + +Package internals such as `.github/workflows/skills-validation.yml` and `composer.json` are maintained here and normally do not need changes in consumer applications. + --- -## Updating +## Advanced AI integrations -```bash -composer update codebar-ag/coding-guidelines -php artisan boost:update -``` +### Claude CI (GitHub Actions) + +You can create a GitHub Actions workflow that uses Claude to challenge your changes against these rules and produce a copy‑pastable refactor plan. + +- Typical usage in a project: + - Add a workflow such as `.github/workflows/claude-guidelines-review.yml` in your application repository. + - Configure it to run on pull requests to `main` and via a `workflow_dispatch` manual trigger. +- Expected output: a Markdown comment on the PR with: + - A short assessment of guideline alignment. + - A step‑by‑step refactor plan grouped by file/area. + - Optional code snippets or pseudo‑patches you can copy‑paste. + +To enable it, configure the Anthropic API secret as described in **Anthropic secret configuration** and follow the setup instructions of the chosen Claude GitHub Action. + +#### Anthropic secret configuration + +The Claude workflow expects an Anthropic API key to be available as a GitHub secret: + +- **Secret name (default)**: `ANTHROPIC_API_KEY` +- **Recommended location**: organization-level `Settings → Secrets and variables → Actions` so all repositories can reuse it. +- **Usage**: the workflow passes this secret to the Claude Code Action for authenticated calls to the Claude API. + +If your company uses a different secret name convention, update the workflow input to match (search for `secrets.ANTHROPIC_API_KEY` in your copied `claude-guidelines-review.yml` workflow and adjust accordingly). + +### Claude Desktop & Claude Terminal + +When using Claude Desktop or Claude Terminal (for example inside PhpStorm), you can: + +- Tell Claude that the project uses `codebar-ag/coding-guidelines`. +- Ask it to load and follow: + - `RULES.md` + - All skills under `resources/boost/skills/**/SKILL.md` +- Reference specific skills by name in your prompts, for example: + - “Apply the `phpstan` and `phpunit` skills when fixing these tests.” + - “Follow the `models` and `actions` skills when refactoring this feature.” + +This makes local AI usage consistent with what runs in CI and via Boost. + +### MCP (optional) + +If your editor supports MCP (Model Context Protocol), configure it to use the Boost MCP server for full context. See the [Laravel Boost documentation](https://laravel.com/docs/boost) for your editor's setup. --- -## CI +## Claude-based skills validation + +This package validates its own skills using Pest and the [Laravel AI SDK](https://laravel.com/docs/12.x/ai-sdk): + +- **Run locally**: `vendor/bin/pest --group=skills` +- **Environment**: Set `ANTHROPIC_API_KEY` and optionally `ANTHROPIC_MODEL` (default: `claude-3-5-sonnet@20240620`). +- **PHPUnit config**: `phpunit.xml.dist` is committed; copy to `phpunit.xml` (gitignored) for local overrides. -GitHub Actions run on push and pull requests. Run validation locally: `composer validate-skills` +The `.github/workflows/skills-validation.yml` workflow runs these checks on pushes and pull requests. Configure `ANTHROPIC_API_KEY` and `ANTHROPIC_MODEL` as GitHub secrets. diff --git a/RULES.md b/RULES.md index 2d19e8c..89a69b9 100644 --- a/RULES.md +++ b/RULES.md @@ -2,6 +2,8 @@ This file defines the folder structure and conventions for skills in this package. +It serves as the index of coding-guideline skills for Laravel Boost and other AI assistants. Detailed rules live in the individual `SKILL.md` files, while `README.md` explains installation, high-level usage, and the full skill list. + ## Package Layout Skills live in `resources/boost/skills/{skill-name}/SKILL.md` — the path Laravel Boost discovers for vendor packages. @@ -53,3 +55,8 @@ description: Brief description of when to use this skill ## Overriding Skills Projects can override any skill by creating `.ai/skills/{skill-name}/SKILL.md` in their Laravel project. The local file takes precedence over the package default. + +Use this package’s `resources/boost/skills/{skill-name}/SKILL.md` files as **defaults to read**, not files to edit in `vendor/`. For project-specific conventions: + +- Prefer `.ai/skills/{skill-name}/SKILL.md` in your application. +- Adjust the `compatible_agents` frontmatter there to map skills to the agents from `AGENTS.md` (ArchitectAgent, ImplementationAgent, RefactorAgent, TestAgent, ReviewAgent). diff --git a/composer.json b/composer.json index df45ee3..53e9d0b 100644 --- a/composer.json +++ b/composer.json @@ -1,24 +1,20 @@ { "name": "codebar-ag/coding-guidelines", - "type": "composer-plugin", + "type": "library", "description": "Shared Laravel coding guidelines and skills for codebar-ag projects. Composer package for Laravel Boost.", "keywords": [ "laravel", "boost", - "cursor", "coding-guidelines", "skills" ], "license": "MIT", "require": { - "composer-plugin-api": "^2.0", - "illuminate/console": "^12.0", - "illuminate/support": "^12.0", + "illuminate/console": "^12.41.1", + "illuminate/support": "^12.41.1", + "laravel/boost": "^2.2", "php": "^8.4" }, - "suggest": { - "laravel/boost": "Required for skill discovery. Install in your Laravel project." - }, "autoload": { "psr-4": { "CodebarAg\\CodingGuidelines\\": "src/" @@ -29,24 +25,18 @@ "CodebarAg\\CodingGuidelines\\Tests\\": "tests/" } }, - "extra": { - "class": "CodebarAg\\CodingGuidelines\\Composer\\RefactorCommandPlugin", - "laravel": { - "providers": [ - "CodebarAg\\CodingGuidelines\\CodingGuidelinesServiceProvider" - ] - } - }, - "scripts": { - "validate-skills": "php scripts/validate-skills.php", - "sync-guidelines": "php scripts/sync-guidelines.php" - }, "config": { - "sort-packages": true + "sort-packages": true, + "allow-plugins": { + "pestphp/pest-plugin": true + } }, - "minimum-stability": "dev", - "prefer-stable": true, "require-dev": { - "laravel/pint": "^1.27" + "laravel/pint": "^1.27", + "phpunit/phpunit": "^11.0", + "laravel/ai": "^0.2.0", + "orchestra/testbench": "^10.0", + "pestphp/pest": "^3.0", + "pestphp/pest-plugin-laravel": "^3.0" } } diff --git a/docs/concepts/mermaid/phpstan-analysis-flow.mmd b/docs/concepts/mermaid/phpstan-analysis-flow.mmd new file mode 100644 index 0000000..8ae4086 --- /dev/null +++ b/docs/concepts/mermaid/phpstan-analysis-flow.mmd @@ -0,0 +1,13 @@ +flowchart TD + start[Start] --> preconditions["Verify preconditions"] + preconditions --> initialAnalysis["Run initial PHPStan analysis"] + initialAnalysis --> categorizeErrors["Categorize errors"] + categorizeErrors --> fixIteratively["Fix errors iteratively"] + fixIteratively --> rerunPhpstan["Re-run PHPStan on scope"] + rerunPhpstan --> decisionMoreErrors{"More in-scope errors?"} + decisionMoreErrors -->|Yes| categorizeErrors + decisionMoreErrors -->|No| runTests["Run automated tests"] + runTests --> decisionTestsPass{"Tests pass?"} + decisionTestsPass -->|No| fixIteratively + decisionTestsPass -->|Yes| done[Done] + diff --git a/docs/concepts/mermaid/skill-template-flow.mmd b/docs/concepts/mermaid/skill-template-flow.mmd new file mode 100644 index 0000000..a20ef50 --- /dev/null +++ b/docs/concepts/mermaid/skill-template-flow.mmd @@ -0,0 +1,7 @@ +flowchart TD + start[Start] --> gatherRequirements["Gather requirements"] + gatherRequirements --> designSkill["Design skill structure"] + designSkill --> writeSkill["Write SKILL.md and docs"] + writeSkill --> verifySkill["Verify skill quality"] + verifySkill --> useSkill["Use and iterate skill"] + diff --git a/docs/skills/template-skill.md b/docs/skills/template-skill.md new file mode 100644 index 0000000..d98981a --- /dev/null +++ b/docs/skills/template-skill.md @@ -0,0 +1,167 @@ +--- +name: [skill-name] +description: [one-line description of when/why to use this skill] +--- + +# [Skill Title] + +> **Purpose**: One-line summary of what this skill does and when to use it. +> +> **How to use this template** +> +> - Copy this file into `.cursor/skills/[skill-name]/SKILL.md` (or into your project’s preferred skills directory). +> - Replace all bracketed placeholders like `[Skill Title]`, `[tool-binary]`, `[main workflow trigger]`, and `[path/to/module]` with concrete values. +> - Trim optional sections (**Concept diagram**, **Variants**, **Troubleshooting**) if they are not needed for this workflow. +> - Keep each final skill focused on a single primary workflow to stay readable and maintainable. + +## Concept diagram + +High-level flow for authoring and using this kind of skill: + +- (Optional) Add a mermaid diagram reference here, for example: `[path/to/skill-diagram.mmd]`. + +## When to Apply + +- **Primary use cases**: + - After / during **[main workflow trigger]** (for example: completing a feature or bug fix). + - When **[secondary trigger]** (for example: upgrading a dependency, level, or tool configuration). +- **Explicitly avoid**: + - Do **NOT** run during unrelated tasks; only apply when this workflow is part of the current objective or has been explicitly requested. + +## Preconditions + +- **Environment**: + - Project is checked out and dependencies installed. + - Required tools are available (for example: `[tool-binary]`, `[runtime-1]`, `[runtime-2]`, `[package-manager]`). +- **Repository state**: + - Working tree is clean or only contains changes relevant to this workflow. + - On the correct branch (for example: `main`, `develop`, or the feature branch under review). +- **Configuration / tool setup**: + - Any required config files are present (for example: `[tool-config].neon`, `.env`, `phpunit.xml`, `[tool-config]-baseline.neon`). + - If a baseline or ignore configuration exists, it is committed and understood (do not assume it is safe to delete or rewrite). + +## Process + +Copy this section and replace placeholders for each workflow. Prefer **numbered sub-sections** for major phases. + +### 1. Initial Analysis + +Explain how to run the main tool in **read-only / analysis** mode and how to interpret the output. + +```bash +# Example command (replace with real one) +[tool-binary] [subcommand] [path] --flag-1 --flag-2 +``` + +- Capture and skim the full output to understand: + - Error or finding categories. + - Affected files, modules, or namespaces. + - Whether a baseline or ignore configuration is already in place. +- If a baseline file exists, **respect it by default** – do not fix errors that are intentionally baselined unless explicitly requested. +- Focus first on **new** or **out-of-baseline** findings that were introduced by recent work. + +### 2. Categorize Issues + +Group findings or work items by type before fixing. Common categories: + +- **Type or schema issues**: Missing / wrong param & return types, mismatched generics, invalid payload shapes. +- **Undefined references**: Missing methods, properties, variables, constants, routes, or services. +- **Dead code**: Unused variables, unreachable branches, obsolete functions or classes. +- **Logic issues**: Incorrect comparisons, impossible conditions, misuse of nullable or optional values. +- **Documentation mismatches**: Docblocks or comments contradicting actual signatures or behavior. + +Decide which categories (and which paths/modules) are in-scope for this run. Prefer handling one or two categories or a single module per batch to keep diffs focused and reviewable. + +### 3. Fix Iteratively + +Work in **small, reviewable batches**, not all at once: + +1. Pick a category (or a small set of files, modules, or namespaces). +2. Apply minimal, conservative fixes that respect existing project conventions. +3. Re-run the tool for only the affected scope when possible. + +```bash +# Example: re-run only for a subset of paths +[tool-binary] [subcommand] [path/to/module] --flag-1 --flag-2 +``` + +- After each batch, confirm that: + - The total issue count for that scope is decreasing. + - No new categories of issues have been introduced. + - Fixes align with project coding standards and do not mix in unrelated refactors. + - You are not introducing broad new ignores or baselines without clear justification. + +### 4. Validate with Tests / Secondary Checks + +Once the primary tool reports success (or acceptable remaining issues for the chosen scope): + +- Run relevant automated tests or additional checks: + +```bash +# Example commands – replace or trim as needed +[test-runner-or-secondary-tool] +``` + +- If specific tests or checks map directly to the changed code, run those first for faster feedback. +- Only consider the workflow complete when: + - The primary tool is passing for the chosen scope (or remaining findings are explicitly accepted and documented), and + - Tests or secondary checks are green for the affected areas. + +## Checklists + +Use these checklists to track progress during the workflow. + +### Execution Checklist + +- [ ] Preconditions verified (environment, repo state, configuration / tool setup). +- [ ] Initial analysis run and output reviewed (including any baselines or ignores). +- [ ] Issues categorized by type and in-scope paths/modules selected. +- [ ] Fixes applied iteratively in small, reviewable batches. +- [ ] Tool re-run after each batch until results are stable for the chosen scope. +- [ ] Tests / secondary checks executed and passing (or failures documented and accepted). + +### Communication Checklist (Optional) + +- [ ] Summarized what was run (commands, scope, and options). +- [ ] Noted any trade-offs (for example: findings intentionally ignored or baselined). +- [ ] Highlighted any follow-up work that should be scheduled separately. + +## Variants (Optional) + +Describe common variations of the workflow, for example: + +- **Quick check**: Lightweight run over a narrow path for fast feedback. +- **Full project scan**: Comprehensive run across the entire codebase (more expensive; avoid during tight feedback loops). +- **CI mode**: Stricter flags or paths used in CI only. + +Be explicit about when to choose each variant. + +## Troubleshooting (Optional) + +Common failure modes and how to address them: + +- **Tool fails to start**: + - Verify the binary exists and is executable. + - Ensure dependencies are installed (for example: `[dependency-manager-install-command]`). +- **Configuration errors**: + - Point to the relevant config file(s) and typical fixes. +- **Too many findings**: + - Recommend creating / updating a baseline. + - Narrow the scope to a single module or category for the current run. + +## Safety / Things to Avoid + +- Do **not** apply automatic fixes without reviewing the diff. +- Do **not** mix large refactors with unrelated cosmetic changes in the same batch. +- Do **not** silence errors via ignores or baselines unless there is a clear, documented justification. + +## Example Summary Format + +When reporting results back to the user, use a concise structure like: + +- **Tool / mode**: `[tool-binary]` in `[quick check | full scan | CI mode]`. +- **Scope**: `[paths / modules]`. +- **Result**: + - `[N] issues fixed` + - `[M] issues remaining` (with brief explanation). +- **Follow-ups**: Short list of recommended next steps. diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 0000000..0b0722d --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,19 @@ + + + + + + + + + + + tests + + + + diff --git a/prompts/skill-validation.md b/prompts/skill-validation.md new file mode 100644 index 0000000..76ac347 --- /dev/null +++ b/prompts/skill-validation.md @@ -0,0 +1,51 @@ +You are an expert technical editor helping maintain a library of Laravel Boost skills. + +Each skill is a markdown file called SKILL.md that follows these conventions: +- YAML frontmatter with at least: + - name: machine-readable skill identifier (kebab-case) + - description: one-line explanation of when/why to use the skill +- A clear H1 title. +- Concise sections that usually include: + - When to Apply + - Preconditions + - Process (often broken into numbered steps) + - Checklists (Execution / Communication) + - Safety / Things to Avoid + - Optional: Examples, References, Troubleshooting, Variants, Example Summary Format + +You must evaluate a single SKILL.md file strictly against these criteria: + +STRUCTURE (blocking if missing or obviously wrong) +- Has YAML frontmatter with non-empty name and description. +- Has a top-level H1 title. +- Does not contain obvious template placeholders such as [Skill Title], [tool-binary], [main workflow trigger], or TODO markers. + +CONTENT (usually warnings if missing) +- Mentions when to apply the skill and when NOT to. +- Describes prerequisites / preconditions before using the skill. +- Explains the process in concrete, ordered steps. +- Provides at least one checklist or clearly structured bullet list for execution or communication. +- Calls out safety considerations / things to avoid. + +TONE & QUALITY (warnings/improvements) +- Language is clear, unambiguous, and specific to this skill. +- Does not contradict itself or general Laravel practices. +- Uses examples that match the skill's purpose where relevant. + +You MUST respond with ONLY JSON that matches this schema, no extra text: +{ + "skill_name": string, // inferred from frontmatter or path + "path": string, // relative path to the SKILL.md file + "valid": boolean, // false only for structural or severe content issues + "errors": string[], // blocking issues that should fail CI + "warnings": string[], // non-blocking consistency or clarity issues + "improvements": string[] // concrete suggestions to strengthen the skill +} + +Consider a skill INVALID (valid = false) when: +- Frontmatter is missing or name/description are empty or obviously placeholders. +- There is no clear H1 title. +- The file is clearly still the raw template (placeholders not filled in). + +Otherwise, set valid = true even if there are warnings. + diff --git a/refactor.md b/refactor.md deleted file mode 100644 index f6cf80e..0000000 --- a/refactor.md +++ /dev/null @@ -1,118 +0,0 @@ -# Codebase Refactor — Full Guidelines Compliance - -You are refactoring a Laravel codebase to achieve 100% alignment with **codebar-ag coding guidelines**. This prompt is used when (a) newly adopting guidelines in an existing project, or (b) cross-checking AI-generated implementations for compliance. - ---- - -## 1. Skill Discovery - -Locate skills from one of these paths (check in order; first existing wins): - -- `resources/boost/skills/` (when running inside this guidelines package repo) -- `vendor/codebar-ag/coding-guidelines/resources/boost/skills/` -- `guidelines/resources/boost/skills/` - -If none exist, search the workspace for `**/resources/boost/skills/*/SKILL.md` and use the nearest matching root as the active skill source path. - -Project overrides in `.ai/skills/{skill-name}/SKILL.md` take precedence over package defaults. - -**Action:** List all `SKILL.md` files. For each skill, extract: - -- `name` (from frontmatter or folder) -- `Tags` — the first path-like value (e.g. `app/Models/**/*.php`) is the glob for file discovery -- `Rules`, `Anti-Patterns`, `Examples` — apply these when analyzing and refactoring - ---- - -## 2. Processing Order (Dependency-Aware) - -Process skills in this order to avoid repeated edits and respect dependencies: - -| Phase | Skills | -|-------|--------| -| Foundation | `general`, `php`, `helperfunctions` | -| Data layer | `migrations`, `enums`, `models`, `traits` | -| Backend core | `actions`, `services`, `dto`, `exceptions`, `interfaces` | -| HTTP layer | `formrequests`, `controllers`, `middleware`, `requests`, `resources`, `routing` | -| Infrastructure | `commands`, `jobs`, `events`, `observers`, `policies` | -| Frontend | `blade`, `design`, `livewire`, `tailwind`, `translations` | -| Integrations | `saloon`, `docuware`, `albatros` (only if matching files exist) | -| Helpers | `helpers` | -| Testing | `phpunit`, `pesttesting`, `phpstan`, `dusk` | - ---- - -## 3. Per-Skill Workflow - -For each skill in order: - -1. **Match files** — Find all files in the workspace that match the skill’s glob patterns from Tags (e.g. `app/Http/Controllers/**/*.php`). -2. **Skip if empty** — If no files match (e.g. no Albatros service), skip the skill. -3. **Read skill** — Load the full `SKILL.md` content for Rules, Examples, and Anti-Patterns. -4. **Analyze** — Check each matching file against the Rules and Anti-Patterns. -5. **Refactor** — Fix violations using the skill’s Examples. Preserve behavior; do not introduce breaking changes. -6. **Batch edits** — Group edits by skill (e.g. all controller fixes in one pass). - ---- - -## 4. Efficiency Directives - -- **Incremental changes** — Prefer small, reviewable edits over large rewrites. -- **Prioritize when large** — If the scope is large, produce a prioritized compliance report and refactor in phases. -- **Cross-check mode** — When validating recent AI work, focus first on recently changed files, then broaden if needed. -- **Avoid redundant passes** — Process skills in the defined order so earlier fixes are not undone by later ones. - ---- - -## 5. Output Format - -### Phase 0: Plan and Confirm (mandatory) - -Before making any code changes: - -- Enter planning mode and produce a concrete implementation plan. -- Include: applicable skills, target files, prioritized violation groups, and intended edit batches. -- Present the plan to the user and request explicit approval. -- Do not edit files, run formatters, or execute write operations until the user confirms the plan. - -### Phase A: Compliance Report (before edits) - -Produce a concise report: - -- Skills that apply (have matching files) -- Skills that are skipped (no matching files) -- Per skill: files with violations, brief description of each violation -- Summary: total violations, suggested commit grouping - -### Phase B: Refactoring (skill-by-skill) - -For each skill with violations: - -1. State the skill name and what is being fixed. -2. Apply the changes. -3. Suggest a commit message for that batch of changes. - ---- - -## 6. Tags-to-Glob Mapping - -Skills use Tags like: - -``` -**Tags:** app/Models/**/*.php, laravel, php, backend, eloquent, model, database -``` - -Use the **first path-like Tag** (e.g. `app/Models/**/*.php`, `database/migrations/**/*.php`, `resources/views/**/*.blade.php`) as the glob. Some skills have multiple paths (e.g. `app/Events/**/*.php`, `app/Listeners/**/*.php`); include all path-like Tags for that skill. - ---- - -## 7. Non-Breaking Refactors Only - -- Do not change observable behavior. -- Do not remove or rename public APIs without explicit approval. -- Prefer additive fixes (add missing types, FormRequests, transactions) over removals. -- If a refactor is ambiguous or risky, report it and do not apply it automatically. - ---- - -**Begin by discovering skills, then producing the compliance report, then executing refactors in the specified order.** diff --git a/resources/boost/skills/actions/SKILL.md b/resources/boost/skills/actions/SKILL.md index ab4ce2a..c93eb98 100644 --- a/resources/boost/skills/actions/SKILL.md +++ b/resources/boost/skills/actions/SKILL.md @@ -3,23 +3,66 @@ name: actions description: Single-purpose business logic classes that encapsulate one well-defined business operation. Actions are the primary location for business logic in Laravel applications, invoked from controllers, commands, or jobs. --- -**Name:** Actions -**Description:** Single-purpose business logic classes that encapsulate one well-defined business operation. Actions are the primary location for business logic in Laravel applications, invoked from controllers, commands, or jobs. -**Compatible Agents:** general-purpose, backend +# Actions + +**Name:** Actions +**Description:** Single-purpose business logic classes that encapsulate one well-defined business operation. Actions are the primary location for business logic in Laravel applications, invoked from controllers, commands, or jobs. +**Compatible Agents:** general-purpose, backend **Tags:** app/Actions/**/*.php, laravel, php, backend, business-logic, action -## Rules +## When to Apply + +- When implementing or refactoring a **single business operation** that can be described in one sentence. +- When slimming **fat controllers, commands, or jobs** by moving business logic out of them. +- When multiple entry points (controller, command, job, listener) should reuse the **same business logic**. +- When aligning legacy code with the project’s pattern of **`app/Actions/` classes with `execute()`**. + +## Preconditions + +- The Laravel project is installed and bootstrapped. +- The `app/Actions/` directory exists (or will be created) and is autoloaded by Composer. +- Related models, notifications, events, and DTOs required by the action already exist or have a clear design. +- Authorization and validation rules are defined at the controller, policy, or Form Request level. + +## Process + +### 1. Decide if an Action is Appropriate + +- Confirm the work is a **single business operation**, not multi-step orchestration across domains. +- Prefer an Action when: + - The behavior will be reused from multiple places. + - The behavior is business logic, not HTTP or infrastructure logic. +- If the behavior crosses multiple domains or requires complex orchestration, prefer a **Service** instead. + +### 2. Design the Action -- Action classes live in `app/Actions/` -- Each action represents **one single business operation** — if you can't describe it in a single sentence, split it up -- Use a clear verb-noun naming pattern: `CreateInvoice`, `SendPasswordResetEmail`, `ArchiveExpiredSubscriptions` -- Never use vague names like `InvoiceAction` or `UserHandler` -- Actions expose a single public `execute()` method -- Keep the constructor for dependency injection only -- Actions are resolved via the service container -- Never include HTTP concerns (request, response, redirects) in an action -- Never put multi-domain orchestration in an action — use a Service instead -- Never put reusable formatting or utility logic in an action — use a Helper +- Place the class in `app/Actions/`. +- Use a clear verb–noun naming pattern: + - Examples: `CreateInvoice`, `SendPasswordResetEmail`, `ArchiveExpiredSubscriptions`. + - Avoid vague names like `InvoiceAction`, `UserHandler`, `DataProcessor`. +- Plan for a **single public `execute()` method** that represents the operation. +- Keep the constructor for dependency injection only (repositories, services, helpers, etc.). + +### 3. Implement the Action + +- Implement `execute()` with the full business operation: + - Perform any database writes and domain logic required for the operation. + - Call other Actions or Services as needed, but keep the responsibility focused. +- Resolve the Action through the **service container** (type-hint it in controllers, commands, or jobs). +- Do **not**: + - Include HTTP concerns (`Request`, `Response`, redirects) inside the Action. + - Include cross-domain orchestration that belongs in a Service. + - Put reusable formatting or generic utility logic here (use Helpers instead). + +### 4. Integrate from Controllers, Commands, and Jobs + +- In controllers: + - Validate input via Form Requests. + - Authorize via policies or `$this->authorize()`. + - Inject the Action and call `execute()` with validated data or models. +- In console commands or queued jobs: + - Resolve the Action from the container. + - Iterate over models or DTOs and delegate the business operation to `execute()`. ## Examples @@ -78,14 +121,26 @@ class GenerateInvoicesCommand extends Command } ``` -## Anti-Patterns +## Checklists + +### Execution Checklist + +- [ ] Verified the behavior is a **single business operation** appropriate for an Action. +- [ ] Created or updated a class under `app/Actions/` with a clear verb–noun name. +- [ ] Implemented a single public `execute()` method for the operation. +- [ ] Kept the constructor for dependency injection only. +- [ ] Removed HTTP concerns from the Action (validation, requests, responses, redirects). +- [ ] Ensured authorization is handled in controllers, policies, or Form Requests. +- [ ] Updated controllers, commands, or jobs to **delegate to the Action** instead of duplicating logic. + +## Safety / Things to Avoid -- Putting HTTP concerns (`Request`, `Response`, redirects) inside an action -- Creating multi-step orchestration across domains in a single action (use a Service) -- Naming an action vaguely: `InvoiceAction`, `UserHandler`, `DataProcessor` -- Adding multiple `execute()` methods or public methods beyond the single operation -- Adding business logic in a constructor — use `execute()` for that -- Performing database queries unrelated to the action's single responsibility +- Putting HTTP concerns (`Request`, `Response`, redirects) inside an Action. +- Creating multi-step orchestration across domains in a single Action (use a Service instead). +- Naming an Action vaguely, for example `InvoiceAction`, `UserHandler`, `DataProcessor`. +- Adding multiple `execute()` methods or extra public methods beyond the single operation. +- Adding business logic in a constructor — keep it in `execute()`. +- Performing database queries unrelated to the Action’s single responsibility. ## References diff --git a/resources/boost/skills/albatros/SKILL.md b/resources/boost/skills/albatros/SKILL.md index 24c856e..7706a64 100644 --- a/resources/boost/skills/albatros/SKILL.md +++ b/resources/boost/skills/albatros/SKILL.md @@ -1,6 +1,11 @@ --- name: albatros description: Albatros accounting API integration via Saloon. Use when working with app/Services/Albatros/, AlbatrosConnector, or Albatros DTOs. +compatible_agents: + - architect + - implement + - refactor + - review --- **Name:** Albatros API Integration diff --git a/resources/boost/skills/blade/SKILL.md b/resources/boost/skills/blade/SKILL.md index 8b8e0f1..aee3da0 100644 --- a/resources/boost/skills/blade/SKILL.md +++ b/resources/boost/skills/blade/SKILL.md @@ -1,6 +1,10 @@ --- name: blade description: Laravel Blade template conventions covering components, output escaping, security, structure, and formatting. +compatible_agents: + - implement + - refactor + - review --- **Name:** Blade Templates diff --git a/resources/boost/skills/commands/SKILL.md b/resources/boost/skills/commands/SKILL.md index 7359f4a..e7fda52 100644 --- a/resources/boost/skills/commands/SKILL.md +++ b/resources/boost/skills/commands/SKILL.md @@ -1,6 +1,11 @@ --- name: commands description: Artisan console command classes that serve as the CLI entry point for operations. Commands validate input and delegate all business logic to Actions or Services. +compatible_agents: + - architect + - implement + - refactor + - review --- **Name:** Commands diff --git a/resources/boost/skills/controllers/SKILL.md b/resources/boost/skills/controllers/SKILL.md index b6da9d0..6a4a82a 100644 --- a/resources/boost/skills/controllers/SKILL.md +++ b/resources/boost/skills/controllers/SKILL.md @@ -1,25 +1,69 @@ --- name: controllers description: Thin HTTP entry points that validate input, delegate to Actions or Services, and return a response. Controllers contain no business logic. +compatible_agents: + - implement + - refactor + - review --- -**Name:** Controllers -**Description:** Thin HTTP entry points that validate input, delegate to Actions or Services, and return a response. Controllers contain no business logic. -**Compatible Agents:** general-purpose, backend +# Controllers + +**Name:** Controllers +**Description:** Thin HTTP entry points that validate input, delegate to Actions or Services, and return a response. Controllers contain no business logic. +**Compatible Agents:** general-purpose, backend **Tags:** app/Http/Controllers/**/*.php, laravel, php, backend, controller, http, request-response -## Rules +## When to Apply + +- When creating or refactoring HTTP endpoints in `app/Http/Controllers/**`. +- When moving **business logic out of controllers** into Actions, Services, or Jobs. +- When ensuring API and web controllers follow consistent patterns for validation, authorization, and responses. +- When reviewing controllers for thinness, correct status codes, and proper delegation. + +## Preconditions + +- The Laravel routing and controller setup is in place (`routes/web.php`, `routes/api.php`). +- Related Actions, Services, Jobs, Policies, and Form Requests exist or have clear designs. +- The project conventions for API vs web controllers (JSON vs views) are understood. + +## Process + +### 1. Keep Controllers Thin + +- Restrict controller responsibilities to: + - Validating and authorizing incoming requests. + - Delegating work to Actions, Services, or Jobs. + - Returning appropriate HTTP responses (JSON or views). +- Remove any: + - Direct database queries from controller methods. + - Complex branching or multi-step domain logic. + +### 2. Use Form Requests and Authorization -- Keep controllers **thin** — delegate business logic to Services, Actions, or Jobs -- Controllers handle: request validation, calling a service/job, returning a response -- No direct database queries or complex logic in controller methods -- Use dedicated `FormRequest` classes for all validation — never call `$request->validate()` or `Validator::make()` inside a controller -- Use invokable controllers (`__invoke`) for single-action endpoints -- Name invokable controllers after the action: `StoreInvoiceController`, `ProcessWebhookController` -- Return JSON responses from API controllers -- Return views from web controllers -- Use appropriate HTTP status codes (200, 201, 422, 403, etc.) -- Enforce authorization at the controller level using `$this->authorize()`, via Form Request `authorize()`, or route middleware +- Use dedicated `FormRequest` classes for **all validation**: + - Avoid `$request->validate()` or `Validator::make()` directly in the controller. +- Enforce authorization at the controller level via: + - `$this->authorize()` calls. + - Form Request `authorize()` methods. + - Route or controller middleware (e.g., `can:` or `auth`). + +### 3. Design Controller Structure and Naming + +- For single-action endpoints, use **invokable controllers** (`__invoke`): + - Name them after the action: `StoreInvoiceController`, `ProcessWebhookController`. +- For resource controllers: + - Keep each method thin and delegate to appropriate Actions or Services. + - Only define the methods actually needed; prefer invokable controllers when only one or two actions exist. + +### 4. Return Consistent Responses + +- For API controllers: + - Return JSON responses (e.g., `JsonResponse` or `Resource` / `ResourceCollection`). + - Use appropriate HTTP status codes: 200, 201, 204, 403, 404, 422, etc. +- For web controllers: + - Return views or redirects, not JSON. + - Keep view data preparation simple and delegated where possible. ## Examples @@ -66,14 +110,24 @@ class InvoiceController extends Controller } ``` -## Anti-Patterns +## Checklists + +### Execution Checklist + +- [ ] Controller methods contain **no business logic** or direct database queries. +- [ ] All validation is handled by **FormRequest** classes, not inline in the controller. +- [ ] Authorization is enforced via policies, Form Requests, or middleware. +- [ ] Controllers delegate to Actions, Services, or Jobs for business operations. +- [ ] Invokable controllers are used for single-action endpoints where appropriate. +- [ ] Responses use correct types and HTTP status codes (JSON for API, views for web). + +## Safety / Things to Avoid -- Calling `$request->validate()` directly in a controller (use a FormRequest) -- Writing database queries directly in a controller -- Putting business logic in a controller method -- Using resource controllers with 7 methods when only 1-2 are needed (use invokable controllers) -- Not using appropriate HTTP status codes in responses -- Performing authorization inside Actions instead of at the controller level +- Calling `$request->validate()` directly in a controller (use a FormRequest). +- Writing database queries or heavy business logic directly in controller methods. +- Using resource controllers with seven methods when only one or two are needed (prefer invokable controllers). +- Ignoring HTTP status codes or returning incorrect codes for errors and success. +- Performing authorization inside Actions instead of at the controller level. ## References diff --git a/resources/boost/skills/design/SKILL.md b/resources/boost/skills/design/SKILL.md index ccb35a1..0a31e55 100644 --- a/resources/boost/skills/design/SKILL.md +++ b/resources/boost/skills/design/SKILL.md @@ -1,6 +1,10 @@ --- name: design description: Component-first design system for Blade views. Use when creating UI components, designing responsive layouts, or implementing accessible interfaces. +compatible_agents: + - implement + - refactor + - review --- **Name:** Design System diff --git a/resources/boost/skills/documentation/SKILL.md b/resources/boost/skills/documentation/SKILL.md new file mode 100644 index 0000000..4217bae --- /dev/null +++ b/resources/boost/skills/documentation/SKILL.md @@ -0,0 +1,118 @@ +--- +name: documentation +description: Keep README, guidelines, and feature documentation in sync with the actual behaviour of the codebase, focusing on behaviour, examples, and how to apply the skills in practice. +--- + +# Documentation + +**Name:** Documentation +**Description:** Keep README, guidelines, and feature documentation in sync with the actual behaviour of the codebase, focusing on behaviour, examples, and how to apply the skills in practice. +**Compatible Agents:** documentation, general-purpose, review +**Tags:** docs, readme, guides, how-to, behaviour, examples + +## When to Apply + +- After implementing or refactoring a feature with **BackendImplementationAgent**, **FrontendImplementationAgent**, or **ImplementationAgent**. +- When the behaviour of a public API endpoint, console command, job, or user-facing screen changes. +- When adding a new pattern, skill, or workflow that other developers should follow. +- When onboarding material (`README.md`, `RULES.md`, or top-level docs) is out of date with current behaviour. + +## Preconditions + +- The relevant code changes are implemented or have at least a stable design from **ArchitectAgent**. +- You have access to: + - `README.md` + - `RULES.md` + - Any feature or skill docs that describe the area being changed +- Tests or basic manual checks have confirmed the new or changed behaviour. + +## Process + +### 1. Identify the Behaviour to Document + +- Summarize the change in 1–3 sentences: + - What problem does it solve? + - Who uses it (developer, end user, operator)? + - What is the primary entry point (route, command, job, UI)? +- Locate the most relevant documentation home for this behaviour: + - High-level or onboarding: `README.md`. + - Project-wide rules or patterns: `RULES.md`. + - Skill- or pattern-specific: the corresponding `resources/boost/skills/**/SKILL.md`. + - Feature-specific: the closest existing doc file or a new one in the project’s docs area. + +### 2. Update or Create Documentation + +- Prefer **updating** existing sections over creating new, parallel explanations. +- Keep sections short and scannable: + - Use clear headings and bullet points. + - Lead with “what this is” and “when to use it”. +- Focus on: + - **Inputs**: routes, request payloads, CLI flags, important configuration. + - **Outputs**: responses, side effects (DB changes, events, emails, jobs). + - **Constraints**: permissions, limits, feature flags, environment assumptions. +- Link to deeper technical details (code, skills) instead of duplicating them. + +### 3. Add or Refresh Examples + +- For backend features: + - Provide at least one example request/response or CLI invocation. + - Show the **happy path** and briefly mention notable error cases. +- For frontend features: + - Show how a Blade view, Livewire component, or route is used. + - Mention any important state, props, or events. +- Make examples: + - Copy-pasteable where reasonable. + - Minimal: avoid irrelevant noise or unrelated configuration. + +### 4. Validate Against the Code + +- Cross-check that the documentation matches the **current**: + - Route names, HTTP methods, and URIs. + - Request fields and validation rules. + - Response structure or resource fields. + - Flags, env vars, or configuration keys. +- If something is uncertain: + - Prefer reading the code or tests over guessing. + - If truly ambiguous, explicitly call it out as “behaviour depends on …” instead of inventing details. + +### 5. Keep Changelogs and History Manageable + +- Avoid narrating every refactor; focus on **observable behaviour** and how to use the system. +- When behaviour is intentionally changed: + - Update the documentation as if it had always been correct. + - Use commit messages or PR descriptions for historical context, not the docs themselves. + +## Checklists + +### Execution Checklist + +- [ ] Identified which behaviours or features changed. +- [ ] Located the most appropriate docs to update (README, RULES, skill docs, feature docs). +- [ ] Updated or created sections with concise descriptions of behaviour and usage. +- [ ] Added or refreshed at least one practical example where helpful. +- [ ] Cross-checked docs against current routes, requests, responses, and configuration. + +### Communication Checklist + +- [ ] Summarized what changed in the docs (scope, files, and key points). +- [ ] Highlighted any new patterns or skills authors should follow. +- [ ] Noted any follow-up documentation that should be tackled separately (for example, larger guides or diagrams). + +## Safety / Things to Avoid + +- Do **not** describe internal implementation details that are likely to change unless they are critical for users. +- Do **not** duplicate large code snippets that will fall out of sync; prefer links or short, focused examples. +- Do **not** invent behaviour that does not exist in the code or tests. +- Do **not** mix unrelated documentation changes into the same batch; keep diffs focused on the current feature or area. + +## Example Summary Format + +When reporting documentation work back to the team, use a concise structure like: + +- **Area**: `[feature / module / onboarding]`. +- **Docs touched**: `[README.md, RULES.md, path/to/feature-doc.md]`. +- **Changes**: + - Updated behaviour for `[endpoint / screen / command]`. + - Added examples for `[common task or workflow]`. +- **Follow-ups**: `[optional longer-form guides, diagrams, or cross-links to add later]`. + diff --git a/resources/boost/skills/docuware/SKILL.md b/resources/boost/skills/docuware/SKILL.md index e5d5e74..3a5a37d 100644 --- a/resources/boost/skills/docuware/SKILL.md +++ b/resources/boost/skills/docuware/SKILL.md @@ -1,6 +1,11 @@ --- name: docuware description: DocuWare document management integration patterns. Use when working with DocuWare connector, webhooks, document imports, or app/Services/DocuWare/. +compatible_agents: + - architect + - implement + - refactor + - review --- **Name:** DocuWare Integration diff --git a/resources/boost/skills/dto/SKILL.md b/resources/boost/skills/dto/SKILL.md index a645a91..ceea51e 100644 --- a/resources/boost/skills/dto/SKILL.md +++ b/resources/boost/skills/dto/SKILL.md @@ -1,6 +1,11 @@ --- name: dto description: Readonly data containers with a `fromArray` factory method used to pass structured data between application layers — especially for external API responses and service boundaries. +compatible_agents: + - architect + - implement + - refactor + - review --- **Name:** DTO (Data Transfer Object) diff --git a/resources/boost/skills/dusk/SKILL.md b/resources/boost/skills/dusk/SKILL.md index 0265164..c3fd2af 100644 --- a/resources/boost/skills/dusk/SKILL.md +++ b/resources/boost/skills/dusk/SKILL.md @@ -1,6 +1,10 @@ --- name: dusk description: End-to-end browser testing with Laravel Dusk. Used exclusively for full user flows requiring a real Chrome browser — JavaScript interactions, multi-step forms, and visual assertions. +compatible_agents: + - test + - refactor + - review --- **Name:** Dusk (Browser Testing) diff --git a/resources/boost/skills/enums/SKILL.md b/resources/boost/skills/enums/SKILL.md index 0e03d26..63abf5e 100644 --- a/resources/boost/skills/enums/SKILL.md +++ b/resources/boost/skills/enums/SKILL.md @@ -1,6 +1,11 @@ --- name: enums description: PHP backed string enums used instead of constants or magic strings. Enums include `label()` and `color()` helper methods and are cast on Eloquent models. +compatible_agents: + - architect + - implement + - refactor + - review --- **Name:** Enums diff --git a/resources/boost/skills/events/SKILL.md b/resources/boost/skills/events/SKILL.md index a9e96a9..840096c 100644 --- a/resources/boost/skills/events/SKILL.md +++ b/resources/boost/skills/events/SKILL.md @@ -1,6 +1,11 @@ --- name: events description: Decoupled communication between application layers. Events are plain data objects describing what happened; listeners react to those events with a single, specific side effect. +compatible_agents: + - architect + - implement + - refactor + - review --- **Name:** Events & Listeners diff --git a/resources/boost/skills/exceptions/SKILL.md b/resources/boost/skills/exceptions/SKILL.md index 1b7e876..8a43f1b 100644 --- a/resources/boost/skills/exceptions/SKILL.md +++ b/resources/boost/skills/exceptions/SKILL.md @@ -1,6 +1,11 @@ --- name: exceptions description: Named, meaningful failure states in your domain. Custom exceptions communicate precise failure reasons to callers and optionally carry domain-specific data. +compatible_agents: + - architect + - implement + - refactor + - review --- **Name:** Exceptions diff --git a/resources/boost/skills/formrequests/SKILL.md b/resources/boost/skills/formrequests/SKILL.md index 83e5049..fcfd247 100644 --- a/resources/boost/skills/formrequests/SKILL.md +++ b/resources/boost/skills/formrequests/SKILL.md @@ -1,6 +1,10 @@ --- name: formrequests description: Dedicated validation classes for all controller input. Form Requests encapsulate validation rules, authorization, and error messages outside of controllers. +compatible_agents: + - implement + - refactor + - review --- **Name:** Form Requests diff --git a/resources/boost/skills/general/SKILL.md b/resources/boost/skills/general/SKILL.md index 0ba652e..df31ea3 100644 --- a/resources/boost/skills/general/SKILL.md +++ b/resources/boost/skills/general/SKILL.md @@ -1,6 +1,11 @@ --- name: general description: Project-wide Laravel conventions that always apply: configuration access, database patterns, logging, activity logging, and code formatting. +compatible_agents: + - architect + - implement + - refactor + - review --- **Name:** Laravel General Conventions @@ -73,3 +78,7 @@ activity() - [Laravel Logging](https://laravel.com/docs/logging) - [Spatie Activity Log](https://spatie.be/docs/laravel-activitylog/) - [Laravel Pint](https://laravel.com/docs/pint) + +## Further reading + +For the skill authoring template and workflow structure, see [docs/skills/template-skill.md](../../../../docs/skills/template-skill.md). diff --git a/resources/boost/skills/helperfunctions/SKILL.md b/resources/boost/skills/helperfunctions/SKILL.md index e656593..2b601af 100644 --- a/resources/boost/skills/helperfunctions/SKILL.md +++ b/resources/boost/skills/helperfunctions/SKILL.md @@ -1,6 +1,11 @@ --- name: helperfunctions description: Always prefer Laravel's built-in helper classes over native PHP functions. Use `Arr::`, `Str::`, and Collection methods instead of native PHP equivalents. +compatible_agents: + - architect + - implement + - refactor + - review --- **Name:** Laravel Helper Functions diff --git a/resources/boost/skills/helpers/SKILL.md b/resources/boost/skills/helpers/SKILL.md index d8385fa..21e9334 100644 --- a/resources/boost/skills/helpers/SKILL.md +++ b/resources/boost/skills/helpers/SKILL.md @@ -1,6 +1,11 @@ --- name: helpers description: Stateless utility classes providing shared formatting, conversion, or calculation logic needed across multiple parts of the application. +compatible_agents: + - architect + - implement + - refactor + - review --- **Name:** Helpers diff --git a/resources/boost/skills/interfaces/SKILL.md b/resources/boost/skills/interfaces/SKILL.md index b8216eb..29098aa 100644 --- a/resources/boost/skills/interfaces/SKILL.md +++ b/resources/boost/skills/interfaces/SKILL.md @@ -1,6 +1,11 @@ --- name: interfaces description: Contracts defining the shape a class must conform to. Used for decoupling dependent classes from concrete implementations, enabling multiple implementations and easier testing. +compatible_agents: + - architect + - implement + - refactor + - review --- **Name:** Interfaces & Contracts diff --git a/resources/boost/skills/jobs/SKILL.md b/resources/boost/skills/jobs/SKILL.md index 119f97d..5175d05 100644 --- a/resources/boost/skills/jobs/SKILL.md +++ b/resources/boost/skills/jobs/SKILL.md @@ -1,6 +1,11 @@ --- name: jobs description: Queueable units of work for background processing. Jobs handle queue configuration and failure handling — they delegate business logic to Actions or Services. +compatible_agents: + - architect + - implement + - refactor + - review --- **Name:** Jobs diff --git a/resources/boost/skills/livewire/SKILL.md b/resources/boost/skills/livewire/SKILL.md index f9be2d6..3cfb881 100644 --- a/resources/boost/skills/livewire/SKILL.md +++ b/resources/boost/skills/livewire/SKILL.md @@ -1,6 +1,10 @@ --- name: livewire description: Laravel Livewire conventions for building interactive UI without custom JavaScript. Components are PHP classes with reactive properties, computed properties, and event dispatching. +compatible_agents: + - implement + - refactor + - review --- **Name:** Livewire Components diff --git a/resources/boost/skills/middleware/SKILL.md b/resources/boost/skills/middleware/SKILL.md index 560fb98..dc7fc6f 100644 --- a/resources/boost/skills/middleware/SKILL.md +++ b/resources/boost/skills/middleware/SKILL.md @@ -1,6 +1,10 @@ --- name: middleware description: HTTP request/response pipeline handlers that inspect, modify, or reject requests before or after they reach a controller. Used for authentication, throttling, header manipulation, and logging. +compatible_agents: + - implement + - refactor + - review --- **Name:** Middleware diff --git a/resources/boost/skills/migrations/SKILL.md b/resources/boost/skills/migrations/SKILL.md index bdb4cac..6072bc7 100644 --- a/resources/boost/skills/migrations/SKILL.md +++ b/resources/boost/skills/migrations/SKILL.md @@ -1,6 +1,11 @@ --- name: migrations description: Database schema change files. Always create new files for changes — never modify existing migrations. Use descriptive names, proper foreign key constraints, and reversible `down()` methods. +compatible_agents: + - architect + - implement + - refactor + - review --- **Name:** Migrations diff --git a/resources/boost/skills/models/SKILL.md b/resources/boost/skills/models/SKILL.md index 45444b7..840b7bd 100644 --- a/resources/boost/skills/models/SKILL.md +++ b/resources/boost/skills/models/SKILL.md @@ -1,23 +1,62 @@ --- name: models description: Eloquent model conventions covering mass assignment, casts, relationships, section headers, and activity logging. Every model must follow these structural rules. +compatible_agents: + - architect + - implement + - refactor + - review --- -**Name:** Models -**Description:** Eloquent model conventions covering mass assignment, casts, relationships, section headers, and activity logging. Every model must follow these structural rules. -**Compatible Agents:** general-purpose, backend +# Models + +**Name:** Models +**Description:** Eloquent model conventions covering mass assignment, casts, relationships, section headers, and activity logging. Every model must follow these structural rules. +**Compatible Agents:** general-purpose, backend **Tags:** app/Models/**/*.php, laravel, php, backend, eloquent, model, database -## Rules +## When to Apply + +- When creating a new Eloquent model in `app/Models/`. +- When refactoring existing models to align with mass-assignment, casting, and logging conventions. +- When reviewing models for consistency in relationships, helpers, and activity logging. + +## Preconditions + +- Laravel application and Eloquent are configured. +- Database schema and migrations for the model’s table exist or are being designed. +- `spatie/laravel-activitylog` is installed and configured for activity logging. + +## Process + +### 1. Configure Mass Assignment and Casting + +- Set `protected $guarded = [];` on all business models; **do not** use `$fillable`. +- Implement a `casts()` method instead of a `$casts` property. +- In `casts()`, configure: + - Enums, dates, decimals, and JSON fields with explicit types (e.g., `decimal:2`). + +### 2. Add Activity Logging -- Use `$guarded = []` — never use `$fillable` arrays -- Define `casts()` as a **method**, not a property -- Cast enums, dates, decimals, and JSON in `casts()` -- Add the `LogsActivity` trait on all business models -- Configure `getActivitylogOptions()` with `logAll()`, `logOnlyDirty()`, `dontSubmitEmptyLogs()` -- Use typed return types on all relationship methods (`HasMany`, `BelongsTo`, etc.) -- Every new model must have a corresponding factory in `database/factories/` -- Group model code with section comment headers: `// --- Relationships ---`, `// --- Status Helpers ---`, etc. +- Use the `LogsActivity` trait on all business models that should be audited. +- Implement `getActivitylogOptions()` to: + - Call `logAll()`. + - Call `logOnlyDirty()`. + - Call `dontSubmitEmptyLogs()`. + +### 3. Define Relationships and Helpers + +- Use typed return types on all relationship methods (`HasMany`, `BelongsTo`, etc.). +- Group related sections of the model with comment headers such as: + - `// --- Relationships ---` + - `// --- Status Helpers ---` + - `// --- Activity Log ---` +- Keep domain-specific helper methods focused and clearly named (e.g., `isDraft()`, `isPaid()`). + +### 4. Ensure Testability and Factories + +- Create a corresponding factory for every model under `database/factories/`. +- Ensure factories cover required attributes and common state variants. ## Examples @@ -75,14 +114,27 @@ class Invoice extends Model } ``` -## Anti-Patterns +## Checklists + +### Execution Checklist + +- [ ] Model uses `$guarded = []` and **does not** define `$fillable`. +- [ ] Casting is implemented via a `casts()` method, not a `$casts` property. +- [ ] Enums, dates, decimals, and JSON fields are explicitly cast. +- [ ] `LogsActivity` trait is added where auditing is required. +- [ ] `getActivitylogOptions()` is configured with `logAll()`, `logOnlyDirty()`, and `dontSubmitEmptyLogs()`. +- [ ] All relationship methods have correct typed return types. +- [ ] A matching factory exists in `database/factories/`. +- [ ] Business logic is extracted to Actions or Services instead of living directly in the model. + +## Safety / Things to Avoid -- Using `$fillable` arrays instead of `$guarded = []` -- Defining `$casts` as a property instead of a `casts()` method -- Not using the `LogsActivity` trait on business models -- Omitting return types on relationship methods -- Creating a model without a corresponding factory -- Putting business logic directly in the model — use Actions +- Using `$fillable` arrays instead of `$guarded = []`. +- Defining `$casts` as a property instead of a `casts()` method. +- Omitting the `LogsActivity` trait on business models that should be audited. +- Omitting return types on relationship methods. +- Creating a model without a corresponding factory. +- Putting complex business logic directly in the model — prefer Actions or Services. ## References diff --git a/resources/boost/skills/observers/SKILL.md b/resources/boost/skills/observers/SKILL.md index 86eb8b4..8671630 100644 --- a/resources/boost/skills/observers/SKILL.md +++ b/resources/boost/skills/observers/SKILL.md @@ -1,6 +1,11 @@ --- name: observers description: Centralised classes that react to Eloquent model lifecycle events. Used for side effects that should always fire regardless of where a model is mutated — such as notifications, cache invalidation, and audit logging. +compatible_agents: + - architect + - implement + - refactor + - review --- **Name:** Observers diff --git a/resources/boost/skills/pesttesting/SKILL.md b/resources/boost/skills/pesttesting/SKILL.md index 83783e5..6da4157 100644 --- a/resources/boost/skills/pesttesting/SKILL.md +++ b/resources/boost/skills/pesttesting/SKILL.md @@ -1,6 +1,10 @@ --- name: pesttesting description: Laravel testing conventions using the Pest PHP framework. Covers test structure, AAA pattern, HTTP assertions, datasets, mocking, browser tests, and architecture tests. +compatible_agents: + - test + - refactor + - review --- **Name:** Pest Testing diff --git a/resources/boost/skills/php/SKILL.md b/resources/boost/skills/php/SKILL.md index ef8e6e7..a105f2e 100644 --- a/resources/boost/skills/php/SKILL.md +++ b/resources/boost/skills/php/SKILL.md @@ -1,6 +1,11 @@ --- name: php description: General PHP coding standards covering strict typing, formatting, control flow, and error handling. Applies to all PHP files in the application. +compatible_agents: + - architect + - implement + - refactor + - review --- **Name:** PHP Conventions diff --git a/resources/boost/skills/phpstan/SKILL.md b/resources/boost/skills/phpstan/SKILL.md index 6250f82..57f88ef 100644 --- a/resources/boost/skills/phpstan/SKILL.md +++ b/resources/boost/skills/phpstan/SKILL.md @@ -3,21 +3,49 @@ name: phpstan description: Static analysis tool configured at Level 9. All code must pass PHPStan Level 9 with strict typing, no untyped signatures, and minimal suppression of errors. --- -**Name:** PHPStan -**Description:** Static analysis tool configured at Level 9. All code must pass PHPStan Level 9 with strict typing, no untyped signatures, and minimal suppression of errors. -**Compatible Agents:** general-purpose, testing, backend +# PHPStan + +**Name:** PHPStan +**Description:** Static analysis tool configured at Level 9. All code must pass PHPStan Level 9 with strict typing, no untyped signatures, and minimal suppression of errors. +**Compatible Agents:** general-purpose, testing, backend **Tags:** app/**/*.php, tests/**/*.php, laravel, php, static-analysis, phpstan, types -## Rules +## When to Apply + +- After implementing or refactoring PHP code in `app/**` or `tests/**`. +- Before merging pull requests to ensure static analysis passes. +- When raising PHP or PHPStan levels or tightening type strictness. + +## Preconditions + +- PHP, Composer dependencies, and PHPStan are installed. +- `phpstan.neon` (and baseline, if any) are present and understood. +- The working tree contains the relevant changes you want to analyze. + +## Process + +### 1. Run PHPStan and Review Findings + +- Run PHPStan over the relevant scope (project default or narrowed paths). +- Capture and review all reported errors: + - Identify missing or weak type hints. + - Look for untyped signatures and `mixed` usage. + - Note any `@phpstan-ignore` usage and whether it is justified. + +### 2. Strengthen Types and Annotations -- All code must pass **PHPStan Level 9** -- Type hints on all parameters, return types, and properties — no untyped signatures -- No `@phpstan-ignore` unless documented with a justification comment -- Use `phpstan-assert`, `phpstan-param`, and `phpstan-return` PHPDoc tags when generics or complex types are needed -- Replace `mixed` with specific union types where possible -- Use `array` instead of bare `array` in PHPDoc -- Add `@throws` annotations for methods that throw exceptions -- Use `assert()` or type narrowing instead of suppressing errors +- Ensure **all parameters, return types, and properties are typed** wherever possible. +- Replace broad `mixed` types with more specific union types. +- Use `array` or more precise shapes instead of bare `array` in PHPDoc. +- Add `@throws` annotations to methods that can throw exceptions. +- Use `phpstan-assert`, `phpstan-param`, and `phpstan-return` tags when generics or advanced shapes are needed. + +### 3. Prefer Narrowing to Suppression + +- Use runtime type narrowing (for example, `assert()`, `instanceof`) instead of suppressing errors. +- When suppression is unavoidable: + - Limit it to the narrowest possible scope. + - Add a clear justification comment. ## Examples @@ -70,17 +98,32 @@ public function handle(mixed $model): void $user->custom_attribute; ``` -## Anti-Patterns +## Checklists + +### Execution Checklist + +- [ ] Ran PHPStan over the relevant scope (full project or narrowed paths). +- [ ] Ensured all parameters, properties, and return types are typed where possible. +- [ ] Replaced bare `mixed` and `array` usages with more specific types or PHPDoc generics. +- [ ] Added `@throws` annotations to methods that can throw. +- [ ] Used type narrowing and assertions instead of broad suppressions. +- [ ] Any remaining `@phpstan-ignore` usages are justified with clear comments. -- Using bare `mixed` types when a more specific type is possible -- Using bare `array` without a PHPDoc generic shape: `array` -- Using `@phpstan-ignore` without a comment explaining why it is necessary -- Omitting `@throws` annotations on methods that throw -- Leaving parameters, return types, or properties untyped -- Using `(int)`, `(string)` casts as substitutes for proper type narrowing +## Safety / Things to Avoid + +- Using bare `mixed` when a more specific type is possible. +- Using bare `array` without a PHPDoc generic shape such as `array`. +- Using `@phpstan-ignore` without an explanation of why it is necessary. +- Omitting `@throws` annotations on methods that throw. +- Leaving parameters, properties, or return types untyped. +- Relying on `(int)` or `(string)` casts as substitutes for proper type narrowing. ## References - [PHPStan Documentation](https://phpstan.org/user-guide/getting-started) - [PHPStan Rule Levels](https://phpstan.org/user-guide/rule-levels) - Related: `PHP/SKILL.md` — general PHP conventions including strict typing + +## Further reading + +For a detailed workflow (when to apply, preconditions, iterative fixing, verification), see [docs/skills/phpstan-analysis.md](../../../../docs/skills/phpstan-analysis.md). diff --git a/resources/boost/skills/phpunit/SKILL.md b/resources/boost/skills/phpunit/SKILL.md index 0055bbe..049dd5a 100644 --- a/resources/boost/skills/phpunit/SKILL.md +++ b/resources/boost/skills/phpunit/SKILL.md @@ -1,6 +1,10 @@ --- name: phpunit description: PHPUnit test structure, naming, assertions, and factory conventions for Laravel feature and unit tests. +compatible_agents: + - test + - refactor + - review --- **Name:** PHPUnit diff --git a/resources/boost/skills/policies/SKILL.md b/resources/boost/skills/policies/SKILL.md index be6be4f..0361d5b 100644 --- a/resources/boost/skills/policies/SKILL.md +++ b/resources/boost/skills/policies/SKILL.md @@ -1,6 +1,11 @@ --- name: policies description: Centralised authorization logic for a given Eloquent model. Policies define per-ability access control and are enforced at the controller level. +compatible_agents: + - architect + - implement + - refactor + - review --- **Name:** Policies diff --git a/resources/boost/skills/requests/SKILL.md b/resources/boost/skills/requests/SKILL.md index bfeca18..6089955 100644 --- a/resources/boost/skills/requests/SKILL.md +++ b/resources/boost/skills/requests/SKILL.md @@ -1,6 +1,10 @@ --- name: requests description: Dedicated Form Request validation classes for all controller input. Every endpoint that accepts user input must use a `FormRequest` class — validation never happens directly inside a controller. +compatible_agents: + - implement + - refactor + - review --- **Name:** Form Request Validation diff --git a/resources/boost/skills/resources/SKILL.md b/resources/boost/skills/resources/SKILL.md index 04097fc..1a4adb4 100644 --- a/resources/boost/skills/resources/SKILL.md +++ b/resources/boost/skills/resources/SKILL.md @@ -1,6 +1,10 @@ --- name: resources description: API resource classes that transform Eloquent models into JSON-ready arrays. Resources control exactly what is exposed in API responses and handle relationships, conditional attributes, and date formatting. +compatible_agents: + - implement + - refactor + - review --- **Name:** Resources diff --git a/resources/boost/skills/routing/SKILL.md b/resources/boost/skills/routing/SKILL.md index d10a851..c9c9ce3 100644 --- a/resources/boost/skills/routing/SKILL.md +++ b/resources/boost/skills/routing/SKILL.md @@ -1,6 +1,11 @@ --- name: routing description: Route file conventions for organising API and web routes. Covers file separation, naming, grouping, middleware, and route model binding. +compatible_agents: + - architect + - implement + - refactor + - review --- **Name:** Routing diff --git a/resources/boost/skills/saloon/SKILL.md b/resources/boost/skills/saloon/SKILL.md index 5aa7189..095a65d 100644 --- a/resources/boost/skills/saloon/SKILL.md +++ b/resources/boost/skills/saloon/SKILL.md @@ -1,6 +1,11 @@ --- name: saloon description: Saloon-based service layer pattern for all external API integrations. Every new external API integration must use Saloon — no raw HTTP calls. +compatible_agents: + - architect + - implement + - refactor + - review --- **Name:** Saloon API Integration diff --git a/resources/boost/skills/services/SKILL.md b/resources/boost/skills/services/SKILL.md index fa78512..57e7147 100644 --- a/resources/boost/skills/services/SKILL.md +++ b/resources/boost/skills/services/SKILL.md @@ -3,22 +3,56 @@ name: services description: Orchestration classes that coordinate multiple Actions, external APIs, or domain operations into a cohesive workflow. Services own transaction boundaries and third-party API integrations. --- -**Name:** Services -**Description:** Orchestration classes that coordinate multiple Actions, external APIs, or domain operations into a cohesive workflow. Services own transaction boundaries and third-party API integrations. -**Compatible Agents:** general-purpose, backend +# Services + +**Name:** Services +**Description:** Orchestration classes that coordinate multiple Actions, external APIs, or domain operations into a cohesive workflow. Services own transaction boundaries and third-party API integrations. +**Compatible Agents:** general-purpose, backend **Tags:** app/Services/**/*.php, laravel, php, backend, service, orchestration, api-integration -## Rules +## When to Apply + +- When coordinating **multi-step workflows** that span multiple models or domains. +- When wrapping **third-party SDKs or APIs** behind a stable internal interface. +- When you need to own transaction boundaries across several operations. +- When logic is reused from multiple controllers, jobs, or listeners and is **broader than a single Action**. + +## Preconditions + +- The Laravel project is configured with a database connection and, where needed, queue workers. +- Required Actions and models already exist or have clear designs. +- Third-party SDKs or HTTP clients (for example, Saloon) are installed and configured. + +## Process + +### 1. Decide Between Action and Service + +- Use a Service when: + - The workflow coordinates multiple Actions or external calls. + - The logic spans multiple domains or aggregates several operations into a cohesive flow. +- Use an Action when the behavior is a **single, focused business operation**. + +### 2. Design the Service -- Service classes live in `app/Services/` -- Name after the domain or integration they serve: `PaymentService`, `SubscriptionService`, `StripeService` -- Avoid generic suffixes like `Manager` or `Handler` -- Services may expose multiple related methods, all scoped to their domain -- Inject dependencies via the constructor -- Use `DB::transaction()` for multi-step operations that must all succeed or fail together -- Wrap third-party SDKs behind a service class with a clean internal interface -- Register external service wrappers as singletons in a service provider -- Use Actions for individual discrete operations — a Service orchestrates multiple Actions +- Place the class in `app/Services/`. +- Name the Service after the domain or integration it serves: + - Examples: `PaymentService`, `SubscriptionService`, `StripeService`. +- Avoid vague or generic suffixes such as `Manager` or `Handler`. +- Inject dependencies via the constructor: + - Actions, repositories, external API clients, etc. + +### 3. Implement Orchestration and Transactions + +- For multi-step operations that must all succeed or fail together: + - Wrap the logic in `DB::transaction()`. +- Call individual Actions or lower-level services inside the transaction where appropriate. +- Keep public methods cohesive and domain-focused (for example, `processOrderPayment`, `refund`). + +### 4. Integrate External Services + +- Wrap external SDKs and APIs behind Service classes with clean methods. +- Register external service wrappers as **singletons** in a service provider to centralize configuration. +- Keep HTTP-specific or SDK-specific details inside the Service; expose domain-centric methods to callers. ## Examples @@ -79,14 +113,26 @@ class PaymentController extends Controller } ``` -## Anti-Patterns +## Checklists + +### Execution Checklist + +- [ ] Confirmed the workflow spans multiple steps or domains and is appropriate for a Service. +- [ ] Created or updated a class under `app/Services/` with a domain-specific name. +- [ ] Injected required Actions, models, and API clients via the constructor. +- [ ] Wrapped multi-step operations that must succeed together in `DB::transaction()`. +- [ ] Exposed clear, domain-focused public methods (for example, `processOrderPayment`, `refund`). +- [ ] Registered external integrations as singletons in a service provider when needed. +- [ ] Controllers, jobs, or listeners delegate orchestration logic to the Service. + +## Safety / Things to Avoid -- Using a Service for a single discrete operation (use an Action instead) -- Putting HTTP concerns (request, response) inside a Service -- Naming a service `DataManager` or `UserHandler` instead of a domain-specific name -- Putting model attribute logic in a Service (belongs in the Model) -- Putting authorization in a Service (belongs in Policies) -- Making raw HTTP calls instead of using Saloon for external API integrations +- Using a Service for a single discrete operation (use an Action instead). +- Putting HTTP concerns (request, response) inside a Service. +- Naming a service `DataManager`, `UserHandler`, or other generic names instead of a domain-specific name. +- Putting model attribute or persistence logic in a Service that belongs in the Model. +- Putting authorization checks inside a Service (keep them in Policies, controllers, or middleware). +- Making raw HTTP calls directly instead of using the project’s standard integration layer (for example, Saloon). ## References diff --git a/resources/boost/skills/tailwind/SKILL.md b/resources/boost/skills/tailwind/SKILL.md index b127254..c5926f3 100644 --- a/resources/boost/skills/tailwind/SKILL.md +++ b/resources/boost/skills/tailwind/SKILL.md @@ -1,6 +1,10 @@ --- name: tailwind description: Tailwind CSS v4 styling conventions. Use when working with CSS, Tailwind utilities, or customizing the theme in Laravel projects. +compatible_agents: + - implement + - refactor + - review --- **Name:** Tailwind CSS diff --git a/resources/boost/skills/traits/SKILL.md b/resources/boost/skills/traits/SKILL.md index 3988056..b85c439 100644 --- a/resources/boost/skills/traits/SKILL.md +++ b/resources/boost/skills/traits/SKILL.md @@ -1,6 +1,11 @@ --- name: traits description: Reusable behaviour shared across multiple unrelated classes. Traits provide shared Eloquent scopes, accessors, lifecycle hooks, and small stateless helper methods. +compatible_agents: + - architect + - implement + - refactor + - review --- **Name:** Traits diff --git a/resources/boost/skills/translations/SKILL.md b/resources/boost/skills/translations/SKILL.md index 498118d..bf08360 100644 --- a/resources/boost/skills/translations/SKILL.md +++ b/resources/boost/skills/translations/SKILL.md @@ -1,6 +1,10 @@ --- name: translations description: Translation and localization conventions for Laravel. Use when adding user-facing strings, creating translation files, or working with lang/ directory. +compatible_agents: + - implement + - refactor + - review --- **Name:** Translations diff --git a/scripts/sync-guidelines.php b/scripts/sync-guidelines.php deleted file mode 100644 index 66eccd9..0000000 --- a/scripts/sync-guidelines.php +++ /dev/null @@ -1,45 +0,0 @@ -&1", $remoteOutput, $remoteExit); - exec("git -C {$targetDir} fetch origin main --quiet 2>&1", $fetchOutput, $fetchExit); - if ($fetchExit === 0) { - exec("git -C {$targetDir} reset --hard FETCH_HEAD 2>&1", $resetOutput, $exitCode); - } else { - $exitCode = $fetchExit; - } -} else { - exec("git clone --depth 1 --quiet {$repo} {$targetDir} 2>&1", $output, $exitCode); -} - -if ($exitCode !== 0) { - echo 'Warning: Could not sync guidelines (repo not accessible).'.PHP_EOL; - exit(0); // Don't break composer install -} - -echo "Guidelines synced to {$targetDir}/.".PHP_EOL; - -// Copy refactor.md to .cursor/commands/ for Cursor slash commands -$refactorSource = __DIR__.'/../refactor.md'; -$commandsDir = '.cursor/commands'; -$refactorDest = $commandsDir.'/refactor.md'; - -if (file_exists($refactorSource)) { - if (! is_dir($commandsDir)) { - mkdir($commandsDir, 0755, true); - } - if (copy($refactorSource, $refactorDest)) { - echo "Refactor command copied to {$refactorDest}.".PHP_EOL; - } -} diff --git a/scripts/validate-skills.php b/scripts/validate-skills.php deleted file mode 100644 index 5a7e9a0..0000000 --- a/scripts/validate-skills.php +++ /dev/null @@ -1,74 +0,0 @@ -#!/usr/bin/env php -app->runningInConsole()) { - $this->commands([ - SyncRefactorCommand::class, - ]); - } - } -} diff --git a/src/Composer/RefactorCommandPlugin.php b/src/Composer/RefactorCommandPlugin.php deleted file mode 100644 index de3ab3a..0000000 --- a/src/Composer/RefactorCommandPlugin.php +++ /dev/null @@ -1,60 +0,0 @@ -composer = $composer; - $this->io = $io; - } - - public function deactivate(Composer $composer, IOInterface $io): void - { - // Nothing to clean up. - } - - public function uninstall(Composer $composer, IOInterface $io): void - { - // Keep user's .cursor/commands/refactor.md file untouched on uninstall. - } - - /** - * @return array - */ - public static function getSubscribedEvents(): array - { - return [ - ScriptEvents::POST_INSTALL_CMD => 'syncRefactorCommand', - ScriptEvents::POST_UPDATE_CMD => 'syncRefactorCommand', - ScriptEvents::POST_AUTOLOAD_DUMP => 'syncRefactorCommand', - ]; - } - - public function syncRefactorCommand(Event $event): void - { - $composer = $this->composer ?? $event->getComposer(); - $io = $this->io ?? $event->getIO(); - - $vendorDir = (string) $composer->getConfig()->get('vendor-dir'); - $projectRoot = dirname($vendorDir); - $packageRoot = dirname(__DIR__, 2); - - RefactorCommandSynchronizer::sync($projectRoot, $packageRoot, $io); - } -} diff --git a/src/Console/SyncRefactorCommand.php b/src/Console/SyncRefactorCommand.php deleted file mode 100644 index f2d0eeb..0000000 --- a/src/Console/SyncRefactorCommand.php +++ /dev/null @@ -1,33 +0,0 @@ -info('Refactor command is ready at .cursor/commands/refactor.md'); - - return 0; - } - - $this->warn('Could not sync refactor command.'); - - return 1; - } -} diff --git a/src/Support/RefactorCommandSynchronizer.php b/src/Support/RefactorCommandSynchronizer.php deleted file mode 100644 index e831328..0000000 --- a/src/Support/RefactorCommandSynchronizer.php +++ /dev/null @@ -1,53 +0,0 @@ -[coding-guidelines] refactor.md not found, skipping sync.'); - - return false; - } - - if (! is_dir($commandsDir) && ! mkdir($commandsDir, 0755, true) && ! is_dir($commandsDir)) { - self::write($io, '[coding-guidelines] Could not create .cursor/commands directory.'); - - return false; - } - - $sourceHash = hash_file('sha256', $source); - $destinationHash = is_file($destination) ? hash_file('sha256', $destination) : null; - - if ($sourceHash === $destinationHash) { - self::write($io, '[coding-guidelines] /refactor command already up to date.'); - - return true; - } - - if (! copy($source, $destination)) { - self::write($io, '[coding-guidelines] Failed to copy refactor.md.'); - - return false; - } - - self::write($io, '[coding-guidelines] Synced /refactor command to .cursor/commands/refactor.md'); - - return true; - } - - private static function write(mixed $io, string $message): void - { - if (is_object($io) && method_exists($io, 'write')) { - $io->write($message); - } - } -} diff --git a/tests/Feature/SkillValidationTest.php b/tests/Feature/SkillValidationTest.php new file mode 100644 index 0000000..120b88e --- /dev/null +++ b/tests/Feature/SkillValidationTest.php @@ -0,0 +1,87 @@ +markTestSkipped('ANTHROPIC_API_KEY is not set; skipping AI-based skill validation.'); + } + + $root = dirname(__DIR__, 2); + $skillsRoot = $root.'/resources/boost/skills'; + + if (! is_dir($skillsRoot)) { + $this->markTestSkipped('resources/boost/skills directory not found; skipping skill validation.'); + } + + $finder = new Finder; + $finder->files()->in($skillsRoot)->name('SKILL.md'); + + foreach ($finder as $file) { + $relativePath = ltrim(str_replace($root.'/', '', $file->getPathname()), '/'); + $absolutePath = $file->getPathname(); + $markdown = (string) file_get_contents($absolutePath); + + $model = env('ANTHROPIC_MODEL', 'claude-3-5-sonnet@20240620'); + + $agent = new SkillQualityAgent; + + $response = $agent->prompt( + prompt: <<, + * warnings: array, + * improvements: array + * } $result + */ + $result = [ + 'skill_name' => $response['skill_name'], + 'path' => $response['path'], + 'valid' => (bool) $response['valid'], + 'errors' => $response['errors'], + 'warnings' => $response['warnings'], + 'improvements' => $response['improvements'], + ]; + + if ($result['errors'] !== []) { + fwrite( + STDERR, + PHP_EOL.'Skill validation errors for '.$relativePath.':'.PHP_EOL.' - '.implode(PHP_EOL.' - ', $result['errors']).PHP_EOL + ); + } + + if ($result['warnings'] !== [] || $result['improvements'] !== []) { + fwrite( + STDOUT, + PHP_EOL.'Skill validation hints for '.$relativePath.':'.PHP_EOL. + 'Warnings:'.PHP_EOL.' - '.implode(PHP_EOL.' - ', $result['warnings'] ?: ['(none)']).PHP_EOL. + 'Improvements:'.PHP_EOL.' - '.implode(PHP_EOL.' - ', $result['improvements'] ?: ['(none)']).PHP_EOL + ); + } + + expect($result['valid'])->toBeTrue() + ->and($result['errors'])->toBe([]); + } +})->group('skills'); diff --git a/tests/Pest.php b/tests/Pest.php new file mode 100644 index 0000000..772f294 --- /dev/null +++ b/tests/Pest.php @@ -0,0 +1,7 @@ +in('Feature'); diff --git a/tests/Support/Agents/SkillQualityAgent.php b/tests/Support/Agents/SkillQualityAgent.php new file mode 100644 index 0000000..fc88232 --- /dev/null +++ b/tests/Support/Agents/SkillQualityAgent.php @@ -0,0 +1,76 @@ + $schema->string()->required(), + 'path' => $schema->string()->required(), + 'valid' => $schema->boolean()->required(), + 'errors' => $schema->array( + $schema->string() + )->required(), + 'warnings' => $schema->array( + $schema->string() + )->required(), + 'improvements' => $schema->array( + $schema->string() + )->required(), + ]; + } +} diff --git a/tests/TestCase.php b/tests/TestCase.php new file mode 100644 index 0000000..484e299 --- /dev/null +++ b/tests/TestCase.php @@ -0,0 +1,23 @@ + + */ + protected function getPackageProviders($app): array + { + return [ + AiServiceProvider::class, + PrismServiceProvider::class, + ]; + } +} From 9c2974f3ff49b2fde5c4b774067836ca6c05ad10 Mon Sep 17 00:00:00 2001 From: Sebastian Fix Date: Tue, 3 Mar 2026 09:39:58 +0100 Subject: [PATCH 2/5] Updated Core --- .gitignore | 4 +- README.md | 8 ++ tests/Feature/SkillValidationTest.php | 74 +++--------- .../Support/Console/ValidateSkillsCommand.php | 77 ++++++++++++ tests/Support/Jobs/ValidateSkillJob.php | 114 ++++++++++++++++++ 5 files changed, 219 insertions(+), 58 deletions(-) create mode 100644 tests/Support/Console/ValidateSkillsCommand.php create mode 100644 tests/Support/Jobs/ValidateSkillJob.php diff --git a/.gitignore b/.gitignore index 1d246ce..ac41e1b 100644 --- a/.gitignore +++ b/.gitignore @@ -28,4 +28,6 @@ coverage/ phpunit.xml -.cursor/ \ No newline at end of file +.cursor/ + +storage/logs/* \ No newline at end of file diff --git a/README.md b/README.md index ff41396..1446f15 100644 --- a/README.md +++ b/README.md @@ -274,3 +274,11 @@ This package validates its own skills using Pest and the [Laravel AI SDK](https: - **PHPUnit config**: `phpunit.xml.dist` is committed; copy to `phpunit.xml` (gitignored) for local overrides. The `.github/workflows/skills-validation.yml` workflow runs these checks on pushes and pull requests. Configure `ANTHROPIC_API_KEY` and `ANTHROPIC_MODEL` as GitHub secrets. + +Under the hood, skills validation is performed by a small Laravel AI agent and a queued job: + +- **Dispatch**: a `skills:validate` console command discovers each `resources/boost/skills/**/SKILL.md` file and dispatches a validation job per file. +- **Execution**: each job calls the Laravel AI agent once, then appends a JSON line with the input markdown, structured output, and any provider usage metadata to `storage/logs/skills-validation.log`. +- **Provider overloads**: if the Anthropic provider is temporarily overloaded, the job records an `overloaded` status for that skill instead of failing the whole test run. + +To keep CI stable, the Pest feature test for skills only asserts **that the correct jobs are dispatched**; the actual AI calls and token usage reporting happen inside the queued jobs. diff --git a/tests/Feature/SkillValidationTest.php b/tests/Feature/SkillValidationTest.php index 120b88e..833a967 100644 --- a/tests/Feature/SkillValidationTest.php +++ b/tests/Feature/SkillValidationTest.php @@ -2,8 +2,9 @@ declare(strict_types=1); -use CodebarAg\CodingGuidelines\Tests\Support\Agents\SkillQualityAgent; -use Laravel\Ai\Enums\Lab; +use CodebarAg\CodingGuidelines\Tests\Support\Console\ValidateSkillsCommand; +use CodebarAg\CodingGuidelines\Tests\Support\Jobs\ValidateSkillJob; +use Illuminate\Support\Facades\Bus; use Symfony\Component\Finder\Finder; it('validates each SKILL.md with Laravel AI', function (): void { @@ -23,65 +24,24 @@ $finder = new Finder; $finder->files()->in($skillsRoot)->name('SKILL.md'); - foreach ($finder as $file) { - $relativePath = ltrim(str_replace($root.'/', '', $file->getPathname()), '/'); - $absolutePath = $file->getPathname(); - $markdown = (string) file_get_contents($absolutePath); - - $model = env('ANTHROPIC_MODEL', 'claude-3-5-sonnet@20240620'); - - $agent = new SkillQualityAgent; + Bus::fake(); - $response = $agent->prompt( - prompt: <<setLaravel(app()); + $command->run(new \Symfony\Component\Console\Input\ArrayInput([]), new \Symfony\Component\Console\Output\NullOutput); -Relative path: {$relativePath} + $model = env('ANTHROPIC_MODEL', 'claude-3-5-sonnet@20240620'); + $expectedJobs = iterator_to_array($finder); -SKILL.md contents: ------------------- -{$markdown} ------------------- -PROMPT, - provider: Lab::Anthropic, - model: $model, - ); + Bus::assertDispatched(ValidateSkillJob::class, count($expectedJobs)); - /** @var array{ - * skill_name: string, - * path: string, - * valid: bool, - * errors: array, - * warnings: array, - * improvements: array - * } $result - */ - $result = [ - 'skill_name' => $response['skill_name'], - 'path' => $response['path'], - 'valid' => (bool) $response['valid'], - 'errors' => $response['errors'], - 'warnings' => $response['warnings'], - 'improvements' => $response['improvements'], - ]; - - if ($result['errors'] !== []) { - fwrite( - STDERR, - PHP_EOL.'Skill validation errors for '.$relativePath.':'.PHP_EOL.' - '.implode(PHP_EOL.' - ', $result['errors']).PHP_EOL - ); - } - - if ($result['warnings'] !== [] || $result['improvements'] !== []) { - fwrite( - STDOUT, - PHP_EOL.'Skill validation hints for '.$relativePath.':'.PHP_EOL. - 'Warnings:'.PHP_EOL.' - '.implode(PHP_EOL.' - ', $result['warnings'] ?: ['(none)']).PHP_EOL. - 'Improvements:'.PHP_EOL.' - '.implode(PHP_EOL.' - ', $result['improvements'] ?: ['(none)']).PHP_EOL - ); - } + foreach ($expectedJobs as $file) { + $relativePath = ltrim(str_replace($root.'/', '', $file->getPathname()), '/'); - expect($result['valid'])->toBeTrue() - ->and($result['errors'])->toBe([]); + Bus::assertDispatched(ValidateSkillJob::class, function (ValidateSkillJob $job) use ($relativePath, $root, $model) { + return $job->relativePath === $relativePath + && $job->root === $root + && $job->model === $model; + }); } })->group('skills'); diff --git a/tests/Support/Console/ValidateSkillsCommand.php b/tests/Support/Console/ValidateSkillsCommand.php new file mode 100644 index 0000000..48c0b15 --- /dev/null +++ b/tests/Support/Console/ValidateSkillsCommand.php @@ -0,0 +1,77 @@ +warn('ANTHROPIC_API_KEY is not set; skipping AI-based skill validation.'); + + return self::SUCCESS; + } + + $root = dirname(__DIR__, 3); + $skillsRoot = $root.'/resources/boost/skills'; + + if (! is_dir($skillsRoot)) { + $this->warn('resources/boost/skills directory not found; skipping skill validation.'); + + return self::SUCCESS; + } + + $logDir = $root.'/storage/logs'; + $logFile = $logDir.'/skills-validation.log'; + + if (! is_dir($logDir)) { + mkdir($logDir, 0777, true); + } + + file_put_contents($logFile, ''); + + $finder = new Finder; + $finder->files()->in($skillsRoot)->name('SKILL.md'); + + $model = (string) ($this->option('model') ?: env('ANTHROPIC_MODEL', 'claude-3-5-sonnet@20240620')); + $runSync = (bool) $this->option('sync'); + + foreach ($finder as $file) { + $relativePath = ltrim(str_replace($root.'/', '', $file->getPathname()), '/'); + + if ($runSync) { + (new ValidateSkillJob( + relativePath: $relativePath, + root: $root, + model: $model, + ))->handle(); + } else { + ValidateSkillJob::dispatch( + relativePath: $relativePath, + root: $root, + model: $model, + ); + } + } + + return self::SUCCESS; + } +} diff --git a/tests/Support/Jobs/ValidateSkillJob.php b/tests/Support/Jobs/ValidateSkillJob.php new file mode 100644 index 0000000..0f3bd6a --- /dev/null +++ b/tests/Support/Jobs/ValidateSkillJob.php @@ -0,0 +1,114 @@ +root.'/'.$this->relativePath; + + if (! is_file($absolutePath)) { + return; + } + + $markdown = (string) file_get_contents($absolutePath); + + $logDir = $this->root.'/storage/logs'; + $logFile = $logDir.'/skills-validation.log'; + + if (! is_dir($logDir)) { + mkdir($logDir, 0777, true); + } + + $agent = new SkillQualityAgent; + + try { + $response = $agent->prompt( + prompt: <<relativePath} + +SKILL.md contents: +------------------ +{$markdown} +------------------ +PROMPT, + provider: Lab::Anthropic, + model: $this->model, + ); + } catch (ProviderOverloadedException) { + $logEntry = [ + 'timestamp' => date(DATE_ATOM), + 'path' => $this->relativePath, + 'model' => $this->model, + 'valid' => false, + 'errors' => ['AI provider is overloaded; validation deferred.'], + 'warnings' => [], + 'improvements' => [], + 'status' => 'overloaded', + 'markdown' => $markdown, + ]; + + file_put_contents( + $logFile, + json_encode($logEntry, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES).PHP_EOL, + FILE_APPEND + ); + + return; + } + + $responseData = $response->toArray(); + + $result = [ + 'skill_name' => $responseData['skill_name'], + 'path' => $responseData['path'], + 'valid' => (bool) $responseData['valid'], + 'errors' => $responseData['errors'], + 'warnings' => $responseData['warnings'], + 'improvements' => $responseData['improvements'], + ]; + + $logEntry = [ + 'timestamp' => date(DATE_ATOM), + 'path' => $this->relativePath, + 'model' => $this->model, + 'valid' => $result['valid'], + 'errors' => $result['errors'], + 'warnings' => $result['warnings'], + 'improvements' => $result['improvements'], + 'markdown' => $markdown, + 'response' => $responseData, + ]; + + file_put_contents( + $logFile, + json_encode($logEntry, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES).PHP_EOL, + FILE_APPEND + ); + } +} From 98cd8218d8de75bd6be9f98c3f0e1f93ae71c7a4 Mon Sep 17 00:00:00 2001 From: Sebastian Fix Date: Tue, 3 Mar 2026 10:46:03 +0100 Subject: [PATCH 3/5] Updated Skills --- README.md | 15 +- phpunit.xml.dist | 3 +- resources/boost/skills/actions/SKILL.md | 36 +++- resources/boost/skills/albatros/SKILL.md | 78 ++++++- resources/boost/skills/blade/SKILL.md | 78 +++++-- resources/boost/skills/commands/SKILL.md | 79 ++++++-- resources/boost/skills/controllers/SKILL.md | 31 +-- resources/boost/skills/design/SKILL.md | 113 ++++++++--- resources/boost/skills/documentation/SKILL.md | 67 ++++-- resources/boost/skills/docuware/SKILL.md | 53 ++++- resources/boost/skills/dto/SKILL.md | 78 ++++--- resources/boost/skills/dusk/SKILL.md | 69 +++++-- resources/boost/skills/enums/SKILL.md | 25 ++- resources/boost/skills/events/SKILL.md | 76 +++++-- resources/boost/skills/exceptions/SKILL.md | 72 ++++++- resources/boost/skills/formrequests/SKILL.md | 29 ++- resources/boost/skills/general/SKILL.md | 121 +++++++---- .../boost/skills/helperfunctions/SKILL.md | 103 ++++------ resources/boost/skills/helpers/SKILL.md | 104 +++++++++- resources/boost/skills/interfaces/SKILL.md | 50 ++++- resources/boost/skills/jobs/SKILL.md | 123 +++++++++-- resources/boost/skills/livewire/SKILL.md | 53 +++-- resources/boost/skills/middleware/SKILL.md | 80 +++++--- resources/boost/skills/migrations/SKILL.md | 90 +++++++-- resources/boost/skills/models/SKILL.md | 13 +- resources/boost/skills/observers/SKILL.md | 43 +++- resources/boost/skills/pesttesting/SKILL.md | 92 +++++++-- resources/boost/skills/php/SKILL.md | 101 ++++++++- resources/boost/skills/phpstan/SKILL.md | 67 ++++-- resources/boost/skills/phpunit/SKILL.md | 71 +++++-- resources/boost/skills/policies/SKILL.md | 31 ++- resources/boost/skills/requests/SKILL.md | 78 ++++++- resources/boost/skills/resources/SKILL.md | 69 +++++-- resources/boost/skills/routing/SKILL.md | 124 ++++++++++-- resources/boost/skills/saloon/SKILL.md | 82 +++++++- resources/boost/skills/services/SKILL.md | 72 ++++++- resources/boost/skills/tailwind/SKILL.md | 68 +++++-- resources/boost/skills/traits/SKILL.md | 85 ++++++-- resources/boost/skills/translations/SKILL.md | 37 +++- tests/Feature/SkillValidationTest.php | 191 +++++++++++++++--- tests/Support/Agents/SkillQualityAgent.php | 4 + .../Support/Console/ValidateSkillsCommand.php | 2 +- tests/Support/Jobs/ValidateSkillJob.php | 98 ++++++--- .../Validation/SkillValidationQuality.php | 147 ++++++++++++++ 44 files changed, 2508 insertions(+), 593 deletions(-) create mode 100644 tests/Support/Validation/SkillValidationQuality.php diff --git a/README.md b/README.md index 1446f15..7070ec5 100644 --- a/README.md +++ b/README.md @@ -270,15 +270,18 @@ If your editor supports MCP (Model Context Protocol), configure it to use the Bo This package validates its own skills using Pest and the [Laravel AI SDK](https://laravel.com/docs/12.x/ai-sdk): - **Run locally**: `vendor/bin/pest --group=skills` -- **Environment**: Set `ANTHROPIC_API_KEY` and optionally `ANTHROPIC_MODEL` (default: `claude-3-5-sonnet@20240620`). +- **Environment**: Set `ANTHROPIC_API_KEY` and optionally `ANTHROPIC_MODEL` (default in `phpunit.xml.dist`: `claude-haiku-4-5`). +- **Retries**: optionally set `SKILL_VALIDATION_MAX_ATTEMPTS` (default: `3`) to control strict fail-after-retry behavior for temporary provider overloads. - **PHPUnit config**: `phpunit.xml.dist` is committed; copy to `phpunit.xml` (gitignored) for local overrides. The `.github/workflows/skills-validation.yml` workflow runs these checks on pushes and pull requests. Configure `ANTHROPIC_API_KEY` and `ANTHROPIC_MODEL` as GitHub secrets. -Under the hood, skills validation is performed by a small Laravel AI agent and a queued job: +Under the hood, skills validation is performed by a small Laravel AI agent and supports both direct test execution and queued batch execution: -- **Dispatch**: a `skills:validate` console command discovers each `resources/boost/skills/**/SKILL.md` file and dispatches a validation job per file. -- **Execution**: each job calls the Laravel AI agent once, then appends a JSON line with the input markdown, structured output, and any provider usage metadata to `storage/logs/skills-validation.log`. -- **Provider overloads**: if the Anthropic provider is temporarily overloaded, the job records an `overloaded` status for that skill instead of failing the whole test run. +- **Per-skill tests**: `vendor/bin/pest --group=skills` runs one live Anthropic validation test per `SKILL.md` file (currently 37 tests), so failures are isolated by file. +- **Batch command**: `skills:validate` discovers each `resources/boost/skills/**/SKILL.md` file and dispatches (or runs with `--sync`) one validation job per file. +- **Logging**: each validation appends JSON lines to `storage/logs/skills-validation.log`, including the input markdown, structured output, usage/token metadata, provider status, retry attempt metadata, and output-quality audit fields. +- **Strict overload handling**: both per-skill tests and queue jobs retry bounded times and then fail explicitly when Anthropic remains overloaded. +- **Queue safety**: queued batch validation keeps queue-level retries/backoff in `ValidateSkillJob` in addition to bounded in-job retries for transient overloads. -To keep CI stable, the Pest feature test for skills only asserts **that the correct jobs are dispatched**; the actual AI calls and token usage reporting happen inside the queued jobs. +CI now validates skills directly through the per-skill test dataset, while the queue command remains available for manual or maintenance batch runs. diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 0b0722d..98c615a 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -7,7 +7,8 @@ - + + diff --git a/resources/boost/skills/actions/SKILL.md b/resources/boost/skills/actions/SKILL.md index c93eb98..aead827 100644 --- a/resources/boost/skills/actions/SKILL.md +++ b/resources/boost/skills/actions/SKILL.md @@ -1,15 +1,15 @@ --- name: actions description: Single-purpose business logic classes that encapsulate one well-defined business operation. Actions are the primary location for business logic in Laravel applications, invoked from controllers, commands, or jobs. +compatible_agents: + - architect + - implement + - refactor + - review --- # Actions -**Name:** Actions -**Description:** Single-purpose business logic classes that encapsulate one well-defined business operation. Actions are the primary location for business logic in Laravel applications, invoked from controllers, commands, or jobs. -**Compatible Agents:** general-purpose, backend -**Tags:** app/Actions/**/*.php, laravel, php, backend, business-logic, action - ## When to Apply - When implementing or refactoring a **single business operation** that can be described in one sentence. @@ -17,11 +17,17 @@ description: Single-purpose business logic classes that encapsulate one well-def - When multiple entry points (controller, command, job, listener) should reuse the **same business logic**. - When aligning legacy code with the project’s pattern of **`app/Actions/` classes with `execute()`**. +## When Not to Use + +- Tiny, one-line behavior that naturally belongs on the model and has no reuse. +- Cross-domain orchestration with retries/workflows that should be a Service. +- HTTP boundary concerns (validation/response shaping) that belong in controllers/requests. + ## Preconditions - The Laravel project is installed and bootstrapped. - The `app/Actions/` directory exists (or will be created) and is autoloaded by Composer. -- Related models, notifications, events, and DTOs required by the action already exist or have a clear design. +- Related models, notifications, events, and DTOs required by the action already exist or have a clear design. If prerequisites are missing, create them first or narrow the Action scope. - Authorization and validation rules are defined at the controller, policy, or Form Request level. ## Process @@ -133,6 +139,12 @@ class GenerateInvoicesCommand extends Command - [ ] Ensured authorization is handled in controllers, policies, or Form Requests. - [ ] Updated controllers, commands, or jobs to **delegate to the Action** instead of duplicating logic. +## Testing Guidance + +- Add focused tests for each Action behavior branch (success/failure edge cases). +- Mock/fake external dependencies (mail, notifications, queue) and assert interaction boundaries. +- Keep integration coverage in feature tests where the Action is invoked from controllers/commands/jobs. + ## Safety / Things to Avoid - Putting HTTP concerns (`Request`, `Response`, redirects) inside an Action. @@ -142,6 +154,18 @@ class GenerateInvoicesCommand extends Command - Adding business logic in a constructor — keep it in `execute()`. - Performing database queries unrelated to the Action’s single responsibility. +```php +// Anti-pattern: Action doing orchestration + HTTP concerns +class ProcessInvoiceAction +{ + public function execute(Request $request): RedirectResponse + { + // Mixed responsibilities: validation, orchestration, and HTTP response + // Move validation/response to controller, orchestration to Service. + } +} +``` + ## References - [Laravel Service Container](https://laravel.com/docs/container) diff --git a/resources/boost/skills/albatros/SKILL.md b/resources/boost/skills/albatros/SKILL.md index 7706a64..0067dc7 100644 --- a/resources/boost/skills/albatros/SKILL.md +++ b/resources/boost/skills/albatros/SKILL.md @@ -8,16 +8,26 @@ compatible_agents: - review --- -**Name:** Albatros API Integration -**Description:** Albatros accounting API integration via Saloon. Use when working with app/Services/Albatros/, AlbatrosConnector, or Albatros DTOs. -**Compatible Agents:** general-purpose, backend -**Tags:** app/Services/Albatros/**/*.php, albatros, accounting, saloon, api-integration +# Albatros API Integration + +## When to Use + +- You are integrating with the Albatros accounting API specifically. +- You are editing `app/Services/Albatros/`, its connector, requests, or DTO mapping. +- You need typed DTO responses, pagination support, and cached reference data. + +## When Not to Use + +- The integration target is not Albatros (use the generic integration/service skills instead). +- The operation is local business logic with no external API call. +- You need one-off scripts without reusable connector/request architecture. ## Rules - `AlbatrosConnector` extends `Saloon\Http\Connector` - Token-based authentication with Mandant header - Base URL from `config('albatros.base_url')` +- Keep credentials and Mandant values in `.env`, mapped through `config/albatros.php`; never hardcode secrets. - `AlbatrosService` wraps all API calls and returns typed DTOs or `Collection` of DTOs - Use `Cache` for reference data (addresses, accounts, VAT codes, etc.) - Paginated endpoints use `fetchAllPages()` helper with `lastIndex` parameter @@ -29,6 +39,11 @@ compatible_agents: - Handle API field name casing variations in `fromArray()` - Cache reference data to minimize API calls - Use `clearCache()` method when data needs refreshing +- Scope cache keys by Mandant to avoid cross-tenant contamination +- Fail fast on non-success responses and use retries only for transient errors (timeouts/429/5xx) +- In `fetchAllPages()`, document and keep retry/backoff explicit (attempts + delay) for predictable operations. +- Treat empty-string `lastIndex` as the stop sentinel unless API docs specify a different terminal token. +- Normalize response shape at service boundary (for example `items` + `lastIndex`) before DTO mapping. - All monetary values as `decimal:2` ## Examples @@ -107,17 +122,67 @@ readonly class AdresseData // Service with caching public function getAdressen(): Collection { - return Cache::remember('albatros.adressen', 3600, fn () => + return Cache::remember($this->cacheKey('adressen'), 3600, fn () => $this->fetchAllPages(fn ($lastIndex) => new ListAdressenRequest(lastIndex: $lastIndex)) ); } public function clearCache(): void { - Cache::forget('albatros.adressen'); + Cache::forget($this->cacheKey('adressen')); } ``` +```php +// Service pagination + error handling pattern +use Illuminate\Support\Collection; +use Saloon\Exceptions\Request\RequestException; + +private function fetchAllPages(callable $requestFactory): Collection +{ + $all = collect(); + $lastIndex = ''; + + do { + $response = retry(3, function () use ($requestFactory, $lastIndex) { + return $this->connector->send($requestFactory($lastIndex)); + }, 200); + + if (! $response->successful()) { + throw new RequestException($response, 'Albatros request failed.'); + } + + $payload = $response->json(); + $items = collect($payload['items'] ?? []); + $all = $all->merge($items->map(fn (array $row) => AdresseData::fromArray($row))); + $lastIndex = (string) ($payload['lastIndex'] ?? ''); + } while ($lastIndex !== ''); + + return $all; +} + +private function cacheKey(string $segment): string +{ + return sprintf('albatros.%s.%s', config('albatros.mandant'), $segment); +} +``` + +```php +// Minimal config/albatros.php pattern +return [ + 'base_url' => env('ALBATROS_BASE_URL'), + 'mandant' => env('ALBATROS_MANDANT'), + 'token' => env('ALBATROS_TOKEN'), +]; +``` + +```php +// Mocked Saloon test note (no real API calls) +Saloon::fake([ + '*' => MockResponse::make(['items' => [], 'lastIndex' => ''], 200), +]); +``` + ## Anti-Patterns - Making uncached API calls for reference data that rarely changes @@ -126,6 +191,7 @@ public function clearCache(): void - Not handling API field name casing variations in `fromArray()` - Storing monetary values as float or string instead of `decimal:2` - Forgetting to call `clearCache()` when reference data is updated +- Reusing non-Mandant-specific cache keys across Mandant contexts ## References diff --git a/resources/boost/skills/blade/SKILL.md b/resources/boost/skills/blade/SKILL.md index aee3da0..a137d5d 100644 --- a/resources/boost/skills/blade/SKILL.md +++ b/resources/boost/skills/blade/SKILL.md @@ -7,23 +7,44 @@ compatible_agents: - review --- -**Name:** Blade Templates -**Description:** Laravel Blade template conventions covering components, output escaping, security, structure, and formatting. -**Compatible Agents:** general-purpose, frontend -**Tags:** resources/views/**/*.blade.php, laravel, php, frontend, blade, template, html +# Blade Templates + +## When to Use + +- Creating or refactoring server-rendered view templates in `resources/views/`. +- Building reusable UI fragments with Blade components. +- Rendering validated/authorized data from controllers, Livewire, and view models. + +## When Not to Use + +- Complex stateful interactions that should live in Livewire components. +- Heavy client-side application flows that require a dedicated SPA framework. +- Raw PHP templating where Blade directives provide clearer intent. + +## Preconditions + +- Laravel Blade is enabled (default Laravel app setup). +- If `x-*` Alpine directives are used, Alpine is loaded by the frontend build/layout. +- If `wire:*` directives are used, Livewire is installed and version-compatible. +- Data passed to views is already validated and authorized upstream. + +## Process Checklist + +- [ ] Decide whether this should be plain Blade, a Blade component, or Livewire. +- [ ] Keep markup declarative and move reusable blocks into components. +- [ ] Render user-provided values with `{{ }}` by default. +- [ ] Use `{!! !!}` only for trusted, pre-sanitized HTML. +- [ ] Keep scripts/styles out of Blade files unless explicitly required by framework conventions. +- [ ] Ensure text and labeling follow project language/content standards. ## Rules -- Use Blade components (``) for reusable UI pieces -- Prefer anonymous components for simple, presentation-only elements -- Use class-based components when logic is needed -- Use `{{ }}` for escaped output (default) — never output raw user input unescaped -- Use `{!! !!}` only when the content is explicitly safe (e.g., pre-sanitized HTML) -- No inline `