SkillBundleSource interface. Three implementations are available; you choose by setting source.type in the plugin options.
static
Loads from a local filesystem path. Optional watch: true re-fetches on file change (debounced 250ms). Falls back to a 2-second poll if fs.watch rejects the file (some platforms reject watch on certain filesystems).
.json→ JSON.yaml/.yml→ YAML- anything else → format sniffed from the first non-whitespace byte
npm
Loads from a published npm package’s default (or named) export. Pinned by your package.json — updates require a server redeploy, which is intentional: the lower-blast-radius distribution mode.
ResolvedBundle shape; the plugin parses it through the same Zod validator the static source uses.
verifyProvenance defaults to true, and npm provenance verification is not implemented yet, so with true the source refuses to load the package (it is never imported) and logs why. Set verifyProvenance: false to load it without a provenance check.
saas
Pulls bundles from a configured HTTPS endpoint with a pinned JWT. Boot pull is mandatory; interval polling refreshes; a last-good cached bundle on disk is the fallback if a fresh pull fails.
Before every pull the pinned authToken is verified against the SaaS: signed by a key served at jwksUrl (fetched without the token, redirects refused), iss equal to expectedIssuer, aud including expectedAudience, not expired. A token that fails is refused with [saas-source] pull token rejected: …: nothing is pulled, and the cached bundle is not used instead. The JWKS being unreachable, or serving no usable signing key (no RSA, EC or OKP public key for signatures), counts as an ordinary pull failure, so the cache fallback still applies.
Boot semantics
- Initial pull runs synchronously when the plugin’s
BundleSyncServicefactory boots. - If the pull succeeds, the bundle is persisted to
bundleCacheDirand applied via the sync service. - If the pull fails AND a cached bundle exists, the cache is loaded with a startup warning. The server stays healthy. A rejected
authTokenis not a pull failure: the cache is not used, and the source reports an error. - If the pull fails AND no cache exists, the source throws — the plugin reports a startup error but does not kill the server.
Redirects
The pull carriesauthToken as a bearer token, so it never follows a redirect: endpoint must serve the bundle directly. A 3xx (or a browser runtime’s status-0 opaqueredirect) fails the pull like any other pull error, with the boot fallback described above.
Polling
DefaultpollIntervalMs: 300_000 (5 min). Overlapping polls are skipped via a single-flight gate — if a previous poll is still in flight when the next interval fires, the new poll is dropped (not queued).
Source-conflict policy
If multiple sources somehow register the samebundleId (e.g. you wire both static and saas simultaneously), the plugin’s sourceConflictPolicy controls resolution:
'static-wins'(default): static beats npm beats saas'last-wins': most recent apply wins (use with caution; race-prone)'reject': fail to apply when a conflict is detected
options.source, so this policy only takes effect when more than one source registers the same bundleId.