Architecture decision records (ADRs)¶
Important decisions are recorded as short ADRs: context, decision, consequences.
ADR-0001: Docs as a duo — MkDocs Material + Sphinx¶
Context: BrainDeer needs a polished, media-rich user guide and in-depth developer documentation with an API reference.
Decision: user docs in MkDocs Material (
docs/), dev docs in Sphinx (sphinx/, MyST markdown, API via sphinx-autoapi). Deployed together: user docs at/, dev docs at/dev/. Both sides are written in Markdown.Consequences: two build systems in one GitHub Action; cross-links via absolute URLs. Drafts and review stay on GitHub (Markdown in the repo, PR review, edit pen on every page) — no external editorial tool needed.
ADR-0002: AutoAPI instead of autodoc¶
Context: Importing
brain_deerpulls PyQt5, VTK, and related native stacks. That makes headless/CI doc builds brittle and slow.Decision: generate the API reference with sphinx-autoapi (static parse of
src/brain_deer). Hand-written guides link into that tree via a curated API map by layer. Unity bridge sources are ignored; Blender bridge Python remains documented.Consequences: no need to install the full app stack for docs; docstrings must be valid ReST/MyST-friendly text (watch substitutions like
|V1|). Runtime import checks are not exercised by the API build.
ADR-0003: Plugin model — PluginBase, allowlist, widget split¶
Context: Extensions must appear in Plugin Studio without loading every folder under
plugins/and without mixing lifecycle code into Qt layouts.Decision: each plugin is
plugins/<id>/plugin.py+ optionalwidget.py, subclassingplugin_api.v1.PluginBase. Discovery is intersected with_BUNDLED_PLUGIN_ALLOWLISTinplugins_host/plugin_manager.py. Scaffold viabraindeer-new-plugin.Consequences: new plugins need an allowlist edit;
get_metadata()must stay pure for__new__probing; UI stays in the widget, host API via the facade.
ADR-0004: Event bus + command registry as integration surfaces¶
Context: UI panels, plugins, and scripts need to cooperate without importing each other’s private widgets (caller-name coupling).
Decision: cross-cutting notifications go through
application.events.bus.EventBus; user-facing actions are registered undercommands/and invoked through the command registry / palette.Consequences: prefer
register_event_handler/ commands over direct widget references; new features should extend these surfaces before adding ad-hoc callbacks between packages.