Composer: Laravel 13.35, Livewire 4.4.7, Octane 2.21, Fortify 1.41, Boost 2.10.3 and Pest 5.3.1, with the packages they bring (51 in all, brick/math to 1.0). league/commonmark 2.10.3 closes a high and a medium advisory. npm: Vite 8.3.4 and Playwright 1.64; npm audit fix updates source-map-js past a high advisory. Both audits are now clean. Boost's update rewrote its guidelines in CLAUDE.md and four skills. The Gitea workflows move to the current majors of checkout, setup-node and the Docker actions, which run on Node 24 instead of the end-of-life Node 20. QEMU stays pinned to 9.2.2: 10.2 still segfaults on the arm64 runner. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
21 KiB
Laravel Boost Guidelines
Foundational Context
This application is a Laravel application running on PHP 8.5. Always use the APIs that match the installed major version of each package — do not assume a version.
Before relying on a package's API, confirm its installed version:
- PHP packages: run
composer show --directto list direct dependencies with versions, orcomposer show <vendor/package>for a single package. - JS packages: check
package.jsonfor the installed versions.
Skills Activation
This project has domain-specific skills available in **/skills/**. You MUST activate the relevant skill whenever you work in that domain—don't wait until you're stuck.
Conventions
- You must follow all existing code conventions used in this application. When creating or editing a file, check sibling files for the correct structure, approach, and naming.
- Use descriptive names for variables and methods. For example,
isRegisteredForDiscounts, notdiscount(). - Check for existing components to reuse before writing a new one.
Verification Scripts
- Do not create verification scripts or tinker when tests cover that functionality and prove they work. Unit and feature tests are more important.
Application Structure & Architecture
- Stick to existing directory structure; don't create new base folders without approval.
- Do not change the application's dependencies without approval.
Frontend Bundling
- If a frontend change doesn't show in the UI or you get a "Unable to locate file in Vite manifest" error, run
npm run buildor ask the user to runnpm run devorcomposer run dev.
Documentation Files
- You must only create documentation files if explicitly requested by the user.
=== boost rules ===
Laravel Boost
Tools
- Laravel Boost is an MCP server with tools designed specifically for this application. Prefer Boost tools over manual alternatives like shell commands or file reads.
- Use
database-queryto run read-only queries against the database instead of writing raw SQL in tinker. - Use
database-schemato inspect table structure before writing migrations or models. - Use
get-absolute-urlto resolve the correct scheme, domain, and port for project URLs. Always use this before sharing a URL with the user. - Use
browser-logsto read browser logs, errors, and exceptions. Only recent logs are useful, ignore old entries.
Searching Documentation (IMPORTANT)
- Use
search-docsbefore changes that depend on Laravel ecosystem APIs, behavior, configuration, or version-specific syntax. Skip it for copy-only edits and other changes where package documentation is irrelevant. Reuse sufficient results already in context instead of searching again. - Pass a
packagesarray to scope results when you know which packages are relevant. - Use multiple broad, topic-based queries:
['rate limiting', 'routing rate limiting', 'routing']. Expect the most relevant results first. - Do not add package names to queries because package info is already shared. Use
test resource table, notfilament 4 test resource table.
Search Syntax
- Use words for auto-stemmed AND logic:
rate limitmatches both "rate" AND "limit". - Use
"quoted phrases"for exact position matching:"infinite scroll"requires adjacent words in order. - Combine words and phrases for mixed queries:
middleware "rate limit". - Use multiple queries for OR logic:
queries=["authentication", "middleware"].
Project Rules
- This project contains committed, area-grouped rules in
.ai/ruleswhen that directory exists, including path-scoped framework guidelines under.ai/rules/boost. Before you enter plan mode or create/edit any file, you MUST first: open @.ai/rules/index.md (it maps file globs to rule files), read every rule file whose globs cover the path(s) in scope, and rungrep -rin 'keyword' .ai/rulesto catch what a path match alone misses. Do not write code until you have read and are following every matching rule. If.ai/rulesdoes not exist, continue without it.
Artisan
- Run Artisan commands directly via the command line (e.g.,
php artisan route:list). Usephp artisan listto discover available commands andphp artisan [command] --helpto check parameters. - Inspect routes with
php artisan route:list. Filter with:--method=GET,--name=users,--path=api,--except-vendor,--only-vendor. - Read configuration values using dot notation:
php artisan config:show app.name,php artisan config:show database.default. Or read config files directly from theconfig/directory.
Tinker
- Execute PHP in app context for debugging and testing code. Do not create models without user approval, prefer tests with factories instead. Prefer existing Artisan commands over custom tinker code.
- Always use single quotes to prevent shell expansion:
php artisan tinker --execute 'Your::code();'- Double quotes for PHP strings inside:
php artisan tinker --execute 'User::where("active", true)->count();'
- Double quotes for PHP strings inside:
=== php rules ===
PHP
- Always use curly braces for control structures, even for single-line bodies.
- Use PHP 8 constructor property promotion:
public function __construct(public GitHub $github) { }. Do not leave empty zero-parameter__construct()methods unless the constructor is private. - Use explicit return type declarations and type hints for all method parameters:
function isAccessible(User $user, ?string $path = null): bool - Use TitleCase for Enum keys:
FavoritePerson,BestLake,Monthly. - Prefer PHPDoc blocks over inline comments. Only add inline comments for exceptionally complex logic.
- Use array shape type definitions in PHPDoc blocks.
=== deployments rules ===
Deployment
- Laravel can be deployed using Laravel Cloud, which is the fastest way to deploy and scale production Laravel applications.
=== tests rules ===
Test Enforcement
- Add or update tests for behavior and logic changes when a test provides meaningful regression coverage.
- Pure copy, styling, and layout-only changes do not require new or updated tests.
- When test coverage applies, run the affected tests and ensure they pass.
- Test the changed behavior and its important failure modes, but do not add tests beyond them.
- Read the
testing-best-practicesskill before writing tests.
=== laravel/core rules ===
Do Things the Laravel Way
- Use
php artisan make:commands to create new files (i.e. migrations, controllers, models, etc.). You can list available Artisan commands usingphp artisan listand check their parameters withphp artisan [command] --help. - If you're creating a generic PHP class, use
php artisan make:class. - Pass
--no-interactionto all Artisan commands to ensure they work without user input. You should also pass the correct--optionsto ensure correct behavior.
Model Creation
- When creating new models, create useful factories and seeders for them too. Ask the user if they need any other things, using
php artisan make:model --helpto check the available options.
APIs & Eloquent Resources
- For APIs, default to using Eloquent API Resources and API versioning unless existing API routes do not, then you should follow existing application convention.
URL Generation
- When generating links to other pages, prefer named routes and the
route()function.
Testing
- When creating models for tests, use the factories for the models. Check if the factory has custom states that can be used before manually setting up the model.
- Faker: Use methods such as
$this->faker->word()orfake()->randomDigit(). Follow existing conventions whether to use$this->fakerorfake(). - When creating tests, make use of
php artisan make:test [options] {name}to create a feature test, and pass--unitto create a unit test. Most tests should be feature tests.
=== laravel-octane/core rules ===
Laravel Octane
This application uses Laravel Octane, a long-running PHP server. The application bootstraps once and handles many requests within the same process.
- Never store request-specific state in singletons or static properties, because it can leak across requests.
- Use
config('octane.server')to detect the active driver (swoole,roadrunner, orfrankenphp). - Prefer scoped bindings (
$this->app->scoped()) over singletons for per-request services.
When working on Octane-specific features (concurrency, shared tables, memory, driver configuration, testing), invoke octane-development for detailed rules.
=== livewire/core rules ===
Livewire
- Livewire allows you to build dynamic, reactive interfaces in PHP without writing JavaScript.
- You can use Alpine.js for client-side interactions instead of JavaScript frameworks.
- Keep state server-side so the UI reflects it. Validate and authorize in actions as you would in HTTP requests.
=== pint/core rules ===
Laravel Pint Code Formatter
- If you have modified any PHP files, you must run
vendor/bin/pint --dirty --format agentbefore finalizing changes to ensure your code matches the project's expected style. - Do not run
vendor/bin/pint --test --format agent, simply runvendor/bin/pint --format agentto fix any formatting issues.
=== pest/core rules ===
Pest
- This project uses Pest. Create tests with
php artisan make:test --pest {name}. - Do not include the test suite directory in
{name}. UseSomeFeatureTest, notFeature/SomeFeatureTest. - Read the
testing-best-practicesskill for guidance on coverage, naming, structure, dependency isolation, and review. - Do not delete tests or test files without approval. They are part of the application.
Running Tests
- Run the narrowest set of tests that covers the change. Pass a file path or
--filter=testNametophp artisan test --compact. - Rerun a test after each change to it.
- Run
vendor/bin/pestto call the test runner directly. It accepts the same file path and--filter=testNamearguments. - After the feature tests pass, ask the user to run the complete suite with
php artisan test --compact.
=== nonameweb/livewire-material/core rules ===
Livewire Material
This application uses nonameweb/livewire-material: Material 3 Expressive components for Laravel and Livewire, in plain CSS. No utility classes — Tailwind, daisyUI or any other — belong here: a class your CSS does not declare does nothing, and DesignGuard fails it.
- Components are anonymous Blade components, unprefixed unless
config/livewire-material.phpsets aprefix. Before writing or changing a view that uses them, activate thelivewire-material-developmentskill for the props, slots and traps of each component. - The CSS entry imports
foundation.cssfirst, then the stylesheet of each component the views render (orall.cssfor all of them). A component whose stylesheet is not imported renders unstyled;DesignGuard::missingStylesheets()names each missing@import. - Every layout includes
<x-theme-script />in<head>before@vite. The colour scheme is generated withphp artisan material:scheme— never editresources/css/material-scheme.cssby hand. With colour profiles (livewire-material.profiles), run it without a seed after changing them; the active profile comes fromScheme::resolveProfileUsing(). - While the application runs locally, every token and component renders in the application's own scheme at
/material(the showcase). - HTTP error pages and the Markdown mail theme come from the package. Change error wording by publishing
--tag=livewire-material-errors; select the mail theme withMAIL_MARKDOWN_THEME=livewire-material::mail.theme.
=== nonameweb/livewire-material/material-3 rules ===
Material 3
Every view in this application is Material 3 Expressive (m3.material.io), through nonameweb/livewire-material. These rules decide what to write; the material-3-design skill carries the tables, the numbers and Google's source pages behind each one — activate it before designing a screen.
The library is plain CSS on M3's tokens. No utility classes — Tailwind, daisyUI or any other — belong here: a class your CSS does not declare does nothing, and DesignGuard fails it. A view is written three ways:
- Components and their props:
<x-button variant="filled">, and the layout components<x-row>,<x-stack>,<x-grid>,<x-feed>,<x-surface>and<x-pane>, whosegapandpaddingtake a spacing token (space200) and whosehide-below,hide-fromandstack-belowtake a window size class. - A fixed set of classes for text and interaction on plain elements:
md-type-*,md-ink-*,md-text-*,md-truncate,md-tabular,md-visually-hidden,md-state-layer,md-focus-ring,md-touch-targetandmd-link. - The application's own CSS, named by the application, whose values are
--md-sys-*custom properties.
Colour
- A colour is always a role:
md-ink-varianton text,var(--md-sys-color-outline-variant)in the application's CSS,color="error"on a component. Never a hex, a palette tone or an opacity. - Pair a role only with its
on-partner: aprimaryfill takeson-primarytext, asecondary-containerfill takeson-secondary-container. That pair is the one whose contrast is guaranteed at every contrast level; mixing pairs (primary-containerunderon-surface) is not. primaryis the one key action on a screen (a filled button; the FAB inprimary-container).secondary-containeris the quiet fill (tonal buttons, selected navigation, selected chips).tertiaryis a contrasting accent, used rarely.error,success,warning,infomean state and nothing else: the-containerfor a tinted panel, the role itself for its text and icon.- Ink is
on-surface(md-ink); lower emphasis ison-surface-variant(md-ink-variant); decoration isoutline(md-ink-quiet). Never dim ink with an opacity: 38% means disabled. outlineis a boundary that must be read (a text field, the edge of a target).outline-variantis a divider or a card edge (<x-divider>,<x-surface outlined>). Neveroutlineon a divider.- Fixed and dim roles (
primary-fixed,surface-dim, …) are for a colour that must not change with the theme; if unsure, don't. Inverse roles only on an inverse surface (the snackbar). - A link in running text is underlined (
md-link, withmd-ink-primary); colour alone signals nothing. - Contrast: 4.5:1 for text, 3:1 for large text, icons and grouped controls; disabled is exempt. Three contrast levels exist (
<html data-contrast>: standard, medium, high) and every role changes with them — which is why only roles are allowed.
Surfaces and elevation
- The page is
surface. Panels separate by tone first:surface-container-lowest…surface-container-highestis a hierarchy of emphasis, not of height (<x-surface level="surface-container-high">). Navigation chrome issurface-container; a dialog, a menu, the search bar aresurface-container-high; a modal sheet issurface-container-low; a filled card issurface-container-highest. A region keeps its role at every width. - Shadows (
var(--md-sys-elevation-1)…-5) are for what floats or lifts: 1 for elevated cards, buttons and modal sheets; 2 for menus, the navigation bar, a scrolled app bar; 3 for the FAB, dialogs, pickers and search; one level more on hover; nothing rests above 3. Fewer shadows carry more meaning. - A scrim is
scrimat 32%:color-mix(in srgb, var(--md-sys-color-scrim) 32%, transparent).
Shape
- Corners come from the scale
var(--md-sys-shape-corner-{none|xs|sm|md|lg|lg-increased|xl|xl-increased|xxl|full}), or<x-surface corner="md">; never a length of your own. - By family:
fullbuttons, icon buttons, chips' avatars, badges, switches, sliders, the search bar, navigation indicators;xstext fields, menus, snackbars, plain tooltips;smchips;mdcards, rich tooltips;lgthe FAB and a side sheet's inner corners;xldialogs, bottom sheets, the search view, pickers, carousel items;xxllarge hero containers. - Nested shapes: inner radius = outer radius − padding; never the same radius inside and out.
- A press squares a round shape (the components do it; nothing morphs on hover). The 35
<x-shape>s are decoration, never meaning, used sparingly.
Type
- Every text element carries one
md-type-*class:displayfor hero figures and short marketing lines;headlinefor page and section titles;titlefor card, dialog and list-section titles;bodyfor paragraphs (md-type-body-lgfor reading);labelinside components (buttons, chips, tabs, captions). In the application's CSS a style isfont: var(--md-sys-typescale-body-md)with its-tracking; never a size, weight, line height or letter spacing of your own. md-type-emphasized-*is opt-in: a selected item, a primary action, a headline, a badge — not decoration.- 40–60 characters per line;
md-tabularon figures that change; text must scale to 200% without loss (containers grow, rows wrap, no fixed heights on text, no ellipsis without a way to read the rest).
Motion
- Position, size and shape move on the spatial springs (they overshoot):
transition: transform var(--md-sys-motion-spatial-default-duration) var(--md-sys-motion-spatial-default)—fastfor small elements,slowfor large ones. Colour and opacity move on the effects springs (--md-sys-motion-effects-*), which never overshoot. Always pair an easing with its duration. - Entering decelerates, a permanent exit accelerates, a temporary exit (a sheet, a drawer) takes the emphasized curve; exits are shorter than entrances.
- Everything that moves goes through these tokens, so reduced motion makes it instant; a literal duration is a bug.
States and targets
- Interactive elements carry
md-state-layer md-focus-ring: hover 8%, focus 10%, pressed 10%, dragged 16% (data-md-dragged) of the content colour. Disabled is content at 38% and a container at 12% ofon-surface(--md-sys-state-disabled-content-opacity,--md-sys-state-disabled-container-opacity, throughcolor-mix()), with no state layer. Every state shows two indicators: colour plus a shape, an outline, an icon or a word. - Every target is at least 48×48px with 8px between targets (
md-touch-targeton anything drawn smaller); a denser layout is an opt-in prop, never a default. - Keyboard: Tab between components, arrows within one, Enter and Space activate, Escape dismisses; a dialog takes focus and gives it back to what opened it.
Layout and breakpoints
- Widths are M3's window size classes and only those: compact below 600px (the default), medium 600, expanded 840, large 1200, extra-large 1600. A layout component takes them as props (
<x-row stack-below="medium">,<x-stack hide-from="expanded">,<x-grid :columns="['compact' => 1, 'expanded' => 2]">); the application's CSS writes@media (width >= 840px); a script asksfrom()andupTo()fromresources/js/breakpoints.js. - What changes per class: compact — navigation bar, one pane, full-screen dialogs, a bottom sheet for choices; medium — collapsed rail, one pane; expanded — rail (collapsible), two panes, menus and basic dialogs; large and extra-large — the rail expanded, two panes, a third only at extra-large as a side sheet.
<x-scaffold>does this; content lives in panes (<x-pane>,<x-list-detail>for a list's second pane), never beside the rail by hand. - Margins are 16px below medium and 24px from it (
<x-pane>draws them); spacing sits on the 4px grid asspace25…space900, as padding and gaps on the parent, with margins only between layout regions. A fixed pane is 360px (expanded) or 412px (large); a side sheet at most 400px. - Write logical properties (
padding-inline-start,inset-inline-end,md-text-start); directional icons mirror in RTL; charts and media controls stay LTR. Keep controls inside the safe area (--material-safe-*).
Accessibility
- Native elements first (
<button>,<dialog>,<input>), then ARIA. Onemain, onebanner, onecontentinfo; every repeatednavlabelled, without the word "navigation". - Headings in order from a single H1; the level is structure, the
md-type-*class is appearance. - An icon-only control has an accessible name that does not include its role; decorative icons are hidden; an error is announced and tied to its field (
aria-describedby); a toast uses a polite live region and never takes focus. A single-key shortcut needs a modifier or a focused component.
Icons
<x-icon name="home">is a Material Symbol Rounded:filledmeans active or selected,optical="20"when drawn at 20px or less, one weight per group, the size and colour of the text beside it.
Don'ts
- No icon in a snackbar; no disabled FAB (hide it); no horizontal radio rows; no hover morph on cards; no
outlineon dividers; no hex colours; no utility classes, and no breakpoint, radius, shadow, type size or duration off M3's scales; no segmented buttons, navigation drawer or bottom app bar — use<x-button-group connected>, the expanded rail and<x-toolbar>.