spora-ai/installer
A Laravel installer package for Spora AI that streamlines setup by publishing config and assets, registering service providers, and running required migrations, so you can get a new Spora AI integration running quickly from a single Artisan command.
Architecture fit. spora-ai/installer is a Composer plugin, not a Laravel package. Its job is narrowly scoped: intercept post-package-install/post-package-update events and relocate Spora-typed packages out of vendor/ into convention-based application paths (plugins/{$name}/, public/spora/, public/plugins/{$slug}/). That places it in the bootstrap layer of the stack, alongside composer/installers, not in the application layer. Architecturally this is a legitimate pattern — it is how WordPress, Drupal, and nwidart/laravel-modules achieve zero-config install ergonomics — but it is also the highest-blast-radius place to put logic, because it executes arbitrary code during every composer install.
Integration feasibility. Mechanically straightforward. Requirements are Composer 2.x with composer-plugin-api, PHP version parity with spora-core, and the plugin enabled via allow-plugins in composer.json (mandatory since Composer 2.2 — this is a hard gate, not optional). The conventions are hardcoded rather than configurable, which is the right call for a first-party companion package but removes flexibility for monorepos or non-standard public roots. A single composer require plus an allow-plugins entry gets you there.
Technical risk. This is where the package demands scrutiny:
composer/installers. The generic solution to this exact problem already exists and is battle-tested: declare custom types and installer-paths in root composer.json. The value here is zero-config defaults, not capability. That's a defensible product decision, but it means the risk is taken on for convenience alone — worth confirming the team isn't better served by three lines of installer-paths config.plugins/ while Composer's autoloader still expects them in vendor/ creates a dual-source-of-truth problem. spora-core must register PSR-4 roots for plugins/* and public/plugins/*; if it doesn't, you get class-not-found at runtime, not install time.composer update --lock-only runs, cache restoration from a warm CI cache, and partial-failure rollback are the classic holes in this pattern. Untested behavior here produces orphaned directories and stale public/ assets.{$slug} derivation, and read-only public/ in containerized deploys.Key questions. Is spora-core a hard dependency with a pinned compatible range, or optional? Does the plugin handle post-package-uninstall and clean up orphaned directories? Is the behavior configurable via extra.spora-installer paths, or fully hardcoded? Does it publish under symlinked atomic-deploy releases (requiring public/spora and plugins/ to be shared, not release-local)? What is the support contract — is this maintained alongside spora-core releases, and is there a public changelog? Has any third party audited the install-time code?
Stack fit. Good fit for a Laravel app that has bought into the Spora ecosystem end to end. spora-core supplies the runtime (service providers, autoload registration, asset routing), and this installer supplies the placement convention that makes the runtime's expectations true. The two are co-designed; adopting one without the other yields nothing. For teams running vanilla Laravel with a handful of custom packages, this adds a dependency and an install-time code-execution surface for marginal gain.
Migration path. Three scenarios, in ascending cost:
composer require spora-ai/spora-core spora-ai/installer, add both to allow-plugins, install Spora packages, done. No migration.composer install against a clean vendor/ and diffing the tree; expect no unexpected writes..gitignore rules, deploy scripts, and asset build configs. Treat as a small project, not a config change.Compatibility. Confirm three axes before adoption: composer-plugin-api version supported vs. your Composer binary (2.2+ for allow-plugins), PHP floor vs. your runtime, and spora-core version range. The composer.lock will pin all three; the risk is a transitive composer update silently widening the plugin API constraint.
Sequencing. Non-negotiable order:
allow-plugins entries for spora-ai/installer (and any other Spora plugin-type packages) in root composer.json before requiring — otherwise the install aborts interactively in local dev and hard-fails in CI.spora-core at a pinned range.spora-ai/installer at an exact version; commit the lock file..gitignore for plugins/ and public/spora/*, public/plugins/* (keep .gitkeep where the directory must exist).plugins/ and the Spora public assets, plus a post-deploy permission check.Maintenance. Lowest-confidence dimension. Single-vendor, zero stars, zero dependents, no external contributors — bus factor of one. The maintenance burden on your team is small but nonzero: you are now responsible for tracking composer-plugin-api deprecations (Composer 3 will likely change plugin contracts), auditing diffs before every upgrade, and owning the failure mode where an abandoned upstream forces you to fork or inline the logic. Budget an explicit "vendor exit" option: because the behavior is conventions over a handful of event hooks, reimplementing it in-house or replacing it with composer/installers config is a few hours of work, not a rewrite. That keeps the risk bounded.
Support. No community support channel, no issue history to search, no Stack Overflow corpus. Every question routes to the vendor or to reading the source. Practically: read the plugin class before adopting, and treat the source as the documentation. For an internal platform team, acceptable. For a team that expects to file a ticket and get an answer, not acceptable.
Scaling. Negligible runtime cost — the work happens once per composer install, not per request. Scales fine across any number of Spora packages and any number of app instances. The scaling concern is organizational: as more internal packages adopt the spora-* types, the installer becomes load-bearing infrastructure, and a change to its path conventions becomes a coordinated multi-repo migration with no upgrade tooling.
Failure modes. Ranked by likelihood and pain:
allow-plugins missing — install aborts. Loud, fast, caught in the first CI run. Fine.type — package stays in vendor/, spora-core finds nothing, runtime failure surfaces far from the cause. Silent and expensive. Mitigate with a smoke test asserting each expected plugin path exists post-install.--no-dev production build if the code path is untested.public/spora disappears on the next deploy, taking user-uploaded or generated assets with it if anything writes there. Verify the directory is shared, not per-release.vendor/ from before the plugin was enabled may skip the relocation hook, producing a vendor-only tree that passes locally and fails in staging.plugins/ directories after composer remove, requiring manual cleanup and a documented runbook.Ramp-up. Low for developers — the conventions are self-evident once seen and match the mental model of WordPress/Drupal/module ecosystems. The real ramp-up cost is on whoever owns the build and deploy pipeline: they need to understand why a Composer plugin is writing into the application tree, what the allow-plugins gate means for their security posture, and which directories must survive deploys. Write one page covering the three target paths, the allow-plugins requirement, the shared-directory deploy config, and the canary smoke test — and require the exact-version pin until the package has external consumers and a maintenance track record.
How can I help you explore Laravel packages today?