Plugin development
A Marginalia plugin (the user interface calls them extensions) is an OSGi bundle - a JAR with a few extra manifest headers - that Marginalia loads at runtime, without a restart. A plugin can add menu items, tabs, panels and settings to the user interface, keep its own data on books, story parts, lorebooks and user settings, call the model, and take part in generation.
This part of the developer guide explains how plugins work and how to write one. It assumes you can build Marginalia from source (Building from source) and know a little Vaadin Flow (User interface).
How a plugin plugs in
flowchart LR
subgraph Bundle["Plugin JAR (OSGi bundle)"]
Act["BundleActivator"] -->|registers| Ext["MarginaliaExtension"]
Ext --> Dec["ExtensionDecorators"]
Ext --> Lis["generation listeners"]
end
subgraph App["Marginalia"]
Osgi["OsgiService<br/>(Apache Felix)"]
ES["ExtensionService"]
UI["@Extendable UI classes<br/>(instrumented)"]
Gen["StoryGenerationService"]
Ent["entities<br/>attributes JSON"]
end
Osgi -->|onExtensionLoad| Ext
Dec -->|registerDecorator| ES
UI -->|method enter / leave| ES
ES -->|onMethodEnter / onMethodLeave| Dec
Lis -->|addEventListener| Gen
Dec -.->|read / write| EntThere is no plugin API in the usual sense - no list of extension points with stable signatures. Instead, a plugin gets three general mechanisms and the whole application to use them on:
Extending the UI puts the first three together: adding components, settings panels, threads and cleaning up on unload. Generation events shows how a plugin changes the prompt sent to the model, on the bundled Author's Note. Example plugin builds a small plugin from scratch and walks through the bundled Chapter Marker and Author's Note.
Plugins are tied to one version of Marginalia
Hooks are attached by class and method name and read local variables and fields by name. Renaming a method or a variable in the application silently disables the part of a plugin that used it (a warning is logged). Build plugins from the same source tree as the application they run in, and test them after every update. Marginalia itself verifies the decorators of an extension before it starts it and refuses ones that ask for classes, methods, arguments, locals or fields that don't exist.
The bundled plugins
The five plugins in marginalia/plugins/ are complete, working examples. Each is a separate Maven project.
Users install them as described in Managing extensions.
Reading order
- Plugin basics - project layout, the activator and the extension, building and loading.
- Example plugin - build one, load it, see it work.
- @Extendable hooks - the decorator API in detail and its limits.
- Extended attributes - storing data.
- Extending the UI - patterns for menus, tabs and settings, threads and unloading.
- Generation events - changing the prompt and the answer during generation.