# 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](https://github.com/Paarrot/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

## Related docs

- [PLUGINS.md](../../PLUGINS.md)
- [PLUGIN_API.md](../../PLUGIN_API.md)
- [PLUGIN_BUTTON_API.md](../../PLUGIN_BUTTON_API.md)
- [PLUGIN_SYSTEM_IMPLEMENTATION.md](../../PLUGIN_SYSTEM_IMPLEMENTATION.md)
- [PLUGIN_DEVELOPMENT.md](../../../../src/app/features/settings/plugins/PLUGIN_DEVELOPMENT.md)

## 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
