Plugin contract
Plugins extend YggdraSIM with optional capabilities that the core must stay runnable without. This page documents the exact contract the plugin runtime expects, the reserved capability names, and the behavior when a capability is absent.
On this page
Discovery
The plugin runtime in yggdrasim_common/plugin_runtime.py scans the
plugins/ directory under the active runtime root. It loads:
- single-file plugins
plugins/<name>.py(underscore-prefixed names are skipped) - package-style plugins
plugins/<name>/with an__init__.py(skipped if that file is missing)
Loaded plugins get unique synthetic module names on the form
yggdrasim_plugin_<name>. Load errors are captured per plugin and surfaced
back to the runtime, not raised globally. A broken plugin must not break the
rest of the process.
Registration contract
Each plugin module must expose a callable:
def register_plugins(manager):
manager.register_capability("<capability-name>", <provider>)
The manager argument is the PluginManager instance. Capability names are
lowercased and stripped. Empty names are rejected.
Capability manager
The manager exposes:
| Method | Purpose |
|---|---|
register_capability(name, provider) |
register a capability |
get_capability(name) |
retrieve a capability (loads plugins lazily) |
ensure_loaded() |
force-load plugins (idempotent) |
load_errors() |
surface any per-plugin load errors |
Consumers generally call get_capability("polling") and branch on whether
it returns a provider.
Reserved capability names
| Capability | Consumers |
|---|---|
polling |
SCP11/live POLL, SCP11/test POLL, SCP11/eim_local IPAE-LIVE / IPAE-TEST |
New capabilities should be added to this list only after the consumer side is ready to use them cleanly.
Absent-plugin behavior
The contract says:
- The core must remain runnable without any plugin installed.
- A consumer that depends on a capability must either hide the verb that depends on it, or emit a clean runtime error that explicitly states the capability is optional.
- A broken plugin's error is captured and reported; it does not prevent other plugins from loading or the rest of the shell from running.
Runtime root note
Plugins live under the active runtime root, not the source tree. In source
runs that is the repository plugins/ tree. In frozen builds that is the
writable runtime root's plugins/ directory. See
Runtime Root.
Publication policy
plugins/README.md documents the publication-ignore stance: the loader
contract ships in the published core, but plugin implementation files are
intentionally ignored by default. Keep private plugins under the runtime
root only.