laravel/roster
Laravel Roster is a dev-only detection package that reads lockfiles, config markers, and optional source code to report installed packages, app stack and frontend, browser test tools, AI agents and editors, JS package managers, and codebase conventions via the Project facade or roster:scan command.
composer.json, package.json, and lockfiles" with a single php artisan roster:scan JSON payload. Support engineers and onboarding flows can classify a customer's stack (Livewire vs Inertia+Vue vs Inertia+React, Pest vs PHPUnit, Playwright vs Cypress) without a human reading the repo.Project::php()->uses('laravel/framework', '^11.0') and Project::stacks()->uses(Stack::InertiaReact) are the common shape across your install base, that's where docs investment goes. Also enables conditional docs ("you're on Pest — here's the Pest tab").uses('laravel/framework', '>=11 <14')) plus minimumPhpVersion() give a defensible inventory for planning framework/PHP upgrade campaigns, deprecation timelines, and EOL communications — per customer or across an entire portfolio.composer.json conflict suggestions, install wizards, and "your project doesn't meet requirements" preflight checks.approaches() surface (fillable vs guarded, pipe vs array validation, form requests vs inline validation, UUID/ULID keys, #[AsCommand] vs $signature) tells you which defaults your make:* stubs, generators, and starter kits should emit. This is the highest-leverage part for product: it turns style debates into measured distributions, with confidence ratios you can cite..claude, .cursor, AGENTS.md). This supports roadmap bets and partner/integration prioritization (e.g., is it worth building a Cursor integration?).file_exists() and lockfile parsing. Buying (adopting) it is clearly cheaper than building, provided you wrap it behind your own interface so you're not coupled to a young package's API.approaches() data can back "convention drift" reports.Adopt when:
approaches() is explicitly best-effort pattern matching with a confidence ratio, so it belongs in analytics and defaults, not in contracts.--dev, and isolate calls behind a thin internal adapter.Look elsewhere when:
ProjectManager::scan($path) and roster:scan /path help, but the package still expects Laravel/Composer conventions and must be installed somewhere to execute.Project::fresh() deliberately.Operational cautions to note in the adoption decision: multiple JS lockfiles resolve by a fixed precedence (npm, pnpm, Yarn, Bun) rather than erroring — treat that as a data-quality caveat in any telemetry; transitive dev/production classification is only reliable for Composer and npm lockfiles; and approaches() is intentionally excluded from cached scans and from toArray()/json() unless --approaches is passed, so cost and caching behave differently for that surface.
For executives: Laravel Roster is a small, MIT-licensed, Laravel-org detection package that tells us what's actually inside a Laravel project — packages and versions, frontend stack, test framework, JS package manager, even which AI coding tools the team uses — plus the coding conventions the codebase has settled into, with a confidence score. Today we learn this by asking customers and reading repos manually. Roster turns that into a single JSON command we can run in CI or support tooling. Cost is near zero: one dev dependency, no infrastructure, no lock-in, no production footprint. Upside is faster support, better-targeted docs, and product defaults grounded in real usage data instead of opinion.
For engineering: It's a read-only scanner. It reads manifests and lockfiles (plus filesystem markers), optionally pattern-matches source files under PSR-4 roots and app/, and exposes a typed Project facade: php()->uses(...), js()->usesPackageManager(...), stacks(), frontends(), browserTestFrameworks(), agents(), editors(), approaches(). Results are memoized per process, cached across processes keyed on a hash of manifests, lockfiles, and marker paths, and fall back to a direct scan if the cache driver is unavailable — with Project::fresh() as the escape hatch for Octane and queue workers. There's an artisan roster:scan [path] --approaches command that emits JSON, so we can run it in CI or against a directory without coupling our app code to it.
Honest risk framing, stated up front: it's young (167 stars, no dependents yet, 0.x-to-1.0 upgrade guide), the API may move, and approaches() is deliberately heuristic — it abstains unless a style gets at least three votes and 80% of votes cast, and it can be misled by comments or string literals. So we treat detection as directional input for analytics, defaults, and triage, never as a gate on correctness or security. Mitigation: pin the version, install with --dev, and put a thin internal wrapper in front of it so a breaking change costs us an afternoon, not a rewrite. We are not betting the roadmap on it — we're buying back the time we currently spend asking people what's in their project.
How can I help you explore Laravel packages today?