Plugins Component¶
Purpose¶
The Plugins component provides discovery, lifecycle management, marketplace integration, and installation workflows for both built-in modules and user-installed plugins.
Main locations¶
app/core/components/plugins/entrypoint.pyapp/core/components/plugins/logic/manager.pyapp/core/components/plugins/logic/plugin_service.pyapp/core/components/plugins/logic/context.pyapp/core/components/plugins/ui/*
Responsibilities¶
- discover core components and user plugins from disk
- import and validate plugin entrypoints and manifests
- create isolated
ModuleContextinstances - persist plugin activation state in the database
- install, upgrade, reload, disable, and uninstall plugins
- integrate with GitHub archives and version tags
- request marketplace collection sync through the Git component
- trigger UI refreshes after lifecycle changes
Internal layers¶
ModuleManager¶
Owns runtime loading behavior:
- scans
core/componentsandplugins - validates folder names and manifests
- restores activation state from
plugin_states - blocks plugins with unmet dependencies
- activates plugins once the database-backed state is known
PluginService¶
Owns package acquisition behavior:
- downloads plugin source from GitHub
- performs safe ZIP extraction into staging
- installs plugin dependencies into
vendor/ - swaps upgraded plugin directories atomically
- maintains marketplace metadata and collection caches
- runs a background update checker that compares installed versions to release tags
Background update checker (1.0)¶
A periodic task (interval LYNDRIX_PLUGIN_UPDATE_CHECK_INTERVAL_S, default 6h,
plus one check shortly after boot) compares each installed plugin's version to
the newest release tag from its repo (reusing the cached tags API — no extra
network cost per request). Results live in memory and surface as
PluginOut.latest_version / PluginOut.update_available on GET /api/plugins,
so the React plugin card shows an update badge. A newer tag emits
plugin:update_available (forwarded over SSE) and a persisted, admin-gated bell
entry. The marketplace list itself loads lazily and negative-caches failures, so
opening the plugin manager never blocks on a slow collection fetch.
Logs¶
Per-module log lines land in a thread-safe, per-source in-memory ring buffer
(core/logger.py, LogRingBuffer). GET /api/logs?source=Plugin:<name>&limit&level
(and /api/logs/sources, both api:read) serve them; PluginOut.log_source
precomputes the {Core|Plugin}:<name> source string. The React plugin manager
opens a live log modal for any module — plugins and core components alike.
Events¶
Subscribes¶
git:status_updatesystem:boot_completeplugin:files_changeddb:connected
Emits¶
git:syncplugin:install_startedplugin:installedplugin:install_failedplugin:update_availableplugin:state_changedplugin:files_changedui:needs_refresh
Runtime notes¶
- plugins remain pending until the database-backed activation state can be restored
requirements.txtwithout a matchingvendor/directory is treated as a warning condition- repository names with dashes are normalized to underscores for Python imports
- plugin secret access is scoped through
ModuleContext LYNDRIX_PLUGINS_DESIRED(comma-separatedurl[@version]) is reconcilable from a marketplace-fed picker in Settings → Plugins, which writes the same string