Configure and Initialize Plugins

View as Markdown

Use this page when your application manages plugin configuration and lifetime. It explains the shared plugin-host API in Rust, Python, Node.js, Go, and C. Use Plugin Configuration Files for the full plugins.toml format and merge rules. Use a component guide for component-specific settings.

Choose a Configuration Path

NeedUse
Configure the CLI or a host through standard filesCreate plugins.toml. Relay discovers it at startup.
Add settings in application codePass a PluginConfig to initialize or validate.
Test one chosen file with an embedded hostPass that plugins.toml file as the optional second argument.
Check only a complete in-memory static documentUse exact validation. It does not read files or check dynamic plugins.
Preflight a deployment without starting plugin codeUse validate. It reads and resolves the same configuration as initialize.

Initialize, Validate, or Validate Exactly

All bindings use the same three operations. They accept a canonical plugin document. The document has a version, components, and optional policy. Component configuration keys use snake_case in every binding.

OperationWhat it doesSide effects
initializeResolves, validates, and activates plugins.Starts one host and returns its activation handle.
validateResolves and validates configuration, policy, and trust.Does not load plugin code or start a host.
Exact validationValidates only the supplied static document.Does not read files or check dynamic plugins.
BindingInitializeValidateExact validation
Rustinitialize(config, path)validate(config, path)validate_exact(config)
Pythonawait plugin.initialize(config, path)plugin.validate(config, path)plugin.validate_exact(config)
Node.jsawait plugin.initialize(config, path)plugin.validate(config, path)plugin.validateExact(config)
GoInitialize(config, path)Validate(config, path)ValidateExact(config)
Cnemo_relay_plugin_initializenemo_relay_plugin_validatenemo_relay_plugin_validate_exact

path is optional. In Rust it is an Option<PathBuf>. In Python it can be a string or path-like value. Node.js uses an optional string, Go uses an optional string pointer, and C accepts a nullable C string.

Know Which Configuration Relay Uses

Relay merges file layers first, then applies the configuration passed by your application. Programmatic values therefore take precedence over file values.

default: user plugins.toml → system plugins.toml → application config
explicit: explicit plugins.toml → system plugins.toml → application config

An explicit path replaces user-file discovery; it does not remove the system file. A missing file is skipped. The system file can still add settings that the application does not declare.

The application configuration can define static components. Dynamic plugin records, such as [[plugins.dynamic]], come from plugins.toml. Use the optional path when an embedded host needs a specific dynamic-plugin file.

For details such as list order, component matching, disabled components, and how omitted values behave, see Plugin Configuration Files.

Per-Language Plugin Configuration

The following examples validate before activation. They use an empty document to show the host lifecycle. Replace it with component settings from the guide for the plugin you want to use.

import asyncio
from nemo_relay import plugin
config = plugin.PluginConfig()
path = "path/to/plugins.toml"
report = plugin.validate(config, path)
if any(item["level"] == "error" for item in report["config"]["diagnostics"]):
raise RuntimeError(report["config"]["diagnostics"])
async def main() -> None:
async with plugin.activate(config, path) as activation:
print(activation.report)
# Run application work while plugins are active.
asyncio.run(main())

Read the Report

validate returns a PluginHostReport. A successful initialize stores the same kind of report on its activation handle. Check the report before starting application work.

Report fieldMeaningWhat to do
config.diagnosticsStatic document warnings and errors.Stop on error; review warnings before deployment.
config.runtime_diagnosticsBounded failures after activation.Inspect during troubleshooting and shutdown.
dynamic_pluginsResults for dynamic plugin records.Check status and failure for trust, policy, or schema problems.

A diagnostic has a level, code, and message. It also names the component and field when Relay knows them.

For every lifecycle-selected dynamic plugin, validate returns a report even when integrity or signature verification fails. Trust failures do not make validate raise; inspect status.integrity, status.authenticity, and failure, then fail the deployment if the report is not acceptable. A failed trust report has selected = false because Relay will not activate that plugin. With startup = "required", initialize still rejects the same failure before it loads plugin code.

validate is a preflight. It proves that Relay can resolve and check the configuration without starting plugin code. It does not prove that a remote exporter can deliver data after activation. Use component health checks and runtime diagnostics for that work.

Keep the Activation Handle Alive

initialize returns a PluginHostActivation. Keep it alive while any plugin callback can run. Only one plugin-host activation can exist in a process at a time.

Close the handle during normal shutdown. Closing removes component-owned registrations before Relay unloads native libraries or stops worker processes. If close fails, keep the handle and retry close; do not deregister a custom plugin kind while its activation is still active.

Use a guaranteed cleanup path. Node.js flushes queued subscribers before it closes the activation. Python and Rust close the activation after application work finishes.

import asyncio
from nemo_relay import plugin
async def main() -> None:
config = plugin.PluginConfig()
activation = await plugin.initialize(config)
try:
# Run application work while plugins are active.
print("plugins are active")
finally:
await activation.close()
asyncio.run(main())

Common Use Cases

Preflight a Deployment

Call validate with the same configuration and optional file path that production will use. Fail the deployment on error diagnostics or a dynamic plugin failure. This checks configuration, manifest compatibility, and trust policy before the application starts plugin code.

Configure a Service in Code

Build a PluginConfig for application-owned settings. Call initialize once during startup, retain the activation handle, and close it during graceful shutdown. This works well when the service owns its plugin choices.

Use a Provisioned Plugin File

Store shared plugin settings and dynamic-plugin records in plugins.toml. Pass the file path to validate and initialize when the host must use that selected file instead of a discovered user file. This is useful for a service that receives configuration from its deployment system.

Validate One Component in Isolation

Use exact validation when the supplied document is complete and file discovery would hide a mistake. This is useful for unit tests and component-specific configuration helpers. Exact validation does not test manifest-backed plugins.

For a complete configuration document, see Plugin Configuration Files. For manifest-backed plugins, see Configure Discoverable Plugins.