Event Bus¶
The Lyndrix Event Bus in app/core/bus.py is the async backbone shared by core components and plugins.
Purpose¶
The bus provides a lightweight publish/subscribe model that lets components communicate without hard-coding direct dependencies.
It is used for:
- startup sequencing
- readiness signaling
- plugin lifecycle reactions
- operational notifications
- background task tracking
Core API¶
Main primitives:
bus.subscribe(topic)— decorator that registers a handlerbus.emit(topic, payload)— publish an event with an optional payloadbus.create_tracked_task(coro, name=...)— create an observable background task
Handler model¶
The bus supports both:
- synchronous handlers
- asynchronous handlers
Async handlers are wrapped in tracked tasks so that failures are logged centrally rather than disappearing silently.
Logging behavior¶
The bus also acts as a logging choke point for runtime events.
Important built-in behaviors:
- very noisy topics such as
system:metrics_updateare logged at lower verbosity - sensitive topics such as Vault init and unseal requests are redacted
- selected large payloads are summarized instead of logged verbatim
That keeps logs useful while reducing accidental data exposure.
Duplicate subscription protection¶
The bus tracks subscriber keys per topic and ignores duplicate registrations of the same callback. This helps during reload-heavy development flows and prevents repeated event handling.
Plugin integration¶
Plugins should not normally import the global bus directly.
Instead, they should use the ModuleContext helpers:
ctx.subscribe(topic)ctx.emit(topic, payload)ctx.create_task(coro, name=...)
This ensures the plugin permission model is enforced.
Permission model for plugins¶
Plugin manifests define:
permissions.subscribepermissions.emit
If a plugin tries to subscribe to or emit a topic that is not allowed, Lyndrix blocks the action and logs a warning.
Recommended event usage¶
Good plugin and component behavior usually means:
- keep topic names stable and namespaced, for example
domain:event_name - keep payloads small and JSON-friendly
- use events for cross-component contracts, not for hidden internal state
- use tracked tasks for long-running async side effects
- avoid placing secrets in event payloads
Examples of common topics¶
system:startedvault:ready_for_datadb:connectedsystem:boot_completeplugin:installedgit:status_update
For the full list currently used in the repository, see events.md.