Plugin system
The plugin system is inseam’s extension surface. A plugin is an NPM package whose identity is its package name (@inseam/plugin-<name> first-party, inseam-<name> third-party); the loader verifies NPM provenance attestation, materializes a durable plugin_package row, and admits the plugin to an ephemeral LoadedPluginSet. Plugins contribute through typed registries on RegistrationContext and run handlers against a freshly-scoped RuntimeContext whose capabilities the host has granted.
How it fits
Section titled “How it fits”A plugin’s packageName is captured in the closure that builds its contexts; plugins never pass their own name in, so they cannot forge another plugin’s tag or register under another plugin’s identity. The plugin_package row is durable and network-synced (rides the Events outbox); the LoadedPluginSet is process-local and regenerated on every host boot.
Capability authority is the intersection of three layers: the plugin’s manifest declares requested, the host config declares the allowed ceiling, and installation persists the granted set the loader passes in per PluginLoadRequest. Registration-time add calls and runtime-time method calls both check the granted set and throw CapabilityDeniedError synchronously when missing.
Two surfaces, split by package:
@inseam/plugin-contract—PluginPackageName,PluginPackageRow,PluginManifest,PluginModule,RegisterFn,RegistrationContext(with itsRegistriesbag),RuntimeContext(withsource/emit/kv/http/clock/log/self),Capability, and every error class. Zero runtime deps.@inseam/core(plugin-system contribution) —openPluginRegistry,PluginRegistry,AttestationVerifier(test seam — production uses the sigstore-backed default),DEFAULT_PLUGIN_SYSTEM_LIMITS,ALL_CAPABILITIES.
Key pieces
Section titled “Key pieces”PluginModule.register(ctx)— the only thing a plugin author exports. Pure declaration:ctx.registries.*.add(...)only. No I/O, no fetch, no KV. A throw fails the load and rolls back partial contributions.RegistrationContext— exposed toregister. Bundles the area registries (connections,sources,locationKinds,events,operations, …). Auto-tags every contribution with the plugin’spackageName.RuntimeContext— passed as the first argument to each handler the plugin registered.source.write(auto-tagged),kv(durable per-plugin scratch),http(capability-gated),clock,log,self.- Seven-step load sequence. Tarball verification → manifest parse → capability intersection → row materialization → context construction →
registerinvocation → registry admission. Each step has its own error class; a failure lands in that plugin’sPluginLoadOutcomeand sibling plugins in the batch continue. developmentMode: true— opens the registry with attestation skipped andworkspace:*package names stored verbatim, so in-tree dev data is visibly tagged. Production hosts refuseworkspace:*names outright.
Exact signatures and the full load sequence: @inseam/plugin-contract API · arch/plugin-system/spec.md.
When to use this vs alternatives
Section titled “When to use this vs alternatives”Every inseam extension — Connection kind, Location Kind, identifier kind, listener, future area — ships through this same shape. A third-party plugin depends on @inseam/plugin-contract plus whichever area contract(s) it implements against, and on nothing else from the framework.
The minimum a plugin author needs:
- Name the package
@inseam/plugin-<name>(first-party) orinseam-<name>(third-party). The name is the durable identity recorded on every row the plugin asserts. - Publish with
npm publish --provenancefrom CI. The loader refuses tarballs without a valid attestation. - Export a
register(ctx)function. Pure declaration only. - Run runtime work inside the handlers registered through the area registries. Write triples through
ctx.source.write(auto-tagged), keep cursors / refresh tokens inctx.kv, fetch throughctx.http, time throughctx.clock. - Declare every capability the plugin will exercise in
inseam.capabilities.requested. The host’sgrantedset isrequested ∩ allowed; touching a service without its capability throwsCapabilityDeniedError.
If you’re tempted to put runtime work directly in register, stop — register is declaration-only by design. Move the work into a handler registered through ctx.registries.
See also
Section titled “See also”- LLM summary — dense reference for agents.
- Connection —
ConnectionDefinitions are plugin contributions. - Source — Location Kinds are plugin contributions;
uninstallPlugintriggers the envelope-keyed sweep. - Access — identifier kinds and envelope-party roles flow through
ctx.registries. - Events —
plugin_package.observed/plugin_package.revokedride the outbox. arch/plugin-system/design.md— why identity is the package name and whyplugin_packageis a row.arch/plugin-system/spec.md— types, the 7-step load sequence, errors, acceptance criteria.