Skip to main content
A Plugin adds platform capability — a new channel adapter, a new RAG provider. That is what separates it from a Solution, which adds domain logic such as HR or recruitment.
Core does not yet provide an implementation of CoreRegistrarInterface, and nothing in Core reads or validates SolutionManifest at boot. The contracts below exist in fapost/foundation; the Core side that consumes them is not built yet.

The service provider

A Plugin is a Composer package whose service provider extends Fapost\Foundation\Lifecycle\AbstractPluginServiceProvider:
onActivate() and onDeactivate() are available to hook enabling and disabling; both are no-ops unless you override them.

The manifest

SolutionManifest is what makes a Plugin checkable at boot rather than at the moment it breaks. requiresPlatform is a version constraint on Core; requiresCapabilities names the platform capabilities the Plugin needs to be present. Boot-time and update-lifecycle validation of the manifest is the intended behaviour; Core does not perform it yet.

What you may register

Everything is meant to go through CoreRegistrarInterface, the single registration entry point defined in fapost/foundation. Core does not implement it yet.
An extension declares intent through the registrar. It must not call Route, Schedule, or the migrator directly — the platform decides when and how those are mounted.

Rules

Depend on public contracts, not Core internals. Everything a Plugin needs is in fapost/foundation. A use App\… statement in a Plugin will break on a Core refactor, and nothing in the stability promise covers it. Do not inject Vue components into the running builder. The builder front end is compiled before your Plugin is enabled. Make a node configurable by describing it with a configuration schema — see Builder UI extensions. Follow migration isolation. A Plugin migration is a DDL operation like any other: no app(), no config(), no tenant-aware services, no reads of another module’s tables. See Migration isolation.