Plugin system

Plugins extend the desktop agent. One manifest — open-bot.plugin.json — describes everything; GitHub repos hold the code and releases; the marketplace is the searchable index.

Manifest

Schema: packages/plugin-kit/schema/open-bot.plugin.schema.json (seeded into desktops and referenced by ob-plugin new scaffolds; kept in sync with validatePluginManifest).

Key fields:

FieldPurpose
files[]{name, source, exec} payload files fetched from the reviewed release tarball at install; text files only.
setup.commands / setup.uninstallRoot commands run at install (and after every desktop recreate via onDesktopReady → reapplyPluginSetup; the update recycle waits for that re-run to finish); uninstall runs best-effort. Logged to ~/.open-bot/plugin-init/<id>.log; shown in the consent dialog; security-reviewed. Must be idempotent — they re-run on an already-set-up desktop, so every step has to succeed twice (pipe grep/diff style exits through || true, guard installs with test).
opencode.agentsRegisters new agent workers (deep-merged into opencode.json; reserved names rejected). Helper sessions must use the worker: title prefix so the dashboard hides them.
opencode.agentToolsPatches tool globs on existing agents, e.g. {"build": {"blender_*": false}}.
opencode.agentsMdStanding instructions injected next to AGENTS.md (file under ~/.config/open-bot/agents-md/).
configs[]Typed settings: string (default), bool, number, enum + options[], secret. Validated/coerced by validateConfigValue; unknown keys rejected; upgrades prune dropped keys. Secrets land in ~/.config/open-bot/plugin-<id>.json.
hooks[]Max 8 {event: "session.idle"|"thread.created", message} prompts run in hidden worker: plugin-<id> <event> sessions. Loop-guarded: worker/cron sessions never re-trigger; 20 runs/day per plugin; 2 concurrent per event.
permissions.notificationstrue unlocks ob-plugin notify → POST /api/plugins/notice (30/hour) → dashboard toast + native notification.
versionSemver X.Y.Z[-prerelease] or dev tag (beta-1).

Dashboard pages

A plugin can ship a live dashboard — a view in the workspace drawer's Dashboards list where the user picks a plugin page and interacts with live data (stock lists, trackers, admin panels).

FieldPurpose
dashboard.pages.entryA files[] payload (Bun HTTP server) run by the control plane at install, enable, and after every desktop restart. Env: OPEN_BOT_PAGE_PORT, OPEN_BOT_PAGE_TOKEN, OPEN_BOT_PLUGIN_ID; settings/vault arrive via ~/.config/open-bot/plugin-<id>.json. GET /healthz recommended (any response counts as up).
dashboard.tabs[].kind: "app"The server's full UI, proxied same-origin under /api/pages/<pluginId>/ — relative fetches hit the plugin server; SSE and WebSockets pass through. Optional path (default /).
dashboard.tabs[].kind: "page" + dataUrl / pollSeconds (5-3600)The dashboard polls the plugin server for JSON and feeds it to declarative cards ($.path bindings). No HTML needed for read-only views.

The proxy strips cookies/auth toward the plugin and injects x-open-bot-page-token; ports come from a dedicated range (4740-4719-style, per-plugin deterministic). Upgrades and settings changes restart the server so it observes new config; disable/uninstall stop it.

Install surfaces

  • Tools land in /usr/local/bin/ob-plugin-<id>-*; apply-plugin-auth.sh writes the vault config.
  • The install log on the installed_plugins row reverses everything on uninstall.
  • Disable is deep: pauses cron, unloads OpenViking skills, drops vault config + opencode surfaces; enable restores from the stored manifest snapshot.
  • Failed root setup shows “setup failed — retry” on the Plugins page (POST /api/plugins/installed/:id/setup).

Persistence across desktop recreates

A desktop update (or any sleep/start cycle that recreates the container) wipes the container filesystem except the /home and /usr/local volumes. What survives without any re-run:

  • plugin tools and payload files (/usr/local/bin/ob-plugin-<id>-*)
  • vault config (~/.config/open-bot/plugin-<id>.json), agentsMd files, patched opencode.json surfaces, and anything else under /home/agent

What does not survive: anything a setup command installed into the container layer (apt packages, /venv, etc.). The boot re-apply re-runs setup.commands right after the container starts — it is what restores them, so keep the commands idempotent and expect a freshly recreated desktop to need a few minutes before root-installed dependencies are back.

Updates

  • installed_plugins.latest_version refreshes from the marketplace (throttled, on GET /api/plugins/installed).
  • ob-plugin outdated / update; dashboard “update to v…” button.
  • app_settings.plugin_auto_update: off (default) or stable (auto-installs newer approved stables).
  • Install policy app_settings.plugin_install_policy: manual (default, confirm dialog) or auto (also installs pending-review plugins).

Local development

ob-plugin install --path <plugin-root>

No publish needed; Re-install re-reads the path; Remove uninstalls. Schema changes need bun run db:generate and an image rebuild for existing desktops.

setup.commands run as root. Install policy auto also installs pending-review plugins — use it only on trusted instances.