Plugin End-to-End Example

The maintained Notes example shows all three plugin surfaces in one package. It uses monorepo workspace: and catalog: dependencies. Use it inside the Sero monorepo unless you port its complete manifest to published dependencies:

Use this index to find the smallest relevant example.

For an external repository, use the maintained Kanban starter and its setup guide.

TaskFile
Define the Pi, app, and plugin manifestspackage.json
Set runtime ABI 2 and required host capabilitiespackage.json
Define JSON-serialisable state and defaultsshared/types.ts
Register a tool, command, and CLI metadataextension/index.ts
Read and write state from the React UIui/NotesApp.tsx
Call a plugin tool from the UIui/NotesApp.tsx
Create and clean up long-running behaviorruntime/index.ts
Contribute a static Dashboard widgetpackage.json and ui/widgets/NotesWidget.tsx
Register a widget for the renderer sessionui/NotesApp.tsx
Expose the app and widget through Module Federationvite.config.ts
Isolate plugin CSSui/styles.css and vite.config.ts

Module Federation checks

The manifest uses component names without ./. The Vite exposes map uses keys with ./:

manifest component: NotesApp
Vite exposed key:  ./NotesApp

NotesApp.tsx and NotesWidget.tsx each have a default React component export. Each directly exposed entry also imports styles.css. The Vite configuration uses base: './' for production and seroPluginCssScope() after Tailwind.

Select only the parts that you need

For UI and extension only, remove runtime/, the runtime manifest field, the appRuntime.background capability, and runtime typecheck entries. For an extension-only plugin, also remove ui/, vite.config.ts, app UI fields, widgets and other contributions, Module Federation exposes, and UI build or typecheck entries.

Follow Plugin Quickstart for the complete first journey. Use Plugin Extension Points for the contribution schema and lifecycle rules.