Plugin authoring
Layout, manifest, and client entry.
A plugin is a directory under plugins/<id>/ with a harmony.plugin.json manifest at its root. The
id is the directory name.
plugins/my.plugin/
harmony.plugin.json
client/ → clientEntry (bundled into clients)
server/ → optional server module
worker/ → optional worker moduleStart from the sample:
plugins/harmony.sample.embed-notes/Manifest
harmony.plugin.json declares the id, version, and which entrypoints exist. Keep the id stable — it
is the key used by the registry, the CLI (harmony plugins <id> …), and the install path under
$HARMONY_HOME/plugins/.
Entrypoints
| Field | Consumed by | Notes |
|---|---|---|
clientEntry | Web / mobile / desktop | Loaded same-origin, or via the origin allowlist |
| Server module | Main server | Registered during server start |
| Worker module | Worker | Only runs where a worker dials in |
Build client output into the plugin's dist/, then stage it:
bun run plugins:buildThat copies each dist/client.js into apps/web/public/plugins/<id>/client.js, which is where
clients look for it.
First-party clients in this repo
A client/ folder in a monorepo plugin is bundled by the web app from source, so it may reach the
host through two doors: the web API client barrel (apps/web/src/lib/api) and the shared UI package
(@harmony/ui). Nothing deeper inside apps/web/src — those modules are free to move, the barrel
and the package entry are not.
Related
- Plugins for the trust model.
- Storybook covers the plugin host surface under Harmony/Plugins/Host.