Appearance
Plugin Runtime
Server plugins extend the API server with new actions: sending email, calling an external API described by an OpenAPI document, reading platform data, or anything a partner implements with the Plugin SDK. This page describes how the server discovers, configures, invokes and upgrades plugins. Building one is covered in Server Plugins; the administrator's view is in Plugins.
What a plugin is
A plugin is a Python package installed alongside the server that declares a plugin class through a registered entry point. The class exposes:
| Element | Purpose |
|---|---|
| Name and version | Identity of the plugin; each version is registered as its own definition. |
| Configuration schema | A JSON Schema describing what an administrator fills in when creating an instance (hosts, credentials, options). |
| Actions | The operations the plugin offers, each with an input schema and an output schema. |
| Instance action schemas | Optional: action schemas refined per instance (for example, the list of operations found in a configured OpenAPI document). |
invoke | The single entry point the server calls with the action name, the validated request and the resolved configuration. |
Discovery and registration
The server scans installed packages for plugin entry points at startup, again periodically in the background, and on demand through the CLI. For each plugin found it loads the class, reads its schemas and actions, and records a plugin definition keyed by name and version. A definition is read-only metadata; nothing is executed until an instance is invoked.
Because plugins are ordinary packages, adding one means installing it into the server image (or the environment the server runs in) and letting discovery pick it up. Operators decide which packages are installed; see the trust model below.
Definitions and instances
| Concept | Meaning |
|---|---|
| Plugin definition | One registered version of a plugin: its schemas and actions. |
| Plugin instance | A configured deployment of a definition, with a name, the configuration values and an enabled flag. Several instances of the same plugin can coexist (for example two mail servers). |
The web app renders the configuration schema as a form. Configuration is validated against the schema on create and update, and any instance action schemas are computed at that moment and stored with the instance, so the workflow editor can show instance-specific choices.
Sensitive values are not stored in the instance configuration. Administrators put them in the vault and write a reference ($secret:name); the plugin only ever receives the resolved value at invocation time.
Invocation
Actions are invoked from two places: an Action node in a workflow run, and the API (which the web app uses for the Test action button and which integrators can call directly). The steps are the same:
- Load the instance and its definition; both must exist and be enabled.
- Validate the request payload against the action's input schema.
- Resolve vault references in the instance configuration.
- If the instance carries an API key reference, validate the key and derive the plugin's identity and scopes from it.
- Call the plugin's
invokewith the action, the request, the resolved configuration and a context (request identifier, actor, scopes). - Return the result, which the workflow stores as the node output or the API returns to the caller.
Host API: reading and changing platform data from a plugin
A plugin that needs platform data (for example the last measurements of a patient before deciding whether to alert) does not call the HTTP API. It uses the host API, an in-process command bus exposed by the server through the SDK.
- The plugin declares that it needs an API key reference in its configuration schema. The administrator stores an API key in the vault and references it when creating the instance.
- At invocation the server resolves the key and gives the plugin exactly the scopes of that key. The plugin never sees the key itself.
- Each host command declares the scope it requires; a call without that scope fails with a permission error, exactly as an API call would.
- Commands are versioned and self-describing (name, description, required scopes, input and output schemas), and a plugin can list the catalogue at runtime.
- A guard limits chains of plugin → host → plugin calls to a small depth, so a misconfigured plugin cannot recurse indefinitely.
This keeps one authorisation model for humans, integrations and plugins: everything is an API key with scopes.
Errors and their effect
| Error class raised by the plugin | Meaning | Effect |
|---|---|---|
| User error | The input is invalid or the action cannot apply. | The call fails with a client error; a workflow node fails, no retry. |
| Permission error | The plugin's identity lacks a required scope. | Same as a user error, reported as forbidden. |
| Transient error | A temporary condition (network, upstream busy). | The workflow node is retried with backoff; API callers receive an error they may retry. |
| Any other exception | A defect in the plugin. | Reported as an upstream failure; details go to the server log, not to the caller. |
Server-side validation failures (unknown action, payload not matching the schema, disabled instance, missing vault entry) are reported before the plugin runs, with error codes that identify the cause.
Upgrades and decommissioning
When a new version of an installed plugin is discovered, the server disables the previous definition versions and reassigns existing instances to the new version, keeping their configuration. Instances therefore follow the installed package without manual work. If a new version changes its configuration schema, administrators should review each instance's configuration afterwards; the web app flags instances whose stored configuration no longer validates.
Removing a package does not delete its definitions or instances; they remain visible so that workflows referring to them can be reviewed and updated.
Isolation and trust model
Plugins run inside the server process. They share its resources and its database connection, and a plugin defect can affect the server. For that reason:
- only packages vetted by the operator are installed into the server image;
- plugins receive credentials only through vault references, never as stored plaintext;
- data access is gated through the host API with a scoped key, so the blast radius of a plugin is bounded by the scopes granted to it;
- transient failures are isolated per workflow run and per subscription.
Partners who build plugins should follow the SDK's testing guidance so that behaviour is verified outside a production instance first. See Server Plugins.