andreapollastri / larapilot
Spec-driven AI product workflow for Laravel โ discovery, backlog, planning, implementation, and review via Laravel Boost.
Requires
- php: ^8.3
- illuminate/console: ^12.0|^13.0
- illuminate/contracts: ^12.0|^13.0
- illuminate/filesystem: ^12.0|^13.0
- illuminate/http: ^12.0|^13.0
- illuminate/routing: ^12.0|^13.0
- illuminate/support: ^12.0|^13.0
- laravel/boost: ^1.0|^2.0
- symfony/yaml: ^7.0|^8.0
Requires (Dev)
- laravel/pint: ^1.27
- orchestra/testbench: ^10.6|^11.0
- pestphp/pest: ^3.8|^4.1
- phpstan/phpstan: ^2.1
README
From product idea to reviewed Laravel code โ with an AI product team that follows a real process.
Larapilot is a spec-driven workflow for Laravel projects, integrated with Laravel Boost. Install the package, run /larapilot-* skills in your AI editor, and ship backlog artifacts, plans, and reviewed code from .larapilot/.
The agent proposes. You approve what ships. Human-in-the-loop, always.
๐ Documentation: larapilot.web.ap.it ยท Walkthrough ยท API
Why Larapilot
AI agents are fast, but isolated prompts are not a product process. Larapilot gives your assistant a disciplined squad โ discovery โ backlog โ plan โ implement โ review โ ship โ with 27 personas (Mark, John, Alex, Anne, โฆ) as review lenses, not costumes.
Each skill orchestrates the conversation. Artisan commands persist state; Boost skills drive the workflow in chat; MCP exposes Laravel context and workflow tools to your editor.
Core loop
Greenfield โ repeat steps 3โ5 per user story:
/larapilot-inception "โฆ" โ /larapilot-spec โ /larapilot-plan US-XXX
โ /larapilot-implement US-XXX โ /larapilot-review US-XXX
| When | Start with |
|---|---|
| New product, pivot, or legacy rewrite | /larapilot-inception |
| One new capability on an existing product | /larapilot-feature "โฆ" |
| Defect or regression | /larapilot-bug "โฆ" |
Optional: /larapilot-design before plan ยท /larapilot-ship when MVP stories are DONE ยท /larapilot-autopilot to batch plan + implement ยท /larapilot-settings for project effort / backlog granularity / git / testing modes ยท /larapilot-backstage to publish the repo into a Backstage developer portal.
Git discipline follows settings.git_mode (default Gitflow without auto-push): one feature/US-XXX-* branch per story, atomic commits per plan task; push + remote PR only when mode is GITFLOW_PUSH. Configure with /larapilot-settings. Details on the docs site.
What lands in .larapilot/
| Path | Purpose |
|---|---|
config.yaml |
Project workflow config + settings (effort, backlog, git_mode, testing, auto_approve) |
docs/PRD.md |
Product Requirements Document |
backlog/ |
User stories (US-XXX) with status machine |
plans/ |
Technical plans and tasks per spec |
mockups/{spec}/ |
Static HTML previews (optional) |
internal-feedback/{code}.md |
PM/dev comments until DONE |
design-systems/ |
Packaged references (Filament, Starter Kit, Bootstrap 5, Tailwind, AdminLTE) |
techdocs/ |
Generated Backstage TechDocs sources (only after larapilot:backstage-export --write) |
Skills write artifacts; the workflow engine blocks invalid state transitions (e.g. implement before plan, approve before review, approve with open [blocks-merge] feedback or unfinished tasks โ override with --force).
Two configuration layers
| Layer | File | Owns | Changed via |
|---|---|---|---|
| Laravel config | config/larapilot.php (publishable) + .env |
Environment toggles: routes, environments, diagnostics, LARAPILOT_API_TOKEN, package defaults |
php artisan vendor:publish --tag=larapilot-config, env vars |
| Project workflow | .larapilot/config.yaml (committed) |
Per-project settings (effort, backlog, git mode, testing, auto-approve), paths, statuses |
/larapilot-settings or php artisan larapilot:settings-set |
The YAML wins for workflow settings; Laravel config only provides their defaults on first install.
Skills
Published via Laravel Boost after php artisan boost:install:
| Skill | Role |
|---|---|
/larapilot-inception |
Product discovery โ PRD (includes Frontend Topology) |
/larapilot-spec |
MoSCoW backlog from PRD |
/larapilot-feature |
Mini-inception for one evolutiva |
/larapilot-bug |
Bug triage โ fix spec or rework |
/larapilot-frontend-companion |
Link external FE repo path, scan code โ from Laravel only |
/larapilot-design |
Static HTML mockups from design system |
/larapilot-plan |
Technical plan + tasks for a spec |
/larapilot-implement |
Code + tests on a feature branch |
/larapilot-review |
Human gate โ DONE or rework |
/larapilot-ship |
Release checklist when MVP is done |
/larapilot-autopilot |
Batch plan + implement |
/larapilot-settings |
Persist effort / backlog granularity / git mode / testing / auto-approve for the project |
/larapilot-backstage |
Publish the repo into a Backstage developer portal (catalog entity + TechDocs) |
/larapilot-tracker |
Mirror the backlog into Linear ยท Asana ยท Jira ยท Trello ยท ClickUp ยท Monday |
During inception, John + Joe ask Frontend Topology: Laravel-coupled, SPA-in-Laravel, or API + external frontend. For split-repo: larapilot:frontend-set --path=โฆ, then frontend-scan โ all from Laravel. Details: Frontend companion.
Dashboard & API (dev/staging)
When the dashboard is browsable (never in production):
/larapilotโ Kanban board, PRD reader, spec detail with mockup preview and internal feedback/larapilot/apiโ JSON over the same artifacts (board, specs, PRD, OpenAPI at/larapilot/api/docs)GET /larapilot/api/backstageโ Backstage catalog entities + delivery snapshot (see Developer portal)POST /larapilot/api/specs/{code}/commentsโ append internal feedback from scripts or tooling
API auth: set LARAPILOT_API_TOKEN to require a bearer token (or X-Larapilot-Token header) on every /larapilot/api/* request โ strongly recommended on shared staging hosts. Without a token, reads stay open in the allowed environments, but writes are refused outside local/development/testing.
Diagnostics (bug triage)
Read-only runtime snapshot for /larapilot-bug and local debugging โ never mutates workflow state.
| Surface | How |
|---|---|
| API | GET /larapilot/api/diagnostics โ same dashboard gate (dev/staging only); 404 when LARAPILOT_DIAGNOSTICS_ENABLED=false |
| CLI | php artisan larapilot:diagnostics โ --lines= (cap log tail), --no-logs (status + checks only) |
| MCP | Larapilot diagnostics tool, or RunArtisanTool with larapilot:diagnostics |
Query params (API): ?lines=100 (default from config, capped by max_log_lines) ยท ?no_logs=1 to omit the log tail.
Payload: app (name, env, Laravel/PHP versions, โฆ), checks (storage_writable, cache, database, queue, log_file), healthy (critical checks), optional logs with secrets redacted ([REDACTED]).
Config (config/larapilot.php / env): LARAPILOT_DIAGNOSTICS_ENABLED (default true), LARAPILOT_DIAGNOSTICS_LOG_LINES (default 100), LARAPILOT_DIAGNOSTICS_MAX_LOG_LINES (default 500).
Workflow state still changes only via skills or Artisan โ not from the dashboard or API.
Frontend companion โ split repo
When Frontend Topology is API + external frontend, Laravel is the only Larapilot cockpit. PRD, backlog, plans, and all /larapilot-* commands run in the backend workspace. The FE repo is a linked write target configured with an absolute path.
How it works
Laravel (cockpit) Frontend repo (write target)
โโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโโโโโโ
.larapilot/docs/PRD.md src/โฆ โโโ implement (repo: frontend)
.larapilot/backlog.yaml tests/โฆ
.larapilot/plans/ (application code only)
.larapilot/mockups/
- Inception records topology and asks for the FE absolute path โ
larapilot:frontend-set. - Scan (
larapilot:frontend-scan) reads existing FE structure before planning evolutive work. - Spec โ plan โ implement run on Laravel. UI tasks use
repo: frontendand write underdata.frontend.repo_path.
Setup commands
php artisan larapilot:frontend-set --path=/absolute/path/to/fe-repo --stack=React php artisan larapilot:frontend-scan
Or /larapilot-frontend-companion in the Laravel editor.
| Command | Purpose |
|---|---|
larapilot:frontend-set |
Persist frontend.repo_path (+ optional stack) |
larapilot:frontend-scan |
Detect stack, tooling, structure, entrypoints |
Details: Frontend companion.
Developer portal โ Backstage
Larapilot is repo-level; Backstage is org-level. The integration publishes .larapilot/ into the portal โ one way. The workspace stays the source of truth and workflow state never changes from Backstage.
php artisan larapilot:backstage-export # preview the bundle (writes nothing) php artisan larapilot:backstage-export --write # generate catalog + TechDocs
Or run /larapilot-backstage, which asks for owner/system/lifecycle first and persists them to .env.
| Generated | Contents |
|---|---|
catalog-info.yaml (repo root) |
Component entity + one API entity per OpenAPI contract found (storage/api-docs/api-docs.json, openapi.json, โฆ) |
mkdocs.yml (repo root) |
TechDocs config โ docs_dir: .larapilot/techdocs, plugin techdocs-core |
.larapilot/techdocs/ |
index.md (delivery snapshot), prd.md, backlog/index.md, backlog/US-XXX.md (spec + plan + tasks) |
catalog-info.yaml and mkdocs.yml are never overwritten without --force โ a project may already own them. Everything under .larapilot/techdocs/ is regenerated, and pages for deleted specs are pruned. --no-techdocs generates the catalog entity only.
Catalog identity lives in Laravel config / .env (not .larapilot/config.yaml โ it describes the org catalog, not the delivery workflow):
| Env var | Default | Purpose |
|---|---|---|
LARAPILOT_BACKSTAGE_ENABLED |
true |
Master switch for the integration and its endpoints |
LARAPILOT_BACKSTAGE_OWNER |
guests |
Backstage Group/User that owns the entity โ set this, Backstage flags unresolvable owners |
LARAPILOT_BACKSTAGE_SYSTEM |
โ | Parent System entity, when your org uses them |
LARAPILOT_BACKSTAGE_LIFECYCLE |
experimental |
experimental ยท production ยท deprecated |
LARAPILOT_BACKSTAGE_COMPONENT_TYPE |
service |
Backstage component type |
LARAPILOT_BACKSTAGE_NAME |
slug of app.name |
Entity name override |
LARAPILOT_BACKSTAGE_BASE_URL |
app.url |
Base URL for catalog links/annotations โ non-production only |
LARAPILOT_BACKSTAGE_TECHDOCS |
true |
Generate the TechDocs site |
LARAPILOT_BACKSTAGE_WORKFLOW_API |
false |
Also register the dev-only Larapilot API as an API entity |
Live delivery data
For a Backstage plugin or entity provider, two endpoints share the dashboard gate (dev/staging only):
GET /larapilot/api/backstageโ catalog entities, rendered YAML, TechDocs metadata, and a leansnapshot(metrics, per-status counts, blocking feedback, story list without bodies) built for polling many reposGET /larapilot/api/backstage/catalog-info.yamlโ the same entities as a Backstageurllocation
Call them through the Backstage backend proxy so LARAPILOT_API_TOKEN stays server-side. The API returns 404 in production by design โ if the portal cannot reach a dev/staging host, ship the committed catalog-info.yaml and TechDocs instead.
Keep the catalog fresh with a CI step on the default branch (--write --force) or by re-running /larapilot-backstage after PRD and backlog milestones. php artisan larapilot:config-show reports the current mapping under data.backstage.
Project trackers โ Linear, Asana, Jira, Trello, ClickUp, Monday
Optional, API-key based. Mirrors the backlog into the tool the rest of the organisation already uses, so a PM or a client can follow delivery without opening backlog.yaml. .larapilot/ stays the source of truth โ the tracker is a window, not a second workflow.
php artisan larapilot:tracker-status --ping # provider, status map, credentials check php artisan larapilot:tracker-push --dry-run # what would change, no API calls php artisan larapilot:tracker-push # backlog โ tracker php artisan larapilot:tracker-pull # tracker โ drift report (read-only) php artisan larapilot:tracker-pull --apply # write mapped statuses back
Or run /larapilot-tracker, which picks the provider, collects the credentials into .env, and checks the status map before the first push.
What gets mirrored
| Larapilot | Tracker |
|---|---|
User story US-XXX |
Issue / task / card / item titled US-XXX โ Title, with the spec body, priority, points, and epic |
Plan task TASK-XX |
A native sub-issue, subtask, subitem, or checklist item โ not a checklist buried in the description |
| Workflow status | The provider's own column: workflow state, status, section, list, or status-column label |
| Provider | Auth | Destination | Subtasks | Status maps to |
|---|---|---|---|---|
| Linear | personal API key | team key | sub-issues (parentId) |
workflow state |
| Jira (Cloud, REST v2) | email + API token | project key | subtasks (parent) |
status, via a workflow transition |
| Asana | personal access token | project gid | subtasks | section (a DONE story is also marked complete) |
| Trello | key + token | board id | checklist items | list (board column) |
| ClickUp | personal token pk_โฆ |
list id | subtasks (parent) |
list status |
| Monday | API token | board id | subitems | status-column label |
Only one provider is active at a time (LARAPILOT_TRACKER_PROVIDER), but links are stored per provider, so switching tools โ or switching back โ never loses the mapping.
Direction: push writes, pull reports
Push is authoritative. Pull is a report: it reads remote state and lists drift, and changes the backlog only with --apply. Two things it will never do:
- Set a spec to DONE. DONE is a human review gate that records the merge commit โ that stays with
/larapilot-reviewandlarapilot:spec-approve. - Change spec text. Titles, bodies, and acceptance criteria are owned by
.larapilot/; the card description says so, and edits made in the tracker are overwritten on the next push.
TODO and PLANNED mapping to the same column is normal and is not reported as drift. A remote status outside the map is reported as drift with no suggestion rather than guessed at.
Set LARAPILOT_TRACKER_PULL_COMMENTS=true to import tracker comments as internal feedback (non-blocking, imported once).
Configuration
Credentials live in .env only โ never in .larapilot/, which is committed:
| Env var | Purpose |
|---|---|
LARAPILOT_TRACKER_ENABLED |
Master switch (default false) |
LARAPILOT_TRACKER_PROVIDER |
linear ยท asana ยท jira ยท trello ยท clickup ยท monday |
LARAPILOT_TRACKER_SYNC_TASKS |
Mirror plan tasks as native subtasks (default true) |
LARAPILOT_TRACKER_PULL_COMMENTS |
Import remote comments as internal feedback (default false) |
LARAPILOT_LINEAR_API_KEY / _TEAM |
Linear key and team key (e.g. ENG) |
LARAPILOT_JIRA_BASE_URL / _EMAIL / _API_TOKEN / _PROJECT |
Jira site, account, token, project key |
LARAPILOT_ASANA_TOKEN / _PROJECT |
Asana PAT and project gid |
LARAPILOT_TRELLO_KEY / _TOKEN / _BOARD |
Trello credentials and board id |
LARAPILOT_CLICKUP_TOKEN / _LIST |
ClickUp token and list id |
LARAPILOT_MONDAY_TOKEN / _BOARD / _DESCRIPTION_COLUMN |
Monday token, board, and the long-text column that carries the spec body |
Status maps live in config/larapilot.php โ tracker.providers.{provider}.status_map. If a mapped column does not exist, the push fails and names the columns that do โ Larapilot never creates columns in your tracker.
.larapilot/tracker.yaml holds the spec โ remote-id mapping. Commit it: without a shared map, every machine creates duplicate cards. It contains identifiers only, never credentials. php artisan larapilot:config-show reports the wiring under data.tracker, including whether credentials are present โ never their values.
Requirements
- PHP ^8.3
- Laravel ^12 or ^13
- Laravel Boost
^2.0(installed automatically) - MCP-capable editor (Cursor, Claude Code, VS Code, โฆ)
Quickstart
composer require andreapollastri/larapilot --dev php artisan larapilot:install php artisan boost:install
larapilot:install also scaffolds Larastan level 5+ and Laravel Pint (phpstan.neon.dist, pint.json, Composer scripts, dev dependencies). Run php artisan larapilot:quality before merge; larapilot:doctor fails when the gate is missing.
Already on Boost? Refresh skills once:
php artisan boost:update --discover
Register MCP servers in your editor if needed:
{
"mcpServers": {
"laravel-boost": {
"command": "php",
"args": ["artisan", "boost:mcp"]
},
"larapilot": {
"command": "php",
"args": ["artisan", "mcp:start", "larapilot"]
}
}
}
First run in your editor:
/larapilot-inception "your product idea"
Then /larapilot-spec, and the per-story loop above.
Upgrade
composer update andreapollastri/larapilot php artisan larapilot:update php artisan larapilot:doctor
Runtime-only refresh (skip Boost republish): php artisan larapilot:update --skip-boost.
larapilot:update overwrites .larapilot/design-systems/ with the packaged references; pass --preserve-design-systems to keep local customizations.
Learn more
- Why & how it works
- Five walkthrough examples โ new product, legacy port, feature, bug, frontend companion
- Frontend companion โ split FE repo + shared PRD sync
- Backstage portal โ catalog entity, TechDocs, delivery snapshot
- Design systems
- Team personas
License
MIT ยฉ Andrea Pollastri