Plugin Architecture (Extension Model)
The core is domain-agnostic; a plugin is how a concrete domain clips onto it. This article is the architect's view of how that attachment works — enough to evaluate the extension model. For building a plugin, the Plugin Developer package is the place to go.
What a plugin provides
A plugin is a self-contained unit that supplies: an entity type (registered in the entity table at startup), its own entity-object and {entity_slug}_workspace join tables, entity-scoped workspace statuses, migrations, and a manifest declaring its identity, routes, and extension points. The core validates all of this at startup; a plugin that fails validation is skipped, and the rest of the platform starts normally.
The four extension points
The manifest supplies four functions the core calls at defined moments — this is the whole contract by which the core delegates domain behaviour without knowing anything about the domain:
resultHandler— persists domain artifacts when a workflow completes.workspaceSnapshotProvider— builds the plugin's slice of the webhook payload at launch.dashboardStatsProvider— returns the plugin's completion KPI (the core can't compute what "completed" means for a domain it doesn't understand).workspaceDisplayResolver— resolves display names and routes so the core can render the plugin's entities in shared tables.
The completion flow — where it clips in tightest
The most instructive moment is completion. When a workflow finishes, the core looks up the plugin's resultHandler (via the entity slug) and invokes it inside a shared database transaction, passing a transactional client. If the handler succeeds, the core transitions the workspace to the workflow's resulting status and commits; if the handler throws, the core rolls the whole thing back and marks the execution failed_permanent. So domain persistence and core status advancement either both happen or neither does — a clean, atomic hand-off, with the core owning the transaction and the plugin owning the writes.
The boundary that makes it safe
All of this rests on the core/plugin boundary: the core calls plugin code through these declared points, plugin tables reference core tables (never the reverse), and a well-behaved plugin touches core state only through core services. The extension model is powerful precisely because it's narrow — four functions and a manifest — and because the boundary keeps a plugin from tangling into core internals. For the concrete manifest, table shapes, and handler signatures, continue into the Plugin Developer package.