Skip to content

Plugin API reference

Reference for the plugin API surface: the event structure, host functions, world-query functions, Go SDK types, common ABAC policy patterns, and host function error types. For a build-along walkthrough, see the Plugin Guide; for error-handling procedure, see Handle plugin errors.

The event table passed to a Lua on_event handler (and the fields of the Go plugin.Event struct) contains:

FieldTypeDescription
idstringUnique event ID (ULID)
streamstringEvent stream (e.g., location:<id>)
typestringEvent type (say, pose, arrive, etc.)
timestampnumberUnix milliseconds
actor_kindstring”character”, “system”, or “plugin”
actor_idstringActor identifier
payloadstringJSON-encoded event data

Lua plugins call host functions via the holomush global:

-- Logging (no capability required)
holomush.log("info", "Plugin loaded")
holomush.log("debug", "Processing event")
holomush.log("warn", "Something unexpected")
holomush.log("error", "Failed to process")
-- Request ID generation (no capability required)
local id = holomush.new_request_id()
-- Key-value storage (enforced via ABAC)
local value, err = holomush.kv_get("my-key")
holomush.kv_set("my-key", "my-value")
holomush.kv_delete("my-key")

World queries are enforced via ABAC policies declared in plugin.yaml. Each returns the result on success, or nil, error_message on failure.

-- Query location information
local location, err = holomush.query_location(location_id)
-- Returns: table with id, name, description, type
-- Query character information
local char, err = holomush.query_character(character_id)
-- Returns: table with id, name, player_id, location_id
-- Query characters in a location
local chars, err = holomush.query_location_characters(location_id)
-- Returns: array of character tables
-- Query object information
local obj, err = holomush.query_object(object_id)
-- Returns: table with id, name, description, is_container, owner_id, containment_type

Example manifest with world-query policies:

name: world-aware-plugin
version: 1.0.0
type: lua
events:
- say
policies:
- name: "read-world"
dsl: |
permit(principal is plugin, action in ["read"], resource is world_object) when {
principal.plugin.name == "world-aware-plugin" &&
(resource like "location:*" || resource like "character:*")
};
lua-plugin:
entry: main.lua

The Go plugin SDK provides these core types:

// Event received by plugins
type Event struct {
ID string
Stream string
Type EventType
Timestamp int64 // Unix milliseconds
ActorKind ActorKind
ActorID string
Payload string // JSON string
}
// Event to emit in response
type EmitEvent struct {
Stream string
Type EventType
Payload string // JSON string
}
// Event types
const (
EventTypeSay EventType = "say"
EventTypePose EventType = "pose"
EventTypeArrive EventType = "arrive"
EventTypeLeave EventType = "leave"
EventTypeSystem EventType = "system"
)
// Actor kinds
const (
ActorCharacter ActorKind = iota
ActorSystem
ActorPlugin
)

ActorKind is a uint8 enum in the Go SDK with a String() method that maps each constant to its wire value. In the event payload (and the Lua event table above) actor_kind is always the string form — "character", "system", or "plugin" — so the numeric constants are a Go-side convenience, not the serialized representation.

Plugins declare access in their manifest using Cedar-style DSL (default-deny). For task-focused recipes, see Plugin Access Control. At a glance:

Access NeededActionResource Pattern
Emit events to streams"emit""stream:*"
Read locations"read""location:*"
Read characters"read""character:*"
Read objects"read""object:*"
Key-value read"read""kv:*"
Key-value write"write""kv:*"
Key-value delete"delete""kv:*"
Execute commands"execute""command:*"

Host functions return errors as a second return value. For the handling pattern and correlation-ID workflow, see Handle plugin errors.

Error MessageCauseRecovery
"location not found"Location ID doesn’t existCheck ID validity, handle missing
"character not found"Character ID doesn’t existCheck ID validity, handle missing
"object not found"Object ID doesn’t existCheck ID validity, handle missing
"access denied"Plugin lacks required ABAC policyAdd policy to manifest
"query timed out"Query exceeded 5-second timeoutSimplify query or retry later
"internal error (ref: XXXX...)"Server error with correlation IDLog and surface to user