Extension and Theme Development
This guide is the cold-start path for a third-party Capell package: scaffold it,
load it in a development app, prove it renders, and prepare a Marketplace
submission. The generated package README.md is the source of truth for that
package’s own commands and dependencies; keep it with the package and update it
when you add a public surface.
1. Scaffold
Section titled “1. Scaffold”Use the colon commands for new work. The older hyphenated commands remain available for compatibility, but generated instructions use these names:
php artisan capell:make:extension acme/notice-board \ --profile=full \ --path=packages \ --name="Notice Board"
php artisan capell:make:theme aurora \ --package=acme/aurora-theme \ --path=packages \ --name="Aurora" \ --extends=defaultChoose minimal when you only need a package provider and manifest. Choose
full when you want the working example widget, settings, typed input and
render Data objects, widget assets, and tests. A generated theme includes its
provider, manifest, CSS source, and a rendering test.
Do not hand-copy a first-party package directory. The generators use only the public package contracts and avoid Capell’s internal development overlay.
2. Read the generated package before editing it
Section titled “2. Read the generated package before editing it”capell.json is the package’s runtime contract. Keep its package name, version,
providers, contributions, assets, and Marketplace metadata consistent with
composer.json. A full extension has an example content widget blueprint; use
it as the starting point for a real widget rather than placing rendering queries
in a Blade view.
For themes, the themeKey value in capell.json is also the CSS registration key.
The provider must register the package CSS with the matching conditional
Tailwind import:
condition: 'theme-css:aurora',This is intentionally not a requirement for a literal
theme-registration.css file in every theme. Capell collects the registered
Tailwind sources and produces the applicable bundle. A missing CSS source or a
different key silently leaves the theme unstyled, so treat the condition as part
of the theme’s public contract.
If you introduce a new design token, register its utility name in every frontend bundle that needs it, alongside the token source. Adding only a token value does not make a Tailwind utility available. This is per bundle: a utility registered for an admin bundle is not automatically available to a public theme bundle.
3. Load the package in a development app
Section titled “3. Load the package in a development app”Use a normal Composer path repository in the consuming application’s
composer.json while developing locally:
{ "repositories": [ { "type": "path", "url": "packages/notice-board", "options": { "symlink": true } } ]}Then install it by Composer name:
composer require acme/notice-board:@devphp artisan capell:package-cache:clearphp artisan config:clearThe package manifest is cached. Run both cache-clearing commands whenever you
change capell.json, especially after renaming a contribution or settings
class. Otherwise a warm app can keep using a deleted class or omit a newly added
widget even though the package files are correct.
For a published package, replace @dev with a tagged normal Composer
constraint such as ^1.0.
4. Validate before rendering
Section titled “4. Validate before rendering”Run both commands from the consuming app. They share the extension-audit
contract: any result with severity=error returns a failing exit code.
php artisan capell:package:lint packages/notice-boardphp artisan capell:extension-audit packages/notice-boardThe lint checks the manifest, naming and version sanity, referenced assets, and theme CSS registration. The audit additionally verifies the declared extension contracts. Fix errors rather than suppressing them; scaffold output should be clean from its first run.
Useful failures and their fixes:
| Failure | What to check |
|---|---|
A theme reports no theme-css:<key> registration | Use the exact theme key from capell.json in the provider’s conditional Tailwind CSS registration. |
| A theme CSS source is missing | Restore or configure the source file that the provider registers, then regenerate the frontend assets. |
| A contribution or settings class cannot be found after a rename | Run capell:package-cache:clear and config:clear; confirm the manifest class name and Composer PSR-4 namespace. |
| A screenshot or Marketplace asset is missing | Keep the referenced path package-relative and commit the file before publishing; consumer audits also accept paths explicitly marked export-ignore. |
Run the generated package tests as you extend the blueprint. The README names the smallest relevant command for that package.
5. Prove it renders
Section titled “5. Prove it renders”For a full extension, open Admin → Pages, edit a development page, and find
its Layout Builder field. In the main area choose Add widget, select
<package display name> example, enter Dogfood heading for Heading and
Rendered by the generated widget. for Body, then save. Preview or open
that page publicly and confirm both strings render and the package’s
widget.css/widget.js resources load. The generated widget key is the Composer
package name with / changed to ., for example acme.notice-board.
Replace the example data with an Action or Data object that supplies only public, cache-safe render state.
For a theme, select the theme in the development app, request a public page, and verify that its CSS is in the generated frontend output. After changing a theme CSS source, its Tailwind registration, or token utility names, regenerate the app’s frontend Tailwind assets, then clear the package and configuration caches before checking the public page again:
php artisan capell:frontend-tailwind-assetsphp artisan capell:package-cache:clearphp artisan config:clearA successful provider boot is not proof that the conditional CSS made it into the page.
6. Prepare a Marketplace submission
Section titled “6. Prepare a Marketplace submission”Keep two versions distinct:
manifest-versiondescribes thecapell.jsonschema (currently manifest v3).versionis your package release version and should match the published Composer release.
Neither field sets Marketplace maturity. Third-party authors submit through the Marketplace submission flow with their repository, package metadata, support, privacy, security, data, and third-party disclosures. Reviewers assign the Marketplace state. An approved community submission starts in Labs; Marketplace Beta acknowledgement is a purchaser-install-flow requirement, not an author-controlled manifest field. The public label for stable is Released.
Do not create or copy Capell’s first-party release ledgers
(docs/release-catalogue.json or config/release-packages.json) into a
third-party package. They are Capell-owned operational records, not a package
publishing interface.
Before submitting, tag the Composer release, run the package’s tests and both validation commands, include accurate Marketplace metadata and package-relative assets, and confirm the package installs through a normal Composer repository.