mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-08-06 11:18:06 +00:00
CLAUDE.md and .cursorrules disagreed about plugin-directory fallback behavior; the code (SchemaManager.get_schema_path) probes plugins/ BEFORE plugin-repos/, and the main discovery path has no fallback at all — both files now describe the real behavior, preferring symbol names over line numbers so the references rot slower. REST_API_REFERENCE.md pointed at app.py:144/:607 for mounts that live at :199/:799 and counted 92 routes where there are 94. PLUGIN_ARCHITECTURE_SPEC.md's historical banner gains a note that its example imports (src/plugin_system/base_classes/*_plugin.py) never shipped — the real base classes are src.base_classes.sports.SportsCore and src.base_classes.hockey.Hockey. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SXb4mKcAkVaxkeTb3YnAdr
3.4 KiB
3.4 KiB
LEDMatrix
Project Structure
src/plugin_system/— Plugin loader, manager, store manager, base plugin classweb_interface/— Flask web UI (blueprints, templates, static JS)config/config.json— User plugin configuration (persists across plugin reinstalls)plugin-repos/— Default plugin install directory used by the Plugin Store, set byplugin_system.plugins_directoryinconfig.json(default perconfig/config.template.json:167). Not gitignored.plugins/— Legacy/dev plugin location. Gitignored (plugins/*). Used byscripts/dev/dev_plugin_setup.shfor symlinks. The plugin loader does NOT fall back to it —PluginManager.discover_plugins()(src/plugin_system/plugin_manager.py) scans only the configured directory. Fallbacks exist in two narrower places: store operations (StoreManager._find_plugin_path()instore_manager.py) and schema lookup (SchemaManager.get_schema_path()inschema_manager.py, which probesplugins/beforeplugin-repos/).
Plugin System
- Plugins inherit from
BasePlugininsrc/plugin_system/base_plugin.py - Required abstract methods:
update(),display(force_clear=False) - Each plugin needs:
manifest.json,config_schema.json,manager.py,requirements.txt - Plugin instantiation args:
plugin_id, config, display_manager, cache_manager, plugin_manager - Config schemas use JSON Schema Draft-7
- Display dimensions: always read dynamically from
self.display_manager.matrix.width/height
Plugin Store Architecture
- Official plugins live in the
ledmatrix-pluginsmonorepo (not individual repos) - Plugin repo naming convention:
ledmatrix-<plugin-id>(e.g.,ledmatrix-football-scoreboard) plugins.jsonregistry athttps://raw.githubusercontent.com/ChuckBuilds/ledmatrix-plugins/main/plugins.json- Store manager (
src/plugin_system/store_manager.py) handles install/update/uninstall - Monorepo plugins are installed via ZIP extraction (no
.gitdirectory) - Update detection for monorepo plugins uses version comparison (manifest version vs registry latest_version)
- Plugin configs stored in
config/config.json, NOT in plugin directories — safe across reinstalls - Third-party plugins can use their own repo URL with empty
plugin_path
Skin System (visual overlays for sports scoreboards)
- Skins live in
skins/<skin-id>/(skin.json + skin.py), NOT in plugin dirs — plugin reinstall deletes plugin dirs - Core:
src/skin_system/(ScoreboardSkin, SkinContext, runtime); hook:SportsCore._render_game()insrc/base_classes/sports/core.py - Skins render onto
ctx.canvasonly; fallback to built-in renderer onFalse/exception (3 strikes disables for session) - View-model guaranteed keys are frozen (see
test/test_skin_system.py::TestViewModelContract) — renaming keys in_extract_game_details_commonor sport extractors breaks published skins - Validate skins headlessly:
python scripts/validate_skin.py --skin <id>; docs:docs/SKIN_SYSTEM.md,docs/CREATING_SKINS.md - Skins are NOT monorepo plugins: no manifest bump / update_registry.py needed
Common Pitfalls
- paho-mqtt 2.x needs
callback_api_version=mqtt.CallbackAPIVersion.VERSION1for v1 compat - BasePlugin uses
get_logger()fromsrc.logging_config, not standardlogging.getLogger() - When modifying a plugin in the monorepo, you MUST bump
versionin itsmanifest.jsonand runpython update_registry.py— otherwise users won't receive the update