Skip to content

Extension API Versioning

Every Capell package declares the Capell API range it supports. This page explains what that declaration means, what Capell guarantees inside it, and how to tell whether a Capell release will break your package.

capell.json requires capellApiVersion, a Composer semver constraint — not a fixed version:

{
"manifest-version": 3,
"capellApiVersion": "^1.0"
}

Capell compares its own extension API version against your constraint with Composer\Semver\Semver::satisfies(). The current value is published as a constant:

Capell\Core\Support\Extensions\CapellExtensionApi::CURRENT_VERSION; // '1.1.0'

This is the extension API version. It is deliberately separate from the Capell release version and from any package’s own version, so the two can move independently: a Capell release that adds no extension surfaces does not bump it.

^1.0 is the right constraint for almost every package. It accepts every 1.x extension API, including additive minor releases. Pin tighter only when you knowingly depend on behaviour introduced in a specific minor version, and never pin to an exact version — "1.1.0" excludes 1.2.0 and makes the package uninstallable on the next Capell release for no benefit.

The base manifest validator only requires capellApiVersion to be a non-empty string. The constraint is actually evaluated in two places:

CheckBehaviour on mismatch
php artisan capell:extension-auditReports “Manifest capellApiVersion does not allow the current Capell API.”
php artisan capell:upgrade --dry-runReports a finding for an empty or non-satisfying constraint before the upgrade runs

So an incompatible constraint surfaces at audit and upgrade-planning time, not at boot. A package whose constraint excludes the running Capell is not silently disabled — run the audit to find out.

Individual contributions narrow this further. public static function compatibleCapellApiVersion(): string is an abstract member of the ExtensionContribution contract, so every class listed in contributes[] must define it, and the audit checks each one against the running API in addition to the manifest-level constraint. A contribution can therefore declare a tighter range than the package as a whole.

The extension API version tracks the stable extension surfaces — the registries, contracts, and manifest requirements a package is allowed to build on. It does not cover internal Capell classes, which may change in any release.

Two generated files in this directory define the surface:

  • extension-surface-catalog.json — every extension surface, each marked with a stability level. Generated by scripts/build-extension-surface-catalog.php and contract-tested. Verify it is current with:

    Terminal window
    composer check:extension-surfaces

    The Composer script passes --check, which only verifies. Run the script without that flag to rewrite the catalogue.

  • stable-extension-api-baseline.json — a frozen snapshot of the surfaces marked stable, including a reflection hash of every public method signature, plus core’s Composer requirements, migrations, and config keys. Verify with:

    Terminal window
    composer check:stable-extension-api

The baseline check rebuilds the snapshot from current code and diffs it against the committed file. Drift is reported as removed class: X or changed public signature: X, and also as a bare section name — manifestRequirements, packageConstraints, migrations, or configKeys — so adding a core migration or changing a core Composer constraint counts as drift too.

Drift only passes with an explicit compatibility decision record in stable-extension-api-decision.json whose drift entries match the detected drift exactly. Running the script without --check does rewrite the baseline, so the guarantee ultimately rests on reviewing the committed baseline diff rather than on the script alone.

That is the practical guarantee behind ^1.0. A stable surface does not lose a class or change a public signature within the major line without a recorded, reviewed decision.

Checking Your Package Against A Capell Release

Section titled “Checking Your Package Against A Capell Release”

Before supporting a new Capell version:

Terminal window
php artisan capell:extension-audit path/to/your-package
php artisan capell:upgrade --dry-run

The audit validates the manifest against the v3 contract and checks the API constraint. It exits non-zero when any result has severity error. The upgrade dry run reports version findings across every installed package without changing anything.

Neither command verifies that your package still behaves correctly. Run your own suite against the target Capell release as well — see Testing packages.

  • Patch — no extension surface change.
  • Minor — surfaces added. Existing packages on ^1.0 keep working; this is the common case.
  • Major — a stable surface was removed or changed. Packages must widen or move their constraint deliberately, and the change carries a recorded decision.

Declaring ^1.0 and testing against each Capell release is the whole maintenance obligation for most packages.