Skip to content

Package Authoring

Capell treats package authoring as a platform surface, not a side effect of Laravel auto-discovery. A package should declare what it owns in capell.json, route runtime work through provider buckets, and keep public output safe for anonymous users and cached HTML.

Use the existing capell:make-extension command to create new packages:

Terminal window
php artisan capell:make-extension
php artisan capell:make-extension vendor/example --profile=minimal --path=packages --name="Example"
php artisan capell:make-extension vendor/example-tools --profile=full --path=packages --premium

Interactive mode asks for the package name, scaffold profile, target directory, and display name when they are missing. Non-interactive scripts must pass package, --profile, and --path.

minimal creates the smallest useful package:

  • Composer metadata and PSR-4 autoloading.
  • Manifest v3 with all provider buckets present and only the runtime bucket populated.
  • A runtime provider extending AbstractPackageServiceProvider.
  • Translations, README, and a manifest/public-cache safety test.

full creates live, harmless examples:

  • Metadata, install, runtime, admin, and frontend providers.
  • A package-owned console command.
  • Settings registration with translated labels.
  • A safe frontend render hook backed by an Action and Data object.
  • Frontend asset registration.
  • Tests for manifest validity, provider bucket shape, and unsafe public-output regressions.

Public package output must not expose admin or editor details. Render hooks and Blade views should receive hydrated public state from Actions or view models, not query models directly. Cached HTML must remain safe to serve to anonymous visitors, signed-in users, admins, crawlers, and static exports.

Use the generated tests as the baseline, then add package-specific tests for settings, commands, admin surfaces, routes, migrations, and frontend rendering before release.

Install, setup, and after-install work that can run from the web UI or Marketplace must be implemented as Actions, not nested Artisan commands. Add lifecycle classes that implement Capell\Core\Contracts\PackageLifecycleAction and declare them in capell.json:

{
"actions": {
"install": "Vendor\\Example\\Actions\\InstallExamplePackageAction",
"setup": "Vendor\\Example\\Actions\\SetupExamplePackageAction",
"afterInstall": "Vendor\\Example\\Actions\\AfterInstallExamplePackageAction"
}
}

Console commands may remain as thin CLI adapters for developers, but they should delegate to the same Action. Web-triggered lifecycle work will prefer these Actions and will not fall back to legacy commands.

Require published packages normally:

Terminal window
composer require vendor/example
php artisan optimize:clear
php artisan capell:package-cache:clear

For local development, point the app at a sibling package repository:

{
"repositories": [
{
"type": "path",
"url": "../capell-packages-4/packages/*",
"options": {
"symlink": true
}
}
]
}

Then require the package by Composer name:

Terminal window
composer require vendor/example:@dev

Use the wildcard path repository when one app should load several local packages. For one package only, this is enough:

Terminal window
composer config repositories.vendor-example path ../capell-packages-4/packages/example
composer require vendor/example:@dev

Before sharing a package, tag a release, run package tests, and audit the manifest:

Terminal window
php artisan capell:extension-audit ../capell-packages-4/packages/example

Marketplace-ready packages should have aligned composer.json and capell.json names, clear marketplace metadata, screenshots where useful, support notes in the README, and a normal Composer install path through Packagist, private Composer, VCS, or another configured repository.