Implementing the Four Extension Points
The four extension points are the heart of the plugin contract: they're the functions the core calls, at defined moments, to hand domain-specific work back to you. Your manifest declares all four; the core invokes them. This is the overview — the most complex one, the result handler, gets its own deep dive.
The four, at a glance
| Extension point | The core calls it when… | It returns… |
|---|---|---|
resultHandler | a workflow execution completes successfully | void — you persist domain artifacts |
workspaceSnapshotProvider | it's assembling the webhook payload at workflow launch | the domain JSON for workspace_snapshot |
dashboardStatsProvider | it's rendering the dashboard | { total, completed, label? } |
workspaceDisplayResolver | it's rendering dashboard tables that show entity identity | [{ workspaceId, entityDisplayName, manageRoute }] |
resultHandler
Called at completion, inside the core's transaction (you receive a client — use it for all writes; never BEGIN/COMMIT/ROLLBACK). You validate and persist the workflow's result payload, and — when the workflow creates a new workspace — create that workspace via coreWorkspaceService.create and link it. You do not update workspace status; the core does that after you return. If you throw, the core rolls everything back and marks the execution failed_permanent. This one is important enough to have its own article.
workspaceSnapshotProvider
Called at launch. You inspect the workspace's current state and return the domain context for the run — the plugin's slice of the webhook payload (for the default plugin: the thing's title, description, current text, input, and status). This is how the operator's specific request reaches the workflow. If it throws, the launch fails cleanly (no execution created).
dashboardStatsProvider
Called when the dashboard renders. You return your completion KPI — { total, completed, label } — because only your plugin knows what "completed" means for your entity. The core can't compute it; it just renders the card you return.
workspaceDisplayResolver
Called when the core renders shared tables (in-progress executions, recent errors) that need to show which entity a workspace belongs to. Given a list of workspace IDs your plugin owns, you return a display name and manage-route for each (a null route for a deleted/unresolvable one). The core only ever passes you workspace IDs your plugin owns, so you don't filter others.
The shape of the deal
Notice the pattern: the core handles everything domain-agnostic (dispatch, logging, cost, status transitions, table rendering) and calls you for the four things only your domain can answer — persist a result, build domain context, define completion, name an entity. Implement these four faithfully and your plugin is fully wired into the platform.