[GH-ISSUE #952] feat: plugin system — install, manage and convert OctoPrint plugins #658

Closed
opened 2026-05-06 12:31:43 +02:00 by BreizhHardware · 7 comments

Originally created by @Soopahfly on GitHub (Apr 12, 2026).
Original GitHub issue: https://github.com/maziggy/bambuddy/issues/952

Originally assigned to: @Soopahfly on GitHub.

Summary

I'd like to propose adding a first-class plugin system to Bambuddy. I've built a working implementation on my fork and would like to contribute it upstream.

Motivation

OctoPrint has a rich plugin ecosystem. Many users who migrate from OctoPrint to Bambuddy miss plugins like GCode visualisers, custom notifications, filament-change scripts, etc. A lightweight plugin system would let the community extend Bambuddy without requiring core changes for every feature.

What I've built

Plugin loader & base mixins

  • Plugins are Python packages in data/plugins/ — auto-discovered on startup
  • Supported mixins: StartupPlugin, ShutdownPlugin, EventHandlerPlugin, SettingsPlugin, AssetPlugin, SimpleApiPlugin
  • Plugin lifecycle events fire on print start/complete, archive creation, startup/shutdown

Plugin API (/api/v1/plugins)

  • List all plugins with metadata, enabled state, load status
  • Upload a .zip, detect type (Bambuddy native or OctoPrint), preview conversion, confirm install
  • Enable / disable (restart required)
  • Per-plugin settings (GET/PUT merged with defaults)
  • Static asset serving (/{key}/assets/{path}) with path-traversal protection
  • SimpleApiPlugin GET and command dispatch

OctoPrint plugin converter

  • AST-based detection: checks for import octoprint, __plugin_pythoncompat__, class inheritance
  • Maps StartupPlugin, SettingsPlugin, AssetPlugin, SimpleApiPlugin, EventHandlerPlugin 1:1
  • Stubs unsupported mixins (TemplatePlugin, BlueprintPlugin) with clear comments
  • Shows a preview of converted code before committing the install

Frontend

  • Plugins sidebar nav item
  • Plugin cards: name/version/author/description, Loaded/Restart/Disabled badges, enable toggle, settings editor
  • Upload modal with type detection, mixin support preview, and generated code diff
  • "Open Viewer" button for plugins that expose a static/index.html

Bundled example: PrettyGCode

Includes a conversion of OctoPrint-PrettyGCode as a reference plugin:

  • Full Three.js 3D GCode viewer
  • Layer highlight synced to Bambu layer_num via MQTT (byte-offset map built by parsing the GCode file)
  • Nozzle animation using synthetic GCode commands (Bambu doesn't expose serial echo, so we reconstruct it)
  • File picker from Bambuddy's library, printer selector with model-based bed sizes

Implementation notes

  • No breaking changes — the plugin system is entirely additive
  • docker-compose.yml gets a ./plugins:/app/data/plugins volume mount
  • PluginRecord DB table added via SQLAlchemy (existing init_db() path)
  • All plugin static assets served through the existing FastAPI layer

Questions for maintainers

  1. Is the data/plugins/ location acceptable, or would you prefer a separate PLUGINS_DIR env var?
  2. Should the OctoPrint converter live in core, or be a separate optional dependency?
  3. Are there CI/linting requirements I should be aware of for the AST-based converter?

Happy to adjust the implementation based on feedback before submitting the PR.

Originally created by @Soopahfly on GitHub (Apr 12, 2026). Original GitHub issue: https://github.com/maziggy/bambuddy/issues/952 Originally assigned to: @Soopahfly on GitHub. ## Summary I'd like to propose adding a first-class plugin system to Bambuddy. I've built a working implementation on my fork and would like to contribute it upstream. ## Motivation OctoPrint has a rich plugin ecosystem. Many users who migrate from OctoPrint to Bambuddy miss plugins like GCode visualisers, custom notifications, filament-change scripts, etc. A lightweight plugin system would let the community extend Bambuddy without requiring core changes for every feature. ## What I've built ### Plugin loader & base mixins - Plugins are Python packages in `data/plugins/` — auto-discovered on startup - Supported mixins: `StartupPlugin`, `ShutdownPlugin`, `EventHandlerPlugin`, `SettingsPlugin`, `AssetPlugin`, `SimpleApiPlugin` - Plugin lifecycle events fire on print start/complete, archive creation, startup/shutdown ### Plugin API (`/api/v1/plugins`) - List all plugins with metadata, enabled state, load status - Upload a `.zip`, detect type (Bambuddy native or OctoPrint), preview conversion, confirm install - Enable / disable (restart required) - Per-plugin settings (GET/PUT merged with defaults) - Static asset serving (`/{key}/assets/{path}`) with path-traversal protection - `SimpleApiPlugin` GET and command dispatch ### OctoPrint plugin converter - AST-based detection: checks for `import octoprint`, `__plugin_pythoncompat__`, class inheritance - Maps `StartupPlugin`, `SettingsPlugin`, `AssetPlugin`, `SimpleApiPlugin`, `EventHandlerPlugin` 1:1 - Stubs unsupported mixins (`TemplatePlugin`, `BlueprintPlugin`) with clear comments - Shows a preview of converted code before committing the install ### Frontend - **Plugins** sidebar nav item - Plugin cards: name/version/author/description, Loaded/Restart/Disabled badges, enable toggle, settings editor - Upload modal with type detection, mixin support preview, and generated code diff - "Open Viewer" button for plugins that expose a `static/index.html` ### Bundled example: PrettyGCode Includes a conversion of [OctoPrint-PrettyGCode](https://github.com/Soopahfly/OctoPrint-PrettyGCode) as a reference plugin: - Full Three.js 3D GCode viewer - Layer highlight synced to Bambu `layer_num` via MQTT (byte-offset map built by parsing the GCode file) - Nozzle animation using synthetic GCode commands (Bambu doesn't expose serial echo, so we reconstruct it) - File picker from Bambuddy's library, printer selector with model-based bed sizes ## Implementation notes - No breaking changes — the plugin system is entirely additive - `docker-compose.yml` gets a `./plugins:/app/data/plugins` volume mount - `PluginRecord` DB table added via SQLAlchemy (existing `init_db()` path) - All plugin static assets served through the existing FastAPI layer ## Questions for maintainers 1. Is the `data/plugins/` location acceptable, or would you prefer a separate `PLUGINS_DIR` env var? 2. Should the OctoPrint converter live in core, or be a separate optional dependency? 3. Are there CI/linting requirements I should be aware of for the AST-based converter? Happy to adjust the implementation based on feedback before submitting the PR.
BreizhHardware 2026-05-06 12:31:43 +02:00
Author
Owner

@maziggy commented on GitHub (Apr 12, 2026):

Thanks for the detailed writeup @Soopahfly — it's clear you've put a lot of thought and work into this. Before we go further, I want to raise some concerns so we can discuss them:

Security surface — Auto-discovering and executing arbitrary Python packages from a directory, combined with a ZIP upload endpoint that installs code, is a significant trust boundary. Every plugin would run with full backend privileges (DB, filesystem, network). How are you thinking about sandboxing or permission scoping? Is there any isolation between plugins and core?

OctoPrint converter maintenance — The AST-based converter is clever, but OctoPrint's plugin API is large and evolving. Stubbing unsupported mixins (TemplatePlugin, BlueprintPlugin) means many real-world OctoPrint plugins won't convert cleanly. Have you tested this against a range of popular OctoPrint plugins beyond PrettyGCode? I'm concerned about the long-tail maintenance burden of keeping compatibility with an ecosystem we don't control.

Timing — Core features are still in active development (auth/SSO, queue automation, database migration). A plugin system is a foundational change that touches DB schema, Docker config, frontend routing, static asset serving, and the startup path. Every future change would need to account for it. I'd want to make sure the core is more settled before committing to this kind of architecture.

Scope — Would it make sense to break this into smaller pieces? For example, the G-code viewer looks genuinely useful as a standalone feature. And a simpler event-hook system (without the full plugin loader and OctoPrint converter) could be a less risky starting point if there's community demand.

Curious to hear your thoughts on these points.

<!-- gh-comment-id:4231248897 --> @maziggy commented on GitHub (Apr 12, 2026): Thanks for the detailed writeup @Soopahfly — it's clear you've put a lot of thought and work into this. Before we go further, I want to raise some concerns so we can discuss them: **Security surface** — Auto-discovering and executing arbitrary Python packages from a directory, combined with a ZIP upload endpoint that installs code, is a significant trust boundary. Every plugin would run with full backend privileges (DB, filesystem, network). How are you thinking about sandboxing or permission scoping? Is there any isolation between plugins and core? **OctoPrint converter maintenance** — The AST-based converter is clever, but OctoPrint's plugin API is large and evolving. Stubbing unsupported mixins (TemplatePlugin, BlueprintPlugin) means many real-world OctoPrint plugins won't convert cleanly. Have you tested this against a range of popular OctoPrint plugins beyond PrettyGCode? I'm concerned about the long-tail maintenance burden of keeping compatibility with an ecosystem we don't control. **Timing** — Core features are still in active development (auth/SSO, queue automation, database migration). A plugin system is a foundational change that touches DB schema, Docker config, frontend routing, static asset serving, and the startup path. Every future change would need to account for it. I'd want to make sure the core is more settled before committing to this kind of architecture. **Scope** — Would it make sense to break this into smaller pieces? For example, the G-code viewer looks genuinely useful as a standalone feature. And a simpler event-hook system (without the full plugin loader and OctoPrint converter) could be a less risky starting point if there's community demand. Curious to hear your thoughts on these points.
Author
Owner

@Soopahfly commented on GitHub (Apr 12, 2026):

Hey, thanks for taking the time to go through it properly.

On the security side — yeah, you're right, there's no sandboxing. Plugins run with full backend privileges. The upload
is admin-only and nothing loads until you explicitly enable and restart, but that's about it. Worth documenting
clearly but I'm not going to pretend it's more than it is.

On the OctoPrint converter — I think I'm going to drop that completely. Honestly it only half-worked even on my own
plugin, and maintaining compatibility with an ecosystem we don't control isn't worth it. If there's ever a use case
for it, a standalone offline tool makes more sense than baking it into the backend.

On timing — totally fair, you know the roadmap better than I do. Happy to keep the plugin loader on my fork and come
back to it when things are more settled.

The GCode viewer though — would that be worth a separate PR as a native built-in? No plugin system needed, just a
viewer page that hooks into the library and printer APIs you already have. That feels like the most useful bit anyway.

So I'll close this one out. Let me know if a focused GCode viewer issue is something you'd be open to.

<!-- gh-comment-id:4231591104 --> @Soopahfly commented on GitHub (Apr 12, 2026): Hey, thanks for taking the time to go through it properly. On the security side — yeah, you're right, there's no sandboxing. Plugins run with full backend privileges. The upload is admin-only and nothing loads until you explicitly enable and restart, but that's about it. Worth documenting clearly but I'm not going to pretend it's more than it is. On the OctoPrint converter — I think I'm going to drop that completely. Honestly it only half-worked even on my own plugin, and maintaining compatibility with an ecosystem we don't control isn't worth it. If there's ever a use case for it, a standalone offline tool makes more sense than baking it into the backend. On timing — totally fair, you know the roadmap better than I do. Happy to keep the plugin loader on my fork and come back to it when things are more settled. The GCode viewer though — would that be worth a separate PR as a native built-in? No plugin system needed, just a viewer page that hooks into the library and printer APIs you already have. That feels like the most useful bit anyway. So I'll close this one out. Let me know if a focused GCode viewer issue is something you'd be open to.
Author
Owner

@maziggy commented on GitHub (Apr 12, 2026):

The GCode viewer though — would that be worth a separate PR as a native built-in? No plugin system needed, just a viewer page that hooks into the library and printer APIs you already have. That feels like the most useful bit anyway.

Yes, definitely. Replacing the existing (bad) gcode viewer is already on my list. So you could just open a PR for it. That would be ver nice!

<!-- gh-comment-id:4231664655 --> @maziggy commented on GitHub (Apr 12, 2026): >The GCode viewer though — would that be worth a separate PR as a native built-in? No plugin system needed, just a viewer page that hooks into the library and printer APIs you already have. That feels like the most useful bit anyway. Yes, definitely. Replacing the existing (bad) gcode viewer is already on my list. So you could just open a PR for it. That would be ver nice!
Author
Owner

@Soopahfly commented on GitHub (Apr 12, 2026):

The GCode viewer though — would that be worth a separate PR as a native built-in? No plugin system needed, just a viewer page that hooks into the library and printer APIs you already have. That feels like the most useful bit anyway.

Yes, definitely. Replacing the existing (bad) gcode viewer is already on my list. So you could just open a PR for it. That would be ver nice!

Image Image

How does that look.

There's just an option on the left navbar for gcode viewer, and in there you can load a pre-sliced gcode file.

<!-- gh-comment-id:4231867147 --> @Soopahfly commented on GitHub (Apr 12, 2026): > > The GCode viewer though — would that be worth a separate PR as a native built-in? No plugin system needed, just a viewer page that hooks into the library and printer APIs you already have. That feels like the most useful bit anyway. > > Yes, definitely. Replacing the existing (bad) gcode viewer is already on my list. So you could just open a PR for it. That would be ver nice! <img width="941" height="496" alt="Image" src="https://github.com/user-attachments/assets/3e9a7657-d5ad-4b72-9f7f-8649e67659da" /> <img width="950" height="490" alt="Image" src="https://github.com/user-attachments/assets/973b7609-5f92-4460-869e-f693f35eb75f" /> How does that look. There's just an option on the left navbar for gcode viewer, and in there you can load a pre-sliced gcode file.
Author
Owner

@Soopahfly commented on GitHub (Apr 12, 2026):

I realised it's loading the gcode viewer as a new tab instead of in the main pane. Just sorting that now.

<!-- gh-comment-id:4231880881 --> @Soopahfly commented on GitHub (Apr 12, 2026): I realised it's loading the gcode viewer as a new tab instead of in the main pane. Just sorting that now.
Author
Owner

@Soopahfly commented on GitHub (Apr 12, 2026):

Fixed that now.

<!-- gh-comment-id:4232774374 --> @Soopahfly commented on GitHub (Apr 12, 2026): Fixed that now.
Author
Owner

@maziggy commented on GitHub (Apr 13, 2026):

Open a PR and I'll check more detailed. Thanks.

<!-- gh-comment-id:4234234777 --> @maziggy commented on GitHub (Apr 13, 2026): Open a PR and I'll check more detailed. Thanks.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/bambuddy#658
No description provided.