Plugin Overview
A FengYu plugin extends the host with new UI and backend capability while staying strictly isolated: its code never runs inside the host Spring context, and its UI never shares the host's DOM tree. Every plugin ships as a single .fyp package, and the host supervises its lifecycle from install to uninstall.
What a plugin is
A plugin is a .fyp package — a zip archive with three parts:
| Path | Contents |
|---|---|
manifest.json | Metadata, permissions, AI tools, and worker method schemas |
ui/ | The micro-frontend assets (entry HTML + JS), served under /plugin-runtime/{id}/** |
backend/worker.jar | The worker executable, spawned as its own OS process |
The UI runs in a sandboxed iframe and talks to the host through a postMessage bridge provided by @infinia/plugin-sdk. The backend is an out-of-process worker that speaks JSON-RPC 2.0 over stdio. A worker crash or hang cannot take down the host, and a worker cannot reach into host beans or the JPA session.
Official vs third-party
Two sources of plugins:
- Official — built by the FengYu team, declared with
"official": truein the manifest, and seeded into every fresh install by theOfficialPluginSeeder(which verifies a SHA-256 sidecar before installing). The shipped set includesfan.summer.markdown,fan.summer.excel,fan.summer.email, andfan.summer.offlinepython. (Browser automation is now a host-embedded backend capability, not a plugin — see Browser Capability.) - Third-party — any
.fyparchive installed by the user through the marketplace or an upload. TheirsourceisTHIRD_PARTY.
The descriptor exposes this as the source field — OFFICIAL or THIRD_PARTY — on every InstalledPluginDescriptor returned by GET /api/plugin-runtime.
Identity is reserved, not self-declared. The
fan.summer.*namespace and theofficial: trueflag are host-trusted and can only be set by the trusted seeder path. A package installed via an upload or the marketplace (an untrusted path) that declares either is rejected — it cannot claim to be official or squat an official id. This closes the impersonation hole; full asymmetric signature verification (a published key signing each.fyp) is a tracked follow-up.
Each official plugin is documented in depth: Markdown, Excel, Email Center, Offline Python. The built-in Browser Capability is documented separately — it is not a plugin.
Lifecycle
A plugin moves through these states under control of the host's PluginProcessManager and PluginPackageService:
install ──► enabled ──► invoked (UI + worker RPC) ──► disabled ──► uninstalled
│ │ │
└─ upload .fyp via marketplace └─ DELETE /api/plugin-market/{id}- Install — a
.fypis uploaded via the marketplace; its manifest is parsed and stored. - Enable —
PATCH /api/plugin-market/{id}/enabled {enabled:true}; the worker process is spawned lazily on first invoke. - Invoke — the UI loads in its iframe; its worker calls (made through the generated typed client, which wraps
FengYuClient.invoke) are forwarded by the host as JSON-RPC to the worker. See Worker (JSON-RPC). - Disable —
PATCH .../enabled {enabled:false}; the host stops the worker process immediately. - Uninstall —
DELETE /api/plugin-market/{id}; the plugin is removed from the catalog and its process stopped.
The source field
Every installed descriptor carries a source discriminator so the UI can distinguish bundled plugins from user-installed ones:
| Value | Meaning |
|---|---|
OFFICIAL | Seeded from the built-in official set (official: true in manifest) |
THIRD_PARTY | Installed by the user from a .fyp archive |
source is read-only — it is derived from the manifest's official flag at install time and never mutated by the enable/disable cycle.
Next steps
- Getting Started — scaffold a plugin with
fengyu init. - Manifest — the full
manifest.jsonfield reference. - Architecture: Plugin System — how the host mounts and supervises plugins.