--- name: plugins-marchat description: >- Develops and maintains marchat plugins: SDK, host IPC, manager install path, store downloads, and Ed25519 licenses. Use when editing plugin/, plugin commands, or plugin_state.json behavior. paths: - "plugin/**" - "cmd/license/**" --- # Plugins (marchat) JSON IPC over stdin/stdout. Packages: `plugin/sdk`, `plugin/host`, `plugin/manager`, `plugin/store`, `plugin/license`. ## SDK (`plugin/sdk`) - Separate `go.mod`; root `go test ./...` does **not** run SDK tests. - Stdio loop: `RunIO` / `HandlePluginRequest` (`stdio_test.go`). - Run: `cd plugin/sdk && go test ./...` ## Host - `StartPlugin` / `StopPlugin`; `StopPlugin` waits for stdout/stderr reader goroutines before niling pipes (race-safe disable/enable). - Bounded plugin chat fan-out queue (`plugin/host/outbound_test.go`). - Serialized stdin writes via `stdinMu` so fan-out and `ExecuteCommand` cannot interleave JSON lines. ## Manager - State in `plugin_state.json` under server data directory. - Install: SHA-256 checksum, size limits, zip-slip checks (`validateArchiveEntryName`, `filepath.IsLocal`, `os.OpenRoot` scoped writes), staging rollback, execute bit on binary by exact name. - `file://` URLs: `plugin/fileurl` (Linux/Windows). - Non-admin users may run chat commands when manifest `AdminOnly: false`. ## Licenses - Ed25519 signing/validation (`plugin/license/`, `cmd/license`). - Cache entries re-signature-checked; plugin name must match cache key. - Separate from chat E2E crypto. ## Server integration - `server/plugin_commands.go` dispatches to manager. - Hub stays off plugin IPC for core routing; plugin messages use bounded fan-out. - Plugin `"message"` and `"command_response"` bodies are broadcast only when `content` is within the chat cap (`pluginContentWithinLimit` in `Hub.Run`). Oversized plugin chat is logged and dropped. User chat over the cap never reaches plugins because `dispatchInbound` rejects it first. ## Testing - `plugin/integration_test.go`, `manager_lifecycle_test.go`, `plugin_lifecycle_test.go` (built minimal plugin). - CI runs nested module fmt and govulncheck (see `go.yml`). ## Docs - `PLUGIN_ECOSYSTEM.md`, `plugin/README.md` for author-facing detail.