Skip to content

Development Workflow

Terminal window
composer dev

composer dev starts four processes with concurrently, each labelled in the output:

NameCommandPurpose
serverphp artisan servePHP’s built-in server, at the address it prints
queuephp artisan queue:listen --tries=1Runs queued jobs from Redis, reloading the code for each job
logsphp artisan pail --timeout=0Streams the application log
vitepnpm run devThe Vite dev server, which rebuilds CSS and TypeScript and reloads the page

The queue worker is required. Jobs go to Redis (QUEUE_CONNECTION=redis), so mail such as email sign-in codes is not sent until a worker runs it.

composer dev doesn’t run the scheduler. Run php artisan schedule:work in another terminal when you need scheduled tasks, or run one by hand, such as php artisan announcements:notify.

composer openapi:generate:v1 writes the OpenAPI schema from the #[OA\...] attributes in app/ to docs/schemas/api-schema.yaml, which the docs site renders as its API Specification. CI regenerates it on every pull request; run it yourself to check your attributes. composer openapi:generate prints the schema without writing it.

The docs site is an Astro Starlight project in docs/, with its own dependencies. Run pnpm install and then pnpm dev in docs/ to preview it with live reload, or pnpm build to check that it builds and that every internal link resolves, as CI does.

With Laravel Herd, Herd serves the site at https://your-project-name.test, named by herd.yml, and Herd Pro runs the PostgreSQL, Redis and RustFS services that herd.yml lists. Use that address rather than the one php artisan serve prints; composer dev still provides the queue worker, the log stream and Vite. Installation covers the first-time setup.

A local environment needs no credentials: copy .env.example, run php artisan key:generate and php artisan db:rebuild, and sign in as a seeded demo user. That makes worktrees and agents cheap to set up. An agent working in the browser signs in by opening /app/login/as/{username} (for example /app/login/as/nuit.admin) at whatever host and port the app is served on. See Signing In Locally.

Every change must pass these checks. CI runs all of them except the type check.

CheckCommandNotes
PHP testsvendor/bin/pest --parallelThe Unit and Feature suites. See Testing
Browser testscomposer test:browserEvery page in a real browser, with axe, through Pest and Playwright. Run pnpm build first. See Browser Tests
Static analysiscomposer analyse:phpPHPStan at level 6 (phpstan.neon). It must report no errors.
PHP formattingcomposer format:phpLaravel Pint with the rules in pint.json
Frontend formattingpnpm format or composer format:frontendPrettier on .blade.php, .ts, .js, .css, .md, .json, .yml, .xml and .astro files. It skips .mdx, the mail views and .github/workflows.
Refactoring rulescomposer rectorRector with the rules in rector.php. composer rector:dry shows the changes without making them.
TypeScriptpnpm typechecktsc --noEmit on resources/js/**/*.ts, in strict mode. Not run in CI.
Asset buildpnpm buildVite production build

composer all runs the IDE helper generators, Rector, Pint, Prettier and PHPStan in that order. It does not run tests or build assets.

  1. Run vendor/bin/pest --parallel and composer analyse:php.
  2. Run composer format:php and pnpm format.
  3. If you changed Blade, CSS or TypeScript, run pnpm typecheck and pnpm build.
  4. If you added or changed a page, make sure the browser tests check it, then run composer test:browser. See Adding a Page.

The pull request template (.github/pull-request-template.md) has a checklist for tests, migrations and documentation.

.github/workflows/check-pr.yml runs on pull requests into, and pushes to, main. A newer push to the same branch cancels a run in progress.

JobRuns whenWhat it does
🎯 Determine ScopeAlwaysSorts the changed files into code, docs/, .github/ and iac/, and the jobs below run only for the scopes they check.
🔍 Lint, Format & AnalyseCode changedRuns Rector, Pint and Prettier, regenerates the OpenAPI schema (composer openapi:generate:v1), fails if a browser test calls ->debug() or ->tinker(), then runs PHPStan and publishes its report as a check.
🧪 Unit Tests (1/3, 2/3, 3/3)Code changedRuns vendor/bin/pest --parallel --ci --shard N/3 with PCOV coverage. --ci runs every test even when one is marked ->only(). See Test shards.
📊 Unit Test ResultsCode changedCombines the shards’ JUnit reports into the 📊 PHPUnit Test Results check, and fails if any shard failed. Require this job, not the generated check, in your branch ruleset.
📈 Coverage ReportCode changedMerges the shards’ coverage with phpcov, posts it as a pull request comment, and uploads it to Coveralls in the starter’s own repository.
🌐 Browser TestsCode changedStarts PostgreSQL and RustFS, creates the bucket and its CORS rule, installs Playwright’s Chromium, builds assets and runs vendor/bin/pest --testsuite=Browser --parallel --ci. It publishes the 🌐 Browser Test Results check, uploads the screenshots of failed tests, and prints storage/logs/laravel.log.
📚 Validate Documentationdocs/ changedInstalls the docs site’s dependencies and runs pnpm build in docs/.
🔬 Lint Workflows.github/ changedChecks the workflows with actionlint and audits them with zizmor. Suppressions live in .github/zizmor.yml with their reasons.

A commented-out validate-infrastructure job plans OpenTofu changes under iac/. Uncomment it and set its secrets if your application keeps infrastructure there.

WorkflowTriggerWhat it does
deploy-docs.ymlPush to main that changes docs/, or manualBuilds the docs site and publishes it to GitHub Pages at the domain in DOCS_CNAME
release.ymlManual, with a versionChecks the version and its changelog entry, then creates a GitHub release from main
smoke-test.ymlA published release, or manualCreates a project from the release with composer create-project, then migrates, seeds, builds assets, runs the tests and boots the app

release.yml and smoke-test.yml release and test the starter itself. Delete them during Project Cleanup unless you adapt them for your application.

The starter ships two files that tell coding agents how to work in the repository. An application keeps both and updates them as it grows: new domains, commands, conventions and rules that are easy to miss.

FileRead byHolds
AGENTS.mdCodex and other agents that follow the AGENTS.md conventionThe stack, the commands to run, where each kind of code goes, rules that are easy to miss, and testing conventions. It points to copilot-instructions.md for the detailed standards.
.github/copilot-instructions.mdGitHub CopilotDetailed coding standards: PHP style, domain structure, models, migrations, factories, seeding, Blade, Tailwind, Livewire, Filament and accessibility

Claude Code reads CLAUDE.md rather than AGENTS.md. To give it the same guidance, add a CLAUDE.md at the repository root that contains @AGENTS.md, which imports the file.