6.4 KiB
Plugin Versioning + Compatibility Policy
The plugin runtime supports three independent version axes. This document defines the rules each axis follows and how they compose into the compatibility checks the host enforces at install time.
Axes
| Axis | Scope | Policy |
|---|---|---|
| Manifest schema version | schemaVersion field on every plugin.toml |
Integer-bumped on breaking schema changes |
| Plugin SDK version | @hivegrid/plugin-sdk npm package |
NPM SemVer |
| Host runtime version | The host binary running the plugin | NPM SemVer (hivegrid-cloud package.json) |
Each plugin pins:
schemaVersion = 1 # required
minHostVersion = "1.0.0" # optional, inclusive lower host bound
maxHostVersion = "1.9.9" # optional, inclusive upper host bound
SemVer policy for plugin authors
| Change | Bump |
|---|---|
| Add a new hook subscription | minor |
| Drop a hook subscription | major |
| Add a new declared capability | minor |
Tighten an allowedHosts / keyPattern scope |
major |
Loosen an allowedHosts / keyPattern scope |
minor |
Change entry filename |
major |
| Logic-only change inside the wasm | patch |
Re-sign with a new key (signedBy change) |
minor (audit) |
Side-by-side updates are not implemented in the foundation. The
Plugin table has a unique (tenantId, pluginId) constraint, and
installPlugin rejects a duplicate pluginId for the tenant with
already_installed. To move a tenant to a new plugin version today,
operators must disable/remove the existing install path first, then
install the replacement.
SemVer policy for the host
| Change | Bump |
|---|---|
| Add a capability to the closed enum | minor |
| Remove a capability from the closed enum | major |
| Add a new optional manifest field | minor |
| Make an optional manifest field required | major |
Bump schemaVersion (breaking manifest change) |
major |
| Reduce plugin fuel limit | major |
| Increase plugin fuel limit | minor |
| Rework hook payload shape (breaking) | major |
Compatibility matrix template (reserved)
Reserved for a future boot-time compatibility sweep. The foundation
does not evaluate an installed plugin set against this table on worker
boot. Current enforcement is per install: the manifest must parse, the
schemaVersion must be accepted, and optional minHostVersion /
maxHostVersion constraints must include the running host version.
| Host version | Manifest schemaVersion accepted |
Plugin SDK majors known to work | Status |
|---|---|---|---|
1.x |
1 |
0.x |
current |
2.x |
1, 2 |
0.x, 1.x |
planned |
When a host crosses a major boundary it must:
- Bump the rejected
schemaVersionset in the runtime. - Update this table.
- Send a deprecation banner to every plugin author 2 majors in advance (the marketplace surface owns the comms — backlog).
Install-time check
PluginLifecycleService.installPlugin validates:
- Manifest parses with the current Zod schema.
schemaVersionis in the host's accepted set.- Production runtime operations are explicitly enabled in production
with
PLUGIN_RUNTIME_PRODUCTION_ENABLED=true. - Optional
minHostVersion/maxHostVersioninclude the running host version. Bounds are inclusive; omitting both means "any host". signaturePublicKeymatchesmanifest.signedBy.manifest.signedByis present inPLUGIN_TRUSTED_PUBLIC_KEYS.- The pre-positioned disk binary verifies against the submitted
wasmSha256, manifest signature, manifest signing key, and trusted key set. - The submitted
wasmSha256matchesmanifest.wasmSha256. - No plugin with the same
(tenantId, pluginId)is already installed. - The tenant has not exceeded
PLUGIN_MAX_INSTALLS_PER_TENANT.
Foundation: any of these failing rejects the install with a
PluginLifecycleError.
Boot-time check (reserved)
The boot-time compatibility matrix remains reserved. If implemented, worker boot would:
- Read every installed
Pluginrow. - Compare against the running host version.
- Mark out-of-range plugins
incompatible_host_versionand skip them on hook fan-out until the operator updates the host or the plugin.
The foundation does not enforce this yet; plugins remain enabled
across host upgrades. Host-version constraints are enforced when a
plugin is installed, not during worker boot.
Upgrade guidance for plugin authors
- Don't ship a patch that changes capability declarations. Patches must be wasm-only; manifest changes are at least a minor.
- Re-sign on every release — the signature covers
wasmSha256so any binary change requires re-signing anyway. - Test against the host's matching SDK major before publishing. The host SDK ships in the same monorepo and is pinned to the host release.
Deviations from SemVer
Two cases break strict SemVer:
- Security re-signs: changing
signedBy(e.g. publisher key rotation) bumps minor + records an audit-event flag so operators notice. The change is non-functional, but operators must re-trust the new key. - Capability-scope tightening: tightening an
allowedHostslist is a user-visible break (some calls now deny) even though the runtime API is identical. Major bump required.
Both are tracked through the audit-log so a tenant admin can correlate upgrades with denial-row spikes.