# Plugins > **Status:** Active > **Last updated:** 2026-07-05 ## Overview Client-only plugin runtime with server-stored **metadata** (install requirements, event definitions) and Electron-local **plugin data** persistence. Plugins extend chat slash commands, toolbar actions, DOM mounts, and a P2P message bus — they never execute on the signaling server. ## Responsibilities | Layer | Owns | |-------|------| | Product client (`plugins` domain) | Manifest validation, load order, `PluginHostService`, UI registry, store installs | | Electron | Local manifest discovery (`plugins/`, `plugin-bundles/`), `plugin_data` CQRS table, path jail | | Signaling server | Requirement/event metadata REST + `plugin_event` WebSocket broadcast; **no** plugin code execution | | P2P data channel | `plugin-message-bus` events (ignored by chat reducers) | Server plugin **data** HTTP routes return **410 Gone** (`PLUGIN_DATA_DISABLED`). ## Server REST (`/api/servers/:serverId/plugins`) | Method | Path | Auth | |--------|------|------| | GET | `/` | Public (metadata snapshot) | | PUT | `/:pluginId/requirement` | Bearer | | DELETE | `/:pluginId/requirement` | Bearer | | PUT | `/:pluginId/events/:eventName` | Bearer | | DELETE | `/:pluginId/events/:eventName` | Bearer | | GET/PUT/DELETE | `/:pluginId/data/*` | 410 (disabled) | ## WebSocket | type | Direction | Purpose | |------|-----------|---------| | `plugin_requirements` | Server → client | Snapshot after `join_server` / `view_server` | | `plugin_event` | Client → server → room | Validated broadcast of plugin events | | `plugin_error` | Server → client | Validation failure | See [signaling.md](signaling.md). ## Manifest scopes - `scope: "client"` — global desktop/browser plugins (Settings → Client plugins). - `scope: "server"` — per chat-server plugins; join may block until user consents to required plugins. Store source manifests support HTTPS `bundle`/`bundleUrl` with optional SHA-256 `integrity` verification before `import()`. ## Electron IPC / storage - `list-local-plugin-manifests`, `get-local-plugins-path`, `grant-plugin-read-root` - Plugin preferences and `api.clientData` / `api.serverData` → `plugin_data` table (user-scoped) - Cached bundles: `plugin-bundles///main.js` ## Client API surface (summary) Plugins receive `TojuClientPluginApi`: `commands`, `ui.mountElement`, `ui.registerToolbarAction`, `messageBus`, `messages.setTyping`, `context.getCurrent()`, `clientData`/`serverData` async storage. ## Related - [signaling.md](signaling.md) — `plugin_event`, `plugin_requirements` - [server-directory.md](server-directory.md) — server-scoped install on join - [authentication.md](authentication.md) — bearer on metadata mutations - Domain README: [`toju-app/src/app/domains/plugins/README.md`](../../toju-app/src/app/domains/plugins/README.md) ## Changelog | Date | Change | |------|--------| | 2026-07-05 | Initial cross-context plugin contract |