| name | maestro |
| description | Maestro monorepo orchestrator for the official Laravel starter kits. Use this skill when making changes to any starter kit source files, building kits, running tests, or working with the kit inheritance hierarchy, placeholder system, teams feature, or any development workflow in this repo.
|
Maestro Skill
What is Maestro
Maestro is the monorepo orchestrator for the official Laravel starter kits. All starter kit source files live here and get built out to individual repositories. Changes are made in this repo, and Maestro automatically creates PRs for the affected starter kit repos after merge.
Project Structure
maestro/
├── kits/ # Source files for all starter kits (inheritance-based layering)
├── orchestrator/ # Laravel app that builds and watches starter kits
├── build/ # Generated starter kit (git-ignored) — make changes here during dev
├── browser_tests/ # Cross-kit browser tests for CI
└── .github/ # GitHub workflows
Commands
All commands below run from the orchestrator/ directory unless noted otherwise.
| Command | Description |
|---|
php artisan build | Build a starter kit into build/. Interactive or use flags (see below). |
php artisan build --kit=vue | Build Vue Fortify kit directly. |
php artisan build --kit=svelte --blank | Build Blank Svelte kit. |
php artisan build --kit=livewire --workos | Build Livewire WorkOS kit. |
php artisan build --kit=react --teams | Build React Fortify kit with Teams. |
php artisan build --kit=vue --workos --teams | Build Vue WorkOS kit with Teams. |
composer kit:run | Start dev server + file watcher (syncs build/ back to kits/). |
composer kits:pint | Run Pint on kits/ and browser_tests/. |
composer kits:lint | Run kits:pint, then lint/format Inertia variants and sync back. |
composer kits:check | Build and run CI checks (composer setup && composer ci:check) for all 21 kit variants sequentially. |
composer kits:browser-tests | Build and run browser tests for all 8 Fortify kit variants (4 base + 4 teams). |
php artisan fortify:matrix --kit=React | Run all Fortify auth_features permutations for one kit. |
npm run watch:kits | Run only the file watcher (no dev server). |
composer setup && composer ci:check | Run inside build/ — installs deps, builds frontend, runs checks (see below). |
Selective Execution
Pass --livewire, --react, --svelte, and/or --vue to target specific frameworks.
Pass --blank, --fortify, --workos, --components, and/or --teams to target specific variants.
Combine both to narrow down exactly which kit variants to run:
composer kits:check -- --react --svelte
composer kits:check -- --vue --svelte --fortify
composer kits:check -- --livewire --fortify --workos
composer kits:check -- --workos
composer kits:lint -- --vue
composer kits:lint -- --livewire
composer kits:browser-tests -- --vue
No flags runs the full default matrix for each command.
Available --kit values defined in orchestrator/app/Enums/StarterKit.php.
CI Checks (composer ci:check)
Every starter kit has a ci:check composer script that validates the kit without auto-fixing. Run composer setup first to install dependencies and build the frontend (composer setup runs composer install, npm install, and npm run build, which generates the Wayfinder types needed by eslint and the type checker).
Inertia kits run: eslint ., prettier --check ., tsc --noEmit / vue-tsc --noEmit / svelte-check, then @test (pint + PHPUnit).
Livewire kits run: @test (pint + PHPUnit) only.
Fortify Feature Matrix
Run from orchestrator/: php artisan fortify:matrix --kit=React|Svelte|Vue|Livewire.
Add --teams or Livewire-only --components as needed. The command builds build/, snapshots it, applies every auth_features permutation through chisel.php, and runs lint/checks for each result. Inertia matrix checks use Bun only; if Bun is missing, let it fail.
Starter Kit Variants (21 total)
These are the full starter kit identifiers written to orchestrator/storage/app/private/starter_kit and used by orchestrator/scripts/watch.js for layer syncing.
| Stack | Variant Identifier | Auth / Feature Set |
|---|
| Livewire | livewire-blank | Blank (no auth) |
| Livewire | livewire | Fortify |
| Livewire | livewire-components | Fortify + Components |
| Livewire | livewire-workos | WorkOS |
| Livewire | livewire-teams | Fortify + Teams |
| Livewire | livewire-workos-teams | WorkOS + Teams |
| React | react-blank | Blank (no auth) |
| React | react | Fortify |
| React | react-workos | WorkOS |
| React | react-teams | Fortify + Teams |
| React | react-workos-teams | WorkOS + Teams |
| Svelte | svelte-blank | Blank (no auth) |
| Svelte | svelte | Fortify |
| Svelte | svelte-workos | WorkOS |
| Svelte | svelte-teams | Fortify + Teams |
| Svelte | svelte-workos-teams | WorkOS + Teams |
| Vue | vue-blank | Blank (no auth) |
| Vue | vue | Fortify |
| Vue | vue-workos | WorkOS |
| Vue | vue-teams | Fortify + Teams |
| Vue | vue-workos-teams | WorkOS + Teams |
Kit Inheritance Hierarchy
Starter kits are built by layering folders in priority order. Higher-priority layers override files from lower ones.
Inertia (React / Svelte / Vue)
Shared/Blank
→ Inertia/Blank/Base
→ Inertia/Blank/{React|Svelte|Vue}
→ Shared/Base
→ Inertia/Base
→ Inertia/{React|Svelte|Vue}
For Fortify variant, add:
→ Shared/Fortify
→ Inertia/Fortify/Base
→ Inertia/Fortify/{React|Svelte|Vue}
For WorkOS variant, add:
→ Shared/WorkOS
→ Inertia/WorkOS/Base
→ Inertia/WorkOS/{React|Svelte|Vue}
For Teams (on top of Fortify or WorkOS), add:
→ Shared/Teams/Base
→ Shared/Teams/{Fortify|WorkOS}
→ Inertia/Teams/Base
→ Inertia/Teams/{React|Svelte|Vue}
→ Inertia/Teams/{Fortify|WorkOS}/Base
→ Inertia/Teams/{Fortify|WorkOS}/{React|Svelte|Vue}
Livewire
Shared/Blank
→ Livewire/Blank
→ Shared/Base
→ Livewire/Base
→ Shared/Fortify → Livewire/Fortify [→ Livewire/Components]
OR Shared/WorkOS → Livewire/WorkOS
For Teams (on top of Fortify or WorkOS), add:
→ Shared/Teams/Base
→ Shared/Teams/{Fortify|WorkOS}
→ Livewire/Teams/Base
→ Livewire/Teams/{Fortify|WorkOS}
What This Means for Editing
- The watcher (
orchestrator/scripts/watch.js) syncs changes from build/ back to the most specific layer in kits/.
- If a file exists in both
Shared/Blank and Inertia/Fortify/Svelte, editing it in build/ syncs to Inertia/Fortify/Svelte.
- Files in
kits/Shared/ affect all kits. Files in kits/Inertia/Svelte/ only affect Svelte.
- The watcher restores placeholders (e.g.,
{{dashboard}}) before syncing back — you don't need to worry about placeholders when editing in build/.
- Fortify kits use
chisel.php plus @chisel-* markers to remove optional auth features. Keep markers wide enough that removed sections leave valid PHP/TS/Vue/Svelte/Blade.
- In kit Chisel scripts, prefer Chisel helpers (
$c->npm()->run(...), $c->npm()->remove(...)) over hardcoded package-manager shell calls; Chisel follows the generated kit's Node runtime.
Kits Folder Structure
kits/
├── Shared/
│ ├── Blank/ # Foundation: config, migrations, artisan, phpunit.xml, .env.example
│ ├── Base/ # Factories, bootstrap, gitignore
│ ├── Fortify/ # Auth Actions, Concerns, Providers, config/fortify.php
│ ├── WorkOS/ # WorkOS routes, migrations, config
│ └── Teams/
│ ├── Base/ # Core teams: models, trait, actions, events, middleware, policies, rules, notifications, migrations, factories, config
│ ├── Fortify/ # Fortify-specific: CreateNewUser (creates personal team), LoginResponse, RegisterResponse, UserFactory
│ └── WorkOS/ # WorkOS-specific: CreatePersonalTeam listener, auth routes, UserFactory
│
├── Inertia/
│ ├── Blank/
│ │ ├── Base/ # Shared Inertia backend (controllers, middleware, routes)
│ │ ├── React/ # React blank resources
│ │ ├── Svelte/ # Svelte blank resources
│ │ └── Vue/ # Vue blank resources
│ ├── Base/ # Authenticated backend (settings controllers, middleware, tests)
│ ├── React/ # React authenticated frontend
│ ├── Svelte/ # Svelte authenticated frontend
│ ├── Vue/ # Vue authenticated frontend
│ ├── Fortify/
│ │ ├── Base/ # Fortify backend (auth controllers, providers, tests)
│ │ ├── React/ # React auth pages
│ │ ├── Svelte/ # Svelte auth pages
│ │ └── Vue/ # Vue auth pages
│ ├── WorkOS/
│ │ ├── Base/ # WorkOS backend
│ │ ├── React/ # React WorkOS pages
│ │ ├── Svelte/ # Svelte WorkOS pages
│ │ └── Vue/ # Vue WorkOS pages
│ └── Teams/
│ ├── Base/ # Inertia teams backend: controllers, requests, routes, middleware, tests
│ ├── React/ # React teams UI: components (TeamSwitcher, AppHeader, etc.), pages, types
│ ├── Svelte/ # Svelte teams UI: components (TeamSwitcher, AppHeader, etc.), pages, types
│ ├── Vue/ # Vue teams UI: components (TeamSwitcher, AppHeader, etc.), pages, types
│ ├── Fortify/
│ │ ├── Base/ # Fortify teams backend: User model, FortifyServiceProvider, routes, auth tests
│ │ ├── React/ # React Fortify teams: welcome page, settings layout
│ │ ├── Svelte/ # Svelte Fortify teams: welcome page, settings layout
│ │ └── Vue/ # Vue Fortify teams: welcome page, settings layout
│ └── WorkOS/
│ ├── Base/ # WorkOS teams backend: User model, routes
│ ├── React/ # React WorkOS teams: welcome page, settings layout
│ ├── Svelte/ # Svelte WorkOS teams: welcome page, settings layout
│ └── Vue/ # Vue WorkOS teams: welcome page, settings layout
│
└── Livewire/
├── Blank/
├── Base/
├── Fortify/
├── Components/ # Multi-file Blade components variant
├── WorkOS/
└── Teams/
├── Base/ # Livewire teams: Blade views (header, sidebar, team-switcher, team pages), tests
├── Fortify/ # Livewire Fortify teams: User model, FortifyServiceProvider, settings layout, routes, auth tests
└── WorkOS/ # Livewire WorkOS teams: User model, settings layout, routes
Placeholder System
The build process replaces {{placeholder}} tokens in files with framework-specific values. The mapping lives in orchestrator/scripts/ui-components.json. For example:
{{dashboard}} → Dashboard (Svelte/Vue) or dashboard (React)
{{auth_login}} → auth/Login (Svelte/Vue) or auth/login (React)
{{teams_index}} → teams/Index (Vue) or teams/index (React)
{{teams_edit}} → teams/Edit (Vue) or teams/edit (React)
Svelte and Vue use PascalCase page names. React uses kebab-case.
Teams Feature
Teams is an additive layer that can be enabled on top of Fortify or WorkOS auth variants. It is not available with --blank or --components variants.
Build Flag
Use --teams with any kit + auth variant combination:
php artisan build --kit=react --teams
php artisan build --kit=vue --workos --teams
php artisan build --kit=livewire --teams
In interactive mode, you'll be prompted "Would you like to enable the Teams feature?" after selecting an auth variant (unless Blank is selected).
Supported Variants
| Stack | Fortify + Teams | WorkOS + Teams |
|---|
| React | react-teams | react-workos-teams |
| Vue | vue-teams | vue-workos-teams |
| Livewire | livewire-teams | livewire-workos-teams |
| Svelte | svelte-teams | svelte-workos-teams |
These identifiers are written to orchestrator/storage/app/private/starter_kit and used by the watch script to determine which kit layers to sync.
Architecture Overview
Core (Shared/Teams/Base): Models (Team, Membership, TeamInvitation), HasTeams trait (added to User model), TeamRole enum (Owner/Admin/Member with permission-based access), CreateTeam action, 9 domain events, 3 notifications (invitation, acceptance, removal), TeamPolicy, EnsureMembership and SetTeamUrlDefaults middleware, validation rules, migrations, factories, and config/teams.php.
Auth variant overrides:
- Fortify (
Shared/Teams/Fortify): Overrides CreateNewUser to create a personal team on registration. Custom LoginResponse/RegisterResponse/TwoFactorLoginResponse that resolve the current team and set URL defaults before redirecting.
- WorkOS (
Shared/Teams/WorkOS): Uses a CreatePersonalTeam event listener on Laravel's Registered event. Overrides auth routes to include team context after authentication.
Inertia controllers (Inertia/Teams/Base): TeamController (CRUD + switch), TeamMemberController (role update, removal), TeamInvitationController (create, cancel, accept). Routes defined in routes/teams.php with EnsureMembership middleware.
Frontend components (per framework in Inertia/Teams/{React|Svelte|Vue}): TeamSwitcher, CreateTeamModal, AppHeader, AppSidebar, NavUser, UserInfo, Dashboard, teams/index page, teams/edit page, TypeScript types.
Livewire views (Livewire/Teams/Base): Blade components for team-switcher, header, sidebar, desktop-user-menu. Team pages: index, edit, accept-invitation.
Roles and Permissions
| Role | Level | Permissions |
|---|
| Owner | 3 | team:update, team:delete, member:add, member:update, member:remove, invitation:create, invitation:cancel |
| Admin | 2 | team:update, invitation:create, invitation:cancel |
| Member | 1 | (none) |
Only Admin and Member roles are assignable. Owner is automatically set on team creation.
Key Team Files
| File | Purpose |
|---|
kits/Shared/Teams/Base/app/Concerns/HasTeams.php | User trait: team relationships, switching, permissions |
kits/Shared/Teams/Base/app/Models/Team.php | Team model with slug routing, soft deletes |
kits/Shared/Teams/Base/app/Enums/TeamRole.php | Role enum with hierarchical permissions |
kits/Shared/Teams/Base/app/Actions/Teams/CreateTeam.php | Team creation action (transaction, events) |
kits/Shared/Teams/Base/config/teams.php | Team config: user model, invitation settings |
kits/Inertia/Teams/Base/app/Http/Controllers/Teams/ | Team, member, and invitation controllers |
kits/Inertia/Teams/Base/routes/teams.php | Team routes with EnsureMembership middleware |
Workflow
- Build:
cd orchestrator && php artisan build --kit=svelte
- Develop:
composer kit:run (starts dev server at localhost:8000 + watcher)
- Edit: If
build/ exists and the watcher is running, make changes in build/ — the watcher syncs them to kits/. Otherwise, edit kits/ directly.
- Test: Inside
build/, run composer setup && composer ci:check
- Commit: Commit the changes in
kits/ (not build/)
- PR: Create PR; after merge, Maestro auto-creates PRs for affected kit repos
Browser Tests (Local CI Parity)
To run browser tests for all kits locally, run from the orchestrator/ directory:
composer kits:browser-tests
This builds each variant (4 Fortify + 4 Fortify Teams), copies the appropriate browser tests, installs dependencies, and runs the tests — matching the steps in .github/workflows/browser-tests.yml.
Browser tests are split into three layers under browser_tests/:
browser_tests/bootstrap/ — shared Pest config, TestCase, and phpunit.xml. Copied for all 8 jobs.
browser_tests/common/ — Fortify browser tests. Copied only for non-teams builds.
browser_tests/teams/ — Teams browser tests. Copied only for Teams builds.
Each variant runs exactly one test suite (common or teams), not both.
Per-Kit Command Sequence
Run from the repo root unless noted:
cd orchestrator
composer install --no-interaction --prefer-dist
php artisan build --kit=<Kit>
cd ..
cp -r browser_tests/bootstrap/* build/
cp -r browser_tests/common/* build/
cd build
composer remove --dev phpunit/phpunit --no-interaction --no-update
composer require --dev pestphp/pest pestphp/pest-plugin-browser pestphp/pest-plugin-laravel --no-interaction
npm install
npm install playwright
npx playwright install --with-deps
cp .env.example .env
php artisan key:generate
npm run build
php vendor/bin/pest --parallel
cd ..
Key Files Reference
| File | Purpose |
|---|
orchestrator/app/Console/Commands/BuildCommand.php | Build orchestration logic |
orchestrator/app/Enums/StarterKit.php | Available kit enum |
orchestrator/scripts/watch.js | File watcher: syncs build → kits with placeholder restoration |
orchestrator/scripts/run.js | Dev server launcher |
orchestrator/scripts/ui-components.json | Placeholder → framework-specific name mapping |
orchestrator/storage/app/private/starter_kit | Stores which kit is currently built |
orchestrator/CLAUDE.md | Laravel Boost guidelines (PHP, Laravel 12, Pest 4, Tailwind v4) |
Important Rules
- Where to edit: If a
build/ folder exists at the project root and composer kit:run is running (dev server + file watcher), make changes in build/ — the watcher syncs them back to kits/. If there is no build/ folder or the watcher is not running, edit kits/ directly. Always commit in kits/ regardless.
- Follow sibling patterns: When creating a Svelte file, check the React and Vue equivalents for expected structure and behavior and vice-versa.
- Layer awareness: Know which layer a file belongs to. Shared files affect all kits. Framework-specific files only affect that framework. Teams layers sit on top of auth layers — place team-specific code in the appropriate
Teams/ directory.
- Placeholder awareness: Files in
kits/ contain {{placeholders}}. Files in build/ have resolved values. The watcher handles conversion.
- Lint changes: Run
composer lint in orchestrator for orchestrator PHP linting. Run composer kits:pint for fast PHP formatting of kits/ and browser_tests/. Run composer kits:lint to run Pint then lint/format all Inertia variants and sync changes back to kits/.
- Test after changes: Run
composer setup && composer ci:check inside build/ to verify nothing is broken.
- Teams layer placement: When modifying teams code, choose the correct layer:
Shared/Teams/Base for cross-stack logic (models, traits, middleware), Shared/Teams/{Fortify|WorkOS} for auth-variant-specific overrides, Inertia/Teams/Base or Livewire/Teams/Base for stack-specific backend, and Inertia/Teams/{React|Svelte|Vue} or Livewire/Teams/{Fortify|WorkOS} for frontend/variant-specific UI.