mirror of
https://github.com/got-feedBack/feedBack.git
synced 2026-09-13 16:30:09 +00:00
docs: extract plugin contracts into modular docs and slim CLAUDE.md
CLAUDE.md had grown to 545 lines / 50 KB — most of it plugin-author
content that other AI tools (Cursor, Copilot, Codex, Aider) and humans
without AI never reach. Extract the plugin surface into 10 focused
docs and a JSON Schema for plugin.json, then slim CLAUDE.md to a
156-line navigable index.
New docs (~999 lines total, all self-contained):
docs/PLUGIN_AUTHORING.md — entry point and quickstart
docs/plugin-manifest.md — plugin.json field reference
docs/plugin-visualization-contracts.md — setRenderer / overlay / note-state
docs/plugin-audio-mixer.md — fader registration
docs/plugin-logging.md — context["log"] + env vars
docs/plugin-diagnostics.md — server_files / callable
docs/plugin-keyboard-shortcuts.md — registerShortcut + scopes
docs/plugin-sibling-imports.md — load_sibling pattern
docs/websocket-protocol.md — /ws/highway message reference
docs/testing-plugins.md — pytest fixtures + Playwright
schema/plugin.schema.json — Draft 2020-12 schema for
plugin.json; license enum
mirrors CONTRIBUTING's curated
allowlist. Backs CI validation
and the plugin-validate skill.
CLAUDE.md slim (581 lines changed, -485):
- Removed ~300 lines of plugin-author prose (now in docs/).
- Kept architecture quick reference, running the app, testing,
git workflow, versioning, song formats, frontend/backend
conventions, plugin authoring INDEX (table → docs/), first-hour
pitfalls, "For AI agents" footer.
- Anchor stubs preserved next to the new index entries so deep
links from specs/001-slopsmith-platform/analyze.md still resolve.
Verification:
python -c "import json,glob,jsonschema; s=json.load(open('schema/plugin.schema.json')); [jsonschema.validate(json.load(open(p)), s) for p in sorted(glob.glob('plugins/*/plugin.json'))]"
# ok — validates highway_3d, app_tour_library, app_tour_settings
Signed-off-by: Miguel_LZPF <mgcdreamer@gmail.com>
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
# Plugin logging
|
||||
|
||||
Use `context["log"]` for all backend plugin output. It is a stdlib `logging.Logger` namespaced to `slopsmith.plugin.<id>`, pre-configured with the app-wide level, format (including JSON mode), and correlation IDs. **Never use `print()`** — it bypasses correlation context and log rotation.
|
||||
|
||||
## Backend usage
|
||||
|
||||
```python
|
||||
def setup(app, context):
|
||||
log = context["log"]
|
||||
log.info("plugin ready")
|
||||
log.warning("optional dependency %r not found, feature disabled", dep)
|
||||
try:
|
||||
risky_init()
|
||||
except Exception:
|
||||
log.exception("unhandled error during setup") # auto-captures traceback
|
||||
```
|
||||
|
||||
## CLI entry-point fallback
|
||||
|
||||
For helper scripts that also run as `__main__`, add a stdlib fallback so the logger works without the server pipeline:
|
||||
|
||||
```python
|
||||
if __name__ == "__main__":
|
||||
import logging
|
||||
logging.basicConfig(level=logging.INFO, format="%(levelname)s %(message)s")
|
||||
```
|
||||
|
||||
## How it's wired
|
||||
|
||||
The plugin loader assigns each plugin a logger before calling `setup()`:
|
||||
|
||||
```python
|
||||
context["log"] = logging.getLogger(f"slopsmith.plugin.{plugin_id}")
|
||||
```
|
||||
|
||||
That logger inherits from the root `slopsmith` logger, which is configured by `logging_setup.configure_logging()` (called from `main.py` before uvicorn boots). It respects:
|
||||
|
||||
- **`LOG_LEVEL`** — `DEBUG | INFO | WARNING | ERROR` (default `INFO`)
|
||||
- **`LOG_FORMAT`** — `json | text` (default `text` — coloured console)
|
||||
- **`LOG_FILE`** — optional path for a persistent log file (e.g. `/config/slopsmith.log`)
|
||||
- **Correlation IDs** — each HTTP request carries `X-Request-ID`; structlog injects it into every log line during that request's lifetime. WebSocket sessions get their own `ws_conn_id` contextvar bound at accept time.
|
||||
|
||||
## Verifying
|
||||
|
||||
Look for your plugin's logger name in the console output:
|
||||
|
||||
```
|
||||
INFO slopsmith.plugin.my_plugin: plugin ready
|
||||
```
|
||||
|
||||
Switch `LOG_FORMAT=json` to see structured output:
|
||||
|
||||
```json
|
||||
{"timestamp": "...", "level": "info", "logger": "slopsmith.plugin.my_plugin", "event": "plugin ready", "request_id": "..."}
|
||||
```
|
||||
|
||||
## Common mistakes
|
||||
|
||||
- **Using `print()` inside `setup()` or request handlers.** `print()` goes to stdout, bypasses level filtering, log rotation, JSON formatting, and correlation IDs. Audit your plugin with `grep -nR 'print(' plugins/<id>/`.
|
||||
- **Creating a new logger with `logging.getLogger("my_plugin")`.** This creates an unparented logger that doesn't inherit slopsmith's configuration. Always use the one passed via `context["log"]`.
|
||||
- **Logging at `INFO` in hot paths.** Default `LOG_LEVEL` is `INFO`, so `log.info(...)` inside a per-frame or per-message loop floods output. Use `log.debug(...)` for hot-path tracing.
|
||||
|
||||
## Related
|
||||
|
||||
- [PLUGIN_AUTHORING.md](PLUGIN_AUTHORING.md) — guide index
|
||||
- [plugin-manifest.md](plugin-manifest.md) — the `routes.py` / `setup(app, context)` contract
|
||||
- [plugin-diagnostics.md](plugin-diagnostics.md) — capturing logs into the diagnostics bundle
|
||||
Reference in New Issue
Block a user