Files
cinny/docs/handoff/features/plugins/HANDOFF.md
Max Litruv Boonzaayer e058165830 feat: upgrade toolchain and soften sync recovery after network blips
Bump Vite 8, matrix-js-sdk, and related deps; fix immer/vanilla-extract imports for new majors. Replace blocking sync error dialog with background recovery on wake/offline, and disable Vite auto-open in dev. Add feature handoff documentation index.
2026-07-09 01:55:09 +10:00

3.9 KiB

Plugin system — handoff

Summary

Paarrot extends the Matrix client with JavaScript plugins loaded from disk or the marketplace. Plugins can register slash commands, inject UI buttons in 11 locations, hook Matrix events, register themes, and run background tasks. The runtime is @paarrot/plugin-manager; the app wires slots in settings, nav, composer, and room UI.

User-facing behavior

  • Settings → Plugins: Installed, Marketplace, enable/disable, uninstall
  • Plugins live in OS-specific dirs (%APPDATA%\paarrot\plugins\, ~/.config/Paarrot/plugins/, etc.)
  • Marketplace pulls from Plugin Directory JSON index

Architecture

Plugin folder (index.js + plugin-metadata.json)
  → PluginLoader (reads, validates, enables)
    → @paarrot/plugin-manager (lifecycle, API surface)
      → PluginAPI.ts (app-specific bindings: Matrix client, navigate, notifications)
        → UI slots: PluginNavSlot, PluginButtonSlot, PluginSidebarSlot, ...

Key files

Path Role
cinny/src/app/features/settings/plugins/PluginLoader.tsx Load/enable/disable plugins
cinny/src/app/features/settings/plugins/PluginAPI.ts Re-exports plugin-manager + app hooks
cinny/src/app/features/settings/plugins/Plugins.tsx Settings UI (installed + marketplace)
cinny/src/app/features/settings/plugins/PluginButtonSlot.tsx Icon button injection
cinny/src/app/features/settings/plugins/PluginNavSlot.tsx Nav row injection
cinny/src/app/features/settings/plugins/PluginSidebarSlot.tsx Sidebar icon injection
cinny/src/app/features/settings/plugins/types.ts Local types
cinny/src/app/features/settings/plugins/PLUGIN_DEVELOPMENT.md Author-facing dev guide
example-plugin/ Reference plugin at repo root
cinny/docs/PLUGIN_*.md API reference docs

Data model

  • Plugin metadata: plugin-metadata.json per plugin (id, version, permissions, paarrot.utils deps)
  • Enabled state: persisted via plugin-manager (Electron userData)
  • No Matrix events for plugins themselves

UI locations (UILocation)

channel-list, home-section, direct-messages, sidebar-actions, text-composer-toolbar, composer-actions, room-header, room-menu, message-actions, user-menu, search-notification-section

Dependencies

  • @paarrot/plugin-manager (npm)
  • Electron fs / IPC for plugin install paths
  • GitHub raw URLs for marketplace index (PluginAPI.ts)

Integration points

  • Matrix client: exposed to plugins for send/receive
  • Local API: separate from plugins; plugins do not use HTTP API by default
  • Settings: plugin tabs via PluginTab
  • All major UI surfaces: search codebase for PluginButtonSlot / PluginNavSlot usages

Testing

Manual

  1. Copy example-plugin/ to plugins directory.
  2. Enable in Settings → Plugins.
  3. Verify slash command and injected button appear.
  4. Disable plugin; verify UI cleans up.

Automated

  • None dedicated; validate via example-plugin manually

Known issues & gotchas

  • Plugin API version must match @paarrot/plugin-manager expectations
  • ctx.require("other-plugin-id") for inter-plugin deps
  • Marketplace cache-bust query param on index fetch
  • Plugin dev guide lives inside src/ — consider linking from handoff only

Future work

  • Sandboxing / permission prompts per capability
  • Hot reload without app restart
  • Signed plugin packages

Add your extra things here

  • Marketplace base: https://raw.githubusercontent.com/Paarrot/Plugin-Directory/refs/heads/main/plugins/
  • 11 UI injection points — see README plugin table in repo root