Skip to main content

PLA Project Kickoff

Reference guide - not a scaffolder. Read and follow step by step.

Audience: AI agents (Claude Code) Gold-standard project: mentat (mentat/ in the workspace root)

Prerequisite: The mentat project must be cloned in the workspace root. If not present, clone it: git clone git@gitlab.com:publicala/mentat.git

Reference files

All baseline configs live in references/. Copy and adapt as needed.

FilePurpose
references/composer-scripts.jsonComposer scripts block (setup, dev, lint, test)
references/package.jsonnpm scripts + devDependencies baseline
references/app.cssTailwind v4 entry with Flux imports
references/vite.config.jsVite + Tailwind + Laravel plugin
references/lefthook.ymlPre-commit (pint, rector, prettier) + pre-push (phpstan)
references/session-start.shClaude Code SessionStart hook for lefthook
references/claude-settings.jsonClaude Code hooks config
references/Pest.phpPest global config (fakes, freeze, refresh)
references/claude-md-template.mdRoot CLAUDE.md template
references/wide-events.mdObservability wide events guide

1. Stack

ComponentVersion / ToolNotes
FrameworkLaravel 12laravel/framework ^12.x
PHP8.4declare(strict_types=1) everywhere
FrontendLivewire 4 SFCsSingle File Components only
UI KitFlux ProKey: 32e360d4-88f9-436f-964d-87babb03a44c
CSSTailwind v4Via @tailwindcss/vite plugin
DB (local)SQLiteZero-config local dev
DB (cloud)MySQL 8Laravel Cloud managed
TestingPest v4Always it(), never class-based
AIlaravel/aiOfficial Laravel AI SDK
MonitoringNightwatchlaravel/nightwatch
BuildVite 7.xWith @tailwindcss/vite + laravel-vite-plugin

Flux Pro requires a Composer repository and auth.json:

// composer.json repositories
[{ "name": "flux-pro", "type": "composer", "url": "https://composer.fluxui.dev" }]

Reference: mentat's composer.json, package.json, vite.config.js

2. Prerequisites

The fastest way to get PHP, Composer, Node, npm, and the Laravel installer:

# Installs PHP 8.4, Composer, Node, npm, and the Laravel installer in one step
/bin/bash -c "$(curl -fsSL https://php.new/install/mac/8.4)"

Additional tools:

  • Lefthook - brew install lefthook
  • Laravel Cloud CLI - composer global require laravel/cloud-cli

3. Project Bootstrap

Step-by-step guide. Agent reads and follows manually - not automated.

3.1 Create Laravel project

composer create-project laravel/laravel {project-name}
cd {project-name}

3.2 composer.json

Add Flux Pro repo, core packages, and scripts.

Required packages:

laravel/ai, laravel/framework, laravel/horizon, laravel/nightwatch,
livewire/flux-pro, livewire/livewire, nunomaduro/essentials

Dev packages:

driftingly/rector-laravel, larastan/larastan, laravel/pail, laravel/pint,
pestphp/pest, pestphp/pest-plugin-browser, pestphp/pest-plugin-laravel,
pestphp/pest-plugin-type-coverage, rector/rector

Composer scripts: Copy from references/composer-scripts.json into composer.json scripts block and adapt the dev concurrently command for your project's services.

Best practice: composer setup bootstraps everything, composer dev runs all services via concurrently.

3.3 package.json

Copy baseline from references/package.json and adapt versions as needed.

3.4 Config files

Copy these from mentat and adapt:

FileSource pathPurpose
pint.jsonmentat/pint.jsonPHP formatting (strict rules, etc.)
rector.phpmentat/rector.phpPHP transforms (dead code, early return, strict booleans)
phpstan.neonmentat/phpstan.neonStatic analysis level 8
lefthook.ymlreferences/lefthook.ymlGit hooks (pre-commit + pre-push)
.editorconfigmentat/.editorconfigEditor settings (utf-8, lf, 4 spaces)
config/livewire.phpmentat/config/livewire.phpSFC mode, page locations
config/essentials.phpmentat/config/essentials.phpEloquent unguard

3.5 Tailwind v4 CSS

Copy references/app.css to resources/css/app.css.

3.6 Vite config

Copy references/vite.config.js to project root.

3.7 .env.example

Set SQLite defaults for local development:

DB_CONNECTION=sqlite

3.8 CLAUDE.md

Create root + directory-level CLAUDE.md files. Use template at references/claude-md-template.md.

3.9 Claude Code Hooks

Set up a SessionStart hook to ensure lefthook git hooks are active in every Claude Code session.

  1. Copy references/session-start.sh to .claude/hooks/session-start.sh
  2. Make it executable: chmod +x .claude/hooks/session-start.sh
  3. Copy references/claude-settings.json to .claude/settings.json

This is fast, idempotent, and warns gracefully if lefthook is missing. It guarantees that pre-commit (pint + rector + prettier) and pre-push (phpstan) hooks are active before any commits happen.

3.10 Laravel Cloud Setup

cloud auth          # authenticate (one-time)
cloud repo:config # save project/org defaults (per project)

4. Code Conventions

High-level principles. See mentat's pint.json and rector.php for enforcement.

  • declare(strict_types=1) in every PHP file
  • Enums: string-backed, names describe values
  • Models: casts() method, ULIDs via HasUlids
  • Services: injected via constructor
  • Jobs: implement ShouldQueue
  • Value objects: readonly classes
  • Frontend: Livewire 4 SFCs only (no class-based components), placed in resources/views/pages/
  • Flux Pro for all UI components - never hand-roll what Flux provides
  • Strict comparisons (===) everywhere
  • DateTimeImmutable over DateTime
  • No superfluous elseif/else - use early returns
  • Ordered class elements: traits, cases, constants, properties, construct, public methods, protected, private

Reference: mentat's pint.json, rector.php, tests/Arch/

Laravel-First Conventions

Always prefer Laravel utilities over native PHP equivalents. This is a hard rule for consistency across all PLA projects.

Filesystem - Use the File facade, never native functions:

Instead ofUse
is_file($path), file_exists($path)File::exists($path)
is_dir($path)File::isDirectory($path)
file_get_contents($path)File::get($path)
file_put_contents($path, $data)File::put($path, $data)
mkdir($path, 0755, true)File::ensureDirectoryExists($path)
rmdir($path) / unlink($path)File::deleteDirectory($path) / File::delete($path)

Collections - Use collect() pipelines, never nested array functions:

// Bad
$result = array_values(array_filter(array_map($fn, $items)));

// Good
$result = collect($items)->map($fn)->filter()->values()->all();

Prefer semantic methods: ->reject() over ->filter() with negation, ->contains() over in_array(), ->pluck() over array_column(), ->keys() over array_keys().

Strings - Use Str:: helpers and Str::of() fluent API:

Instead ofUse
str_starts_with($s, $p)Str::startsWith($s, $p)
str_contains($s, $p)Str::contains($s, $p)
str_ends_with($s, $p)Str::endsWith($s, $p)
mb_substr($s, 0, $pos) / mb_strpos parsingStr::before($s, ':') / Str::after($s, ':')
explode + array_map + array_filterStr::of($s)->explode("\n")->map(...)->filter()

Arr helpers - Use Arr:: for associative array operations:

Instead ofUse
isset($arr['a']['b']) ? $arr['a']['b'] : nullArr::get($arr, 'a.b')
array_key_exists($k, $arr)Arr::has($arr, $k)

PHPStan note: Collection::values()->all() returns array<int, T>, not list<T>. Add /** @var list<T> */ above the return when the method's return type is list<T>.

5. Standard Directory Structure

app/
Actions/ # Single-purpose action classes
Ai/ # AI agents, tools, middleware
Agents/
Middleware/
Tools/
Console/ # Artisan commands
Enums/ # String-backed enums
Exceptions/ # Custom exceptions
Http/ # Controllers, middleware, requests
Jobs/ # Queued jobs (ShouldQueue)
Models/ # Eloquent models (HasUlids)
Providers/ # Service providers
Services/ # Business logic services
ValueObjects/ # Readonly value objects
config/
ai.php # AI provider configuration
livewire.php # Livewire SFC settings
essentials.php # Eloquent unguard, etc.
database/
factories/
migrations/
seeders/
docs/
architecture/ # System design docs
patterns/ # Implementation patterns
plans/ # Development plans
resources/
css/ # Tailwind v4 entry
js/ # JS entry points
views/
components/ # Reusable Blade/Livewire components
layouts/ # Layout templates
pages/ # Livewire SFC page components
tests/
Arch/ # Architecture tests (Pest arch())
Browser/ # Playwright browser tests
Feature/ # Integration tests
Unit/ # Pure logic tests
fixtures/ # Test data
Pest.php # Global test config
stubs/
agent.stub # AI agent template
tool.stub # AI tool template
structured-agent.stub # Structured output agent template
middleware.stub # AI middleware template

6. Testing

Framework

Pest v4. Always it() syntax, never class-based PHPUnit tests.

Organization

TypeLocationWhen to Use
Archtests/Arch/Code quality, conventions, layer deps
Unittests/Unit/Pure logic, no DB or framework
Featuretests/Feature/Livewire, HTTP, jobs, services
Browsertests/Browser/Full-stack rendering via Playwright

Non-negotiable quality gates

  • 100% type coverage (pest --type-coverage --min=100)
  • PHPStan level 8
  • Pint clean (no formatting violations)
  • Rector clean (no transform violations)

Pest.php global config

Copy references/Pest.php to tests/Pest.php and add necessary imports. Key behaviors: RefreshDatabase, preventStrayRequests, preventStrayProcesses, Sleep::fake, freezeTime.

Standard arch tests

Create these in tests/Arch/. Reference: mentat's tests/Arch/ (13 test files).

Test fileWhat it enforces
CodeQualityTest.phpdeclare(strict_types=1)
TestStyleTest.phpit() syntax only, no class-based tests
EnumsTest.phpString-backed, naming conventions
ServicesTest.phpFinal, no Eloquent dependencies
JobsTest.phpFinal, ShouldQueue
ModelsTest.phpFinal, HasUlids, casts()
LivewireSfcTest.phpSFCs only, in correct directories
ObservabilityTest.phpNo Log::debug(), namespaced context keys
LayerDependenciesTest.phpChannels don't depend on Jobs, Enums don't depend on Models, etc.
AgentToolsTest.phpTools implement correct interface
AiMiddlewareTest.phpMiddleware structure
ChannelsTest.phpChannel conventions
NumberFormattingTest.phpConsistent number formatting

Reference: mentat's tests/CLAUDE.md, tests/Pest.php, tests/Arch/

7. Linting & Code Quality

ToolConfig filePurpose
Pintpint.jsonPHP formatting (Laravel preset + strict rules)
Rectorrector.phpPHP transforms (dead code, early return, strict booleans)
Prettierpackage.json scriptsJS/CSS formatting + Tailwind class sorting
PHPStanphpstan.neonStatic analysis level 8 with Larastan
Lefthooklefthook.ymlGit hooks

Lefthook pattern

Copy baseline from references/lefthook.yml. Key: stage_fixed: true auto-stages corrected files.

Composer scripts pattern

composer lint          # Fix: rector + pint + prettier
composer test:lint # Check: pint --test + rector --dry-run + prettier --check
composer test:types # PHPStan
composer test:type-coverage # Pest type coverage (min 100%)
composer test:unit # Pest parallel with coverage
composer test # All of the above

Reference: mentat's config files

8. Git Workflow

  • Branch from main: feature/{description}
  • Lowercase hyphen-separated branch names
  • MR titles reference Linear issue (e.g. DEV-123: Add user export)
  • Use Lefthook hooks - never skip with --no-verify

9. AI Integration (laravel/ai)

All AI code lives in app/Ai/. Four patterns, each with a mentat stub:

PatternInterfaces / TraitsKey MethodsStub
Conversational AgentAgent, Conversational, HasTools + Promptableinstructions(), messages(), tools()stubs/agent.stub
Structured Output Agent+ HasStructuredOutput+ schema(JsonSchema)stubs/structured-agent.stub
ToolTooldescription(), handle(Request), schema(JsonSchema)stubs/tool.stub
Middleware(pipeline class)handle(AgentPrompt, Closure)$next()->then(fn)stubs/middleware.stub

Config

config/ai.php - Multi-provider configuration. Default provider is OpenAI. Supports Anthropic, Azure, Gemini, Groq, Mistral, Ollama, OpenRouter, and more.

Testing AI agents

MyAgent::fake(['response text']);
MyClassifier::fake([['category' => 'product_docs']]);

Reference: mentat's app/Ai/, stubs/, config/ai.php

10. Deployment

Platform

Laravel Cloud (mandatory for all new projects).

CLI workflow

composer global require laravel/cloud-cli
cloud auth
cloud repo:config # Save app/org defaults (run once)
cloud deploy # Deploy
cloud deploy:monitor # Watch deploy progress

Database

MySQL 8 on Laravel Cloud.

CI (referenced, not enforced)

GitLab CI with stages: build-image, build, test, qa, deploy.

Post-deploy verification

  1. Monitor pipeline completion (use /gitlab skill)
  2. After deploy succeeds, wait 3-5 min for Laravel Cloud rollout
  3. Use Nightwatch MCP list_issues to check for new issues since deploy
  4. Zero new issues after 5 min = green signal
  5. If issues found: get_issue() for stack trace + context, read source, fix, repeat

11. Observability

Brief summary - see references/wide-events.md for full guide.

  • Wide events pattern: one canonical Log::info() per unit of work
  • Context: Context::add('{project}.key', value) with project-namespaced keys
  • Warnings: must include reason field
  • No breadcrumbs: no Log::debug(), no step-by-step narration
  • Queue failures: centralized in global Queue::failing listener
  • Nightwatch: monitors production, surfaces context in job/exception records

12. CLAUDE.md Practice

Every project needs root + directory-level CLAUDE.md files.

Root CLAUDE.md

Covers: overview, stack, architecture, key commands, env vars, observability, deploy workflow.

Template: references/claude-md-template.md

Directory-level CLAUDE.md

Add when patterns are non-obvious. Focus on what won't change: architectural patterns, conventions, and the why behind complex or confusing decisions. These files should help an agent (or a new contributor) understand the reasoning that isn't self-evident from reading the code.

Include:

  • Structural patterns (how things are built, what to follow when adding new ones)
  • Key decisions with rationale (the "why," not just the "what")
  • Non-obvious constraints or trade-offs

Do NOT include:

  • Lists or tables of current implementations (maintenance burden; the code is the source of truth)
  • Anything derivable by reading the files in the directory
  • Ephemeral details that change with each PR
LocationContent
tests/CLAUDE.mdTest types, running commands, factory patterns, faking conventions
app/Ai/CLAUDE.mdAgent patterns, tool interface, testing fakes
app/Models/CLAUDE.mdModel conventions, relationships, casts
app/Jobs/CLAUDE.mdJob patterns, observability requirements
app/Health/Checks/CLAUDE.mdCheck pattern, how to add new checks, key decisions with rationale
docs/CLAUDE.mdDocumentation structure, where to find what

13. Quick Reference Checklist

Verify each item exists and matches mentat's patterns:

ItemConfig / FileMentat source
PHP 8.4 + strict typescomposer.json, pint.jsonmentat/composer.json
Laravel 12composer.jsonmentat/composer.json
Livewire 4 SFCsconfig/livewire.phpmentat/config/livewire.php
Flux Pro repocomposer.json repositoriesmentat/composer.json
Tailwind v4resources/css/app.cssmentat/resources/css/app.css
Vite 7.x configvite.config.jsmentat/vite.config.js
Pest v4composer.json require-devmentat/composer.json
Pint (Laravel preset + strict)pint.jsonmentat/pint.json
Rector (Laravel + strict)rector.phpmentat/rector.php
PHPStan level 8phpstan.neonmentat/phpstan.neon
Lefthook hookslefthook.ymlmentat/lefthook.yml
EditorConfig.editorconfigmentat/.editorconfig
Prettier + pluginspackage.jsonmentat/package.json
Essentials configconfig/essentials.phpmentat/config/essentials.php
AI configconfig/ai.phpmentat/config/ai.php
Nightwatchcomposer.json requirementat/composer.json
Composer scripts (setup, dev, lint, test)composer.json scriptsmentat/composer.json
npm scripts (build, dev, lint)package.json scriptsmentat/package.json
SQLite local default.env.examplementat/.env.example
Root CLAUDE.mdCLAUDE.mdmentat/CLAUDE.md
Tests CLAUDE.mdtests/CLAUDE.mdmentat/tests/CLAUDE.md
Claude Code SessionStart hook.claude/hooks/session-start.shSection 3.9
Arch teststests/Arch/mentat/tests/Arch/
Pest.php global configtests/Pest.phpmentat/tests/Pest.php
AI stubsstubs/mentat/stubs/