Packages
Capell packages extend the CMS without adding feature code to Core, Admin, or Frontend. Use a package when a capability can be installed, versioned, tested, and disabled independently.
Use this section if you build or maintain a Capell package.
| I need to… | Read |
|---|---|
| Get from a scaffold to a rendering package | Extension and theme development |
| Decide between host, package, and app code | Host, package, or app code |
| Build a package from start to finish | Build an extension end to end |
| Find the shortest path for a package task | Package authoring jobs |
| Understand package files and structure | Package anatomy |
| Choose an extension point | Extension point chooser |
| Add admin surfaces | Admin extensions |
| Add anonymous-safe frontend output | Frontend extensions |
| Look up exact contracts, tags, and tests | Extension point API reference |
| Browse every extension surface in one list | Extension surface catalogue |
| Know which Capell versions a package supports | Extension API versioning |
| Test a package | Testing packages |
| Debug missing package output | Extension troubleshooting |
| Plan the next Core compatibility line | Core Filament neutrality and 2.x preparation |
Use Extension surface vocabulary when you need the shared definitions for packages, surfaces, contributions, capabilities, install impact, and Marketplace proof.
When To Create A Package
Section titled “When To Create A Package”| Package is right when… | Keep it in the app when… |
|---|---|
| The feature has its own settings, routes, resources, widgets, jobs, or frontend output. | It is one-off project glue with no reuse value. |
| It should be installable through Composer or Marketplace. | It depends heavily on private app models. |
| It needs its own tests and release cadence. | The behavior is just app configuration. |
| It contributes through Capell extension points. | It needs to patch host package classes. |
If you are unsure, use Host, package, or app code.
Required Files
Section titled “Required Files”Every package should have:
composer.jsoncapell.json- at least one service provider
README.md- translations for visible labels
- focused package tests
Packages with admin UI usually also include translations, Filament resources/pages/widgets, settings schemas, an admin bridge, and feature tests.
Create A Package
Section titled “Create A Package”Use capell:make-extension for new local package scaffolds. The command keeps the existing extension command name, but the generated files use package language and manifest v3 provider buckets.
Interactive mode asks for missing values:
php artisan capell:make-extensionNon-interactive scripts must pass the package name, profile, and target directory:
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 --premiumUse minimal for a lean installable package: Composer metadata, capell.json, one runtime provider, translations, README, a phpunit.xml.dist, a Testbench TestCase, and a manifest test. Use full when you want live examples of the metadata/install/admin provider buckets, a package-owned command, a settings class, a Layout Builder content widget with typed Data objects, and package-owned widget assets; it adds a provider-discovery test.
Neither profile scaffolds public-output safety tests, render hooks, or Actions — write those yourself. The generated TestCase also registers only your own provider, so add CapellServiceProvider before testing anything that touches Capell; see Standalone package harness.
Install A Package In An App
Section titled “Install A Package In An App”Capell packages are Composer packages. For a published package:
composer require vendor/examplephp artisan capell:package-cache:clearFor local development, add a Composer path repository to the app for the package path you are editing:
composer config repositories.vendor-example path packages/examplecomposer require vendor/example:@devUse a wildcard path repository in composer.json when the app should load several local packages:
{ "repositories": [ { "type": "path", "url": "packages/*", "options": { "symlink": true } } ]}For a private Git repository, configure a Composer VCS repository:
composer require vendor/example:^1.0Use symlink: true path repositories during local development so package edits apply without reinstalling. Switch to a tagged constraint such as ^1.0 once the package is published. See Package authoring for scaffold profiles and Marketplace sharing.
capell.json
Section titled “capell.json”Keep the manifest boring and explicit. It should identify the package, provider classes, version constraints, contribution metadata, settings ownership, lifecycle commands, and Marketplace metadata when relevant.
Use package-owned manifests and generated extension pages as the source of truth for public add-on package names. Use Packages and extensions for host package boundaries and authoring entry points.
Service Providers
Section titled “Service Providers”Package providers should register only what the package owns:
- config and translations
- migrations and settings migrations
- package settings classes
- admin bridges and admin surface contributions
- render hooks, assets, frontend widgets, and cache invalidation rules
- routes, commands, policies, events, and jobs
Do not register optional-package behavior from the host repo. The package that owns the feature should register it.
Use the extension point chooser before adding a new registration path. Use the extension point API reference when you need exact contracts, tags, and test recipes. Use extension troubleshooting when a package is installed but its admin, frontend, settings, cache, or marketplace contribution does not appear.
Installer and Marketplace surfaces have their own narrow contracts:
Actions, Data, And Settings
Section titled “Actions, Data, And Settings”- Put domain behavior in
src/Actions/*Action.php. - Put structured inputs/outputs in
src/Data/*Data.php. - Cast JSON settings/state to Data objects where practical.
- Keep Filament resources, Livewire components, controllers, commands, and jobs thin.
- Use translations for visible strings.
Command, resource, or job tests should fake Actions when the Action already has direct coverage.
Admin Contributions
Section titled “Admin Contributions”Deciding between an AdminBridge and a direct contribution:
- Contributing several admin concerns (resources + widgets + settings)? Use an
AdminBridge. - Just one surface? A direct
CapellAdmin::contributeToAdminSurface(...)call is fine. - Unsure? Prefer a bridge. One class is easier to audit than scattered calls.
Use an AdminBridge when a package contributes more than one admin concern:
use Capell\Admin\Data\Bridges\AdminBridgeContextData;use Capell\Admin\Support\Bridges\AbstractAdminBridge;use Capell\Admin\Support\Bridges\AdminBridgeRegistrar;
final class PackageAdminBridge extends AbstractAdminBridge{ public function register(AdminBridgeRegistrar $registrar, AdminBridgeContextData $context): void { $registrar->resource(ExampleResource::class, group: 'content', name: 'examples'); $registrar->widget(ExampleWidget::class); $registrar->settingsClass('examples', ExampleSettings::class); $registrar->settingsSchema('examples', ExampleSettingsSchema::class); }}Extend AbstractAdminBridge. The AdminBridge interface also declares isEnabled(AdminBridgeContextData $context): bool, so implementing the interface directly without it is a fatal error; the abstract class provides a default that returns true.
Small packages can contribute directly with CapellAdmin::contributeToAdminSurface(...), but bridges are easier to audit.
Useful admin surfaces:
| Need | Use |
|---|---|
| Filament page/resource/widget/configurator | AdminSurfaceContributionData through AdminBridgeRegistrar. |
| Page, site, layout, or user form fields | Tagged schema extenders. |
| Dashboard Filament widgets | CapellAdmin::registerDashboardFilamentWidget(...). |
| Header tools | AdminToolItem::TAG. |
| User menu items | CapellAdmin::registerUserMenuItem(...). |
| Admin widgets | CapellAdmin::registerDashboardFilamentWidget(...). |
Frontend Contributions
Section titled “Frontend Contributions”Frontend package code must preserve public HTML safety. Anonymous output must not expose authoring selectors, model IDs, field paths, signed admin URLs, permissions, or package internals.
| Need | Use |
|---|---|
| Small HTML injection | RenderHookRegistry::register(...). |
| Public widget | LayoutWidgetRegistry::register(...) with LayoutWidgetTarget::FrontendBlade or FrontendLivewire, when the Layout Builder package is installed. |
| Package CSS/JS | TailwindAssetsRegistry::registerSource(...) and registerImport(...). |
| Page cache invalidation | CacheInvalidationRegistry::registerDependency(...). |
| Static-site export hook | StaticSiteExtensionRegistry::register(...) when the static export package is installed. |
Database And Migrations
Section titled “Database And Migrations”- Package migrations live in the package.
- Settings migrations live in
database/settings/. - Guard settings migrations with table/column existence checks.
- Writes go through Actions, not model methods.
- If the package introduces public rendering data, make sure controllers/actions load it before Blade renders.
Cover package behavior where it lives:
- Action tests for domain behavior.
- Feature tests for routes, commands, Filament pages/resources, and package install/setup.
- Public rendering tests for frontend output and safety.
- Architecture tests for package boundaries.
- Manifest/provider tests so package discovery fails loudly.
When testing commands or UI surfaces that only orchestrate Actions, fake the Action boundary with Laravel Actions fakes instead of running the Action again. The surface test should prove prompts, options, output, permissions, and Action invocation; the Action test should prove domain behavior.
Use the narrowest package Pest command during development, then broaden before release:
vendor/bin/pest packages/admin/tests --configuration=phpunit.xmlRelease Checklist
Section titled “Release Checklist”Use the package checklist before release.
composer.jsonandcapell.jsonmatch the package name.- Provider registers only package-owned behavior.
- Visible strings use translations.
- Actions and Data objects cover meaningful boundaries.
- Migrations are idempotent for installed apps.
- Public frontend output is safe for anonymous users.
- Package tests pass in isolation.
- README explains install, config, commands, extension points, and troubleshooting.
| Need | Read |
|---|---|
| Add ready-made page sections | Content Sections |
| Build pages visually with widgets | Layout Builder |
| Understand package/surface/capability terms | Extension surface vocabulary |
| Write package service providers | Service providers |
| Understand the extension lifecycle | Extension lifecycle |
| Use Actions, Data, and settings correctly | Actions, Data, and settings |
| Ship migrations and settings tables | Database and migrations |
| Study worked extension examples | Extension examples |
| Group packages into products | Package product groups |
| Scaffold packages with AI assistance | AI creator |
| Understand package authoring as a platform | Package authoring |
| Create an installable theme package | Creating custom themes |
| Understand package boot/provider buckets | Package boot lifecycle |
| Debug Composer/manifest/provider discovery | Debugging package discovery |
| Avoid unsafe package patterns | Do not do this |