Skip to content

Register plugin emit types

This guide shows how to declare and register your plugin’s event emit types so they satisfy manifest emit-type validation (INV-S5). For why the invariant exists and what it catches, see Substrate contract invariants.

This procedure applies only to plugins with a non-empty crypto.emits block. Plugins without crypto.emits skip emit-type validation entirely.

crypto:
emits:
- event_type: scene_ic
sensitivity: always
description: "In-character scene pose. Always encrypted."
- event_type: scene_ooc
sensitivity: may
description: "Out-of-character aside. Caller decides per-emit."

Fields: event_type (string), sensitivity (always/may/never), description (human-readable rationale).

Call holomush.register_emit_type(<type>) at top level of main.lua for every event type the plugin may emit:

holomush.register_emit_type("scene_ic")
holomush.register_emit_type("scene_ooc")

The substrate’s Load pass captures these calls and validates them against the manifest before marking the plugin ready.

Top-level idempotency note: top-level code in main.lua runs once at Load AND once per event/command delivery. Limit top-level code to:

  • local function and local <const> declarations
  • holomush.register_emit_type(...) calls

Non-idempotent hostfunc calls (kv_set, create_location, etc.) at top level are forbidden — they fire repeatedly on every delivery. Put those calls inside on_event or on_command handlers.

Implement the pluginsdk.EmitTypeRegistrar interface. The SDK adapter auto-populates InitResponse.registered_emit_types from your registry:

type scenePlugin struct {
registry *pluginsdk.EmitRegistry
// ...
}
func newScenePlugin() *scenePlugin {
r := pluginsdk.NewEmitRegistry()
r.RegisterEmitType("scene_ic")
r.RegisterEmitType("scene_ooc")
return &scenePlugin{registry: r}
}
// EmitRegistry implements pluginsdk.EmitTypeRegistrar.
func (p *scenePlugin) EmitRegistry() *pluginsdk.EmitRegistry {
return p.registry
}

Register types during construction (in main() before pluginsdk.ServeWithServices, or inside Init) so the registry is populated when the host reads it.

For the full mechanism design including proto extension and host-side validator, see INV-S5 Mechanism Design Spec and ADR holomush-3vsb — Startup-Time Set-Equality Validation of crypto.emits Declarations.