From 8b838ff3660d4003da69b1e3efaebc4cb823c156 Mon Sep 17 00:00:00 2001 From: Chuck Date: Tue, 7 Apr 2026 10:22:41 -0400 Subject: [PATCH] =?UTF-8?q?docs:=20fix=20.cursorrules=20=E2=80=94=20the=20?= =?UTF-8?q?file=20Cursor=20auto-loads=20to=20learn=20the=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is the file that Cursor reads to learn how plugin development works. Stale entries here directly mislead AI-assisted plugin authors on every new plugin. Several of the same bug patterns I've been fixing in the user-facing docs were here too. Display Manager section (highest impact) - "draw_image(image, x, y): Draw PIL Image" — that method doesn't exist on DisplayManager. Same bug already fixed in PLUGIN_API_REFERENCE.md, PLUGIN_DEVELOPMENT_GUIDE.md, ledmatrix-stocks/README.md, and .cursor/plugin_templates/QUICK_START.md. Removed the bullet and replaced it with a paragraph explaining the real pattern: paste onto display_manager.image directly, then update_display(). Includes the transparency-mask form. - Added the small_font/centered args to draw_text() since they're the ones that matter most for new plugin authors - Added draw_weather_icon since it's commonly used Cache Manager section - "delete(key): Remove cached value" — there's no delete() method on CacheManager. The real method is clear_cache(key=None) (also removes everything when called without args). Same bug as before. - Added get_cached_data_with_strategy and get_background_cached_data since contributors will hit these when working on sports plugins Plugin System Overview - "loaded from the plugins/ directory" — clarified that the default is plugin-repos/ (per config.template.json:130) with plugins/ as the dev fallback used by scripts/dev/dev_plugin_setup.sh Plugin Development Workflow - ./dev_plugin_setup.sh -> ./scripts/dev/dev_plugin_setup.sh (×2) - Manual setup step "Create directory in plugins//" -> plugin-repos// as the canonical location - "Use emulator: python run.py --emulator or ./run_emulator.sh" — the --emulator flag doesn't exist; ./run_emulator.sh isn't at root (it lives at scripts/dev/run_emulator.sh). Replaced with the real options: scripts/dev_server.py for dev preview, or EMULATOR=true python3 run.py for the full emulator path. Configuration Management - "Reference secrets via config_secrets key in main config" — this is the same fictional reference syntax I just fixed in .cursor/plugins_guide.md. Verified in src/config_manager.py:162-172 that secrets are deep-merged into the main config; there's no separate reference field. Replaced with a clear explanation of the deep-merge approach. Code Organization - "plugins//" -> the canonical location is plugin-repos// (or its dev-time symlink in plugins/) - "see plugins/hockey-scoreboard/ as reference" — the canonical source for example plugins is the ledmatrix-plugins repo. Updated the pointer. Co-Authored-By: Claude Opus 4.6 (1M context) --- .cursorrules | 60 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 46 insertions(+), 14 deletions(-) diff --git a/.cursorrules b/.cursorrules index 79d8abea..ae732017 100644 --- a/.cursorrules +++ b/.cursorrules @@ -2,7 +2,13 @@ ## Plugin System Overview -The LEDMatrix project uses a plugin-based architecture. All display functionality (except core calendar) is implemented as plugins that are dynamically loaded from the `plugins/` directory. +The LEDMatrix project uses a plugin-based architecture. All display +functionality (except core calendar) is implemented as plugins that are +dynamically loaded from the directory configured by +`plugin_system.plugins_directory` in `config.json` — the default is +`plugin-repos/` (per `config/config.template.json:130`), and the loader +also falls back to `plugins/` (used by `scripts/dev/dev_plugin_setup.sh` +for symlinks). ## Plugin Structure @@ -27,14 +33,15 @@ The LEDMatrix project uses a plugin-based architecture. All display functionalit **Option A: Use dev_plugin_setup.sh (Recommended)** ```bash # Link from GitHub -./dev_plugin_setup.sh link-github +./scripts/dev/dev_plugin_setup.sh link-github # Link local repository -./dev_plugin_setup.sh link +./scripts/dev/dev_plugin_setup.sh link ``` **Option B: Manual Setup** -1. Create directory in `plugins//` +1. Create directory in `plugin-repos//` (or `plugins//` + if you're using the dev fallback location) 2. Add `manifest.json` with required fields 3. Create `manager.py` with plugin class 4. Add `config_schema.json` for configuration @@ -63,7 +70,12 @@ Plugins are configured in `config/config.json`: ### 3. Testing Plugins **On Development Machine:** -- Use emulator: `python run.py --emulator` or `./run_emulator.sh` +- Run the dev preview server: `python3 scripts/dev_server.py` (then + open `http://localhost:5001`) — renders plugins in the browser + without running the full display loop +- Or run the full display in emulator mode: + `EMULATOR=true python3 run.py` (or `./scripts/dev/run_emulator.sh`). + There is no `--emulator` flag. - Test plugin loading: Check logs for plugin discovery and loading - Validate configuration: Ensure config matches `config_schema.json` @@ -75,15 +87,22 @@ Plugins are configured in `config/config.json`: ### 4. Plugin Development Best Practices **Code Organization:** -- Keep plugin code in `plugins//` +- Keep plugin code in `plugin-repos//` (or its dev-time + symlink in `plugins//`) - Use shared assets from `assets/` directory when possible -- Follow existing plugin patterns (see `plugins/hockey-scoreboard/` as reference) +- Follow existing plugin patterns — canonical sources live in the + [`ledmatrix-plugins`](https://github.com/ChuckBuilds/ledmatrix-plugins) + repo (`plugins/hockey-scoreboard/`, `plugins/football-scoreboard/`, + `plugins/clock-simple/`, etc.) - Place shared utilities in `src/common/` if reusable across plugins **Configuration Management:** - Use `config_schema.json` for validation -- Store secrets in `config/config_secrets.json` (not in main config) -- Reference secrets via `config_secrets` key in main config +- Store secrets in `config/config_secrets.json` under the same plugin + id namespace as the main config — they're deep-merged into the main + config at load time (`src/config_manager.py:162-172`), so plugin + code reads them directly from `config.get(...)` like any other key +- There is no separate `config_secrets` reference field - Validate all required fields in `validate_config()` **Error Handling:** @@ -138,18 +157,31 @@ Located in: `src/display_manager.py` **Key Methods:** - `clear()`: Clear the display -- `draw_text(text, x, y, color, font)`: Draw text -- `draw_image(image, x, y)`: Draw PIL Image -- `update_display()`: Update physical display +- `draw_text(text, x, y, color, font, small_font, centered)`: Draw text +- `update_display()`: Push the buffer to the physical display +- `draw_weather_icon(condition, x, y, size)`: Draw a weather icon - `width`, `height`: Display dimensions +**Image rendering**: there is no `draw_image()` helper. Paste directly +onto the underlying PIL Image: +```python +self.display_manager.image.paste(pil_image, (x, y)) +self.display_manager.update_display() +``` +For transparency, paste with a mask: `image.paste(rgba, (x, y), rgba)`. + ### Cache Manager Located in: `src/cache_manager.py` **Key Methods:** -- `get(key, max_age=None)`: Get cached value +- `get(key, max_age=300)`: Get cached value (returns None if missing/stale) - `set(key, value, ttl=None)`: Cache a value -- `delete(key)`: Remove cached value +- `clear_cache(key=None)`: Remove a cache entry, or all entries if `key` + is omitted. There is no `delete()` method. +- `get_cached_data_with_strategy(key, data_type)`: Cache get with + data-type-aware TTL strategy +- `get_background_cached_data(key, sport_key)`: Cache get for the + background-fetch service path ## Plugin Manifest Schema