Desktop Plugin Conversion (agent plugin → desktop surface)
How to turn an existing agent plugin (Python + plugin.yaml in
~/.hermes/plugins/) into a Hermes Desktop surface (pane, page,
statusbar chip), or audit a plugin inventory for which ones are worth
converting. Companion to the authoring skill hermes-desktop-plugins
(which covers writing a desktop plugin from scratch); this skill covers the
conversion path: what's bridgeable, what to check before proposing, and
the rules that prevent reinventing wheels.
The two-plugin-systems distinction (state it first)
- Agent plugins —
~/.hermes/plugins/<name>/plugin.yaml, Python. Add
tools/hooks/backends. No UI, loaded by the agent runtime.
- Desktop plugins —
~/.hermes/desktop-plugins/<name>/plugin.js, single
plain ESM file. Add UI only. Loaded by the desktop app, hot-reloaded on
save. Folder name MUST equal plugin id.
The bridge (how conversion actually works)
ctx.rest / ctx.socket on the desktop side reaches a FastAPI backend at
/api/plugins/<id>/. That backend lives in a dashboard/ subfolder of an
AGENT plugin:
~/.hermes/plugins/<id>/dashboard/
├── manifest.json # { "name": "<id>", "api": "plugin_api.py" }
└── plugin_api.py # exports router = APIRouter()
Then the desktop plugin calls ctx.rest('/board') → GET /api/plugins/<id>/board. This is the exact pattern the bundled Kanban plugin
uses (apps/desktop/src/plugins/kanban/ → plugins/kanban/dashboard/).
Security gate: the Python backend imports only when the plugin is in
plugins.enabled in config.yaml — a NEW wrapper plugin must be added to
that allow-list, and the desktop-side toggle alone does NOT import Python.
Audit signals (which plugins are worth converting)
- Plugin exposes data worth seeing — a gallery, history DB, cost ledger,
DAG, transcript store — or already ships a web console/UI to adapt.
provides_tools rich in artifacts (images, transcripts, graph nodes).
Pure-behavior hooks (ponytail-style mode, katana-style scanning) are at
best statusbar-chip + palette-command material, not full pages.
kind: backend or kind: standalone with a real store beats pure-hook
plugins.
Rules learned the hard way
- Check what the desktop app ALREADY ships before proposing a
board/gallery. The app bundles a complete Kanban plugin —
/kanban page,
sidebar nav, statusbar running/ready count, ⌘⌥N new-task keybind —
defaultEnabled: false (off by default, flip in Settings → Plugins).
"Kanban visual" = enable it, never rebuild it.
- Mirror/LAN HTTP plugins are NOT desktop candidates.
kanban-api
(:8643) and session-api (:8644) are HermesMirror bridges for a Pi over
the LAN. On desktop, read the same data via gateway RPC (host.request)
or a dashboard/ backend — never duplicate the HTTP hop.
- Do NOT add
dashboard/ inside a third-party git clone (e.g. hermes-lcm
is Voltropy's repo; image-studio is Cliff's repo). Create a NEW tiny
read-only wrapper plugin that reads the DB directly (the session-api
pattern: plain sqlite3, no core changes) — it survives upstream updates.
- The import restriction kills graph/visualization libraries. Disk
desktop plugins import ONLY
@hermes/plugin-sdk, react,
react/jsx-runtime. A Skills Hub find like dagre-react-flow will NOT
load. For DAG/graph rendering, exploit the data's own structure — LCM
summary_nodes.depth gives a layered layout with zero physics engine; SVG
is fine at realistic node counts (dozens, not thousands).
- Data stores are often created on first use, not at install. image-studio
history.db doesn't exist until the first generation — the gallery starts
empty and grows. Design the empty state honestly; say so in the concept
rather than implying data is already there.
- Check the source code for schema when the DB doesn't exist yet — read
the
CREATE TABLE statements from history.py-style modules instead of
assuming a live DB to introspect.
Workflow
ls ~/.hermes/plugins/*/plugin.yaml — inventory kinds, tools, hooks.
find for dashboard/plugin_api.py — plugins already desktop-ready.
- Grep
apps/desktop/src/plugins/ — what the app already ships (bundled
kanban etc.) so you never propose a duplicate.
- For each candidate, pull the data model (DB schema from source, output
dirs, env redirects like
HERMES_IMAGE_STUDIO_OUTPUT).
- Produce a tiered verdict: Tier 1 = genuinely worth a page/pane, Tier 2 =
small statusbar/palette, Tier 3 = already covered / LAN-only / not visual.
- Write concept docs (see
references/agent-plugin-conversion-audit.md for
the 2026-08-03 session's full audit table and data models), then get the
user's green-light before building anything.
Verification
- Concept is grounded: every claimed data source exists (file, dir, schema
read from source), every "already covered" claim checks the bundled
plugins list.
- No duplicate proposals: kanban-style surfaces point at the bundled plugin.
- No third-party repo is modified; any new backend is a wrapper plugin.
1---2name: desktop-plugin-conversion3description: Audit agent plugins for Hermes Desktop conversion.4---5
6# Desktop Plugin Conversion (agent plugin → desktop surface)
7
8How to turn an existing **agent plugin** (Python + `plugin.yaml` in
9`~/.hermes/plugins/`) into a **Hermes Desktop** surface (pane, page,
10statusbar chip), or audit a plugin inventory for which ones are worth
11converting. Companion to the authoring skill `hermes-desktop-plugins`
12(which covers writing a desktop plugin from scratch); this skill covers the
13*conversion path*: what's bridgeable, what to check before proposing, and
14the rules that prevent reinventing wheels.
15
16## The two-plugin-systems distinction (state it first)
17
18- **Agent plugins** — `~/.hermes/plugins/<name>/plugin.yaml`, Python. Add
19 tools/hooks/backends. No UI, loaded by the agent runtime.
20- **Desktop plugins** — `~/.hermes/desktop-plugins/<name>/plugin.js`, single
21 plain ESM file. Add UI only. Loaded by the desktop app, hot-reloaded on
22 save. Folder name MUST equal plugin `id`.
23
24## The bridge (how conversion actually works)
25
26`ctx.rest` / `ctx.socket` on the desktop side reaches a FastAPI backend at
27`/api/plugins/<id>/`. That backend lives in a `dashboard/` subfolder of an
28AGENT plugin:
29
30```
31~/.hermes/plugins/<id>/dashboard/
32├── manifest.json # { "name": "<id>", "api": "plugin_api.py" }
33└── plugin_api.py # exports router = APIRouter()
34```
35
36Then the desktop plugin calls `ctx.rest('/board')` → `GET
37/api/plugins/<id>/board`. This is the exact pattern the bundled Kanban plugin
38uses (`apps/desktop/src/plugins/kanban/` → `plugins/kanban/dashboard/`).
39
40**Security gate:** the Python backend imports only when the plugin is in
41`plugins.enabled` in `config.yaml` — a NEW wrapper plugin must be added to
42that allow-list, and the desktop-side toggle alone does NOT import Python.
43
44## Audit signals (which plugins are worth converting)
45
461. Plugin exposes **data worth seeing** — a gallery, history DB, cost ledger,
47 DAG, transcript store — or already ships a web console/UI to adapt.
482. `provides_tools` rich in artifacts (images, transcripts, graph nodes).
49 Pure-behavior hooks (ponytail-style mode, katana-style scanning) are at
50 best statusbar-chip + palette-command material, not full pages.
513. `kind: backend` or `kind: standalone` with a real store beats pure-hook
52 plugins.
53
54## Rules learned the hard way
55
56- **Check what the desktop app ALREADY ships before proposing a
57 board/gallery.** The app bundles a complete Kanban plugin — `/kanban` page,
58 sidebar nav, statusbar running/ready count, ⌘⌥N new-task keybind —
59 `defaultEnabled: false` (off by default, flip in Settings → Plugins).
60 "Kanban visual" = enable it, never rebuild it.
61- **Mirror/LAN HTTP plugins are NOT desktop candidates.** `kanban-api`
62 (:8643) and `session-api` (:8644) are HermesMirror bridges for a Pi over
63 the LAN. On desktop, read the same data via gateway RPC (`host.request`)
64 or a `dashboard/` backend — never duplicate the HTTP hop.
65- **Do NOT add `dashboard/` inside a third-party git clone** (e.g. hermes-lcm
66 is Voltropy's repo; image-studio is Cliff's repo). Create a NEW tiny
67 read-only wrapper plugin that reads the DB directly (the session-api
68 pattern: plain sqlite3, no core changes) — it survives upstream updates.
69- **The import restriction kills graph/visualization libraries.** Disk
70 desktop plugins import ONLY `@hermes/plugin-sdk`, `react`,
71 `react/jsx-runtime`. A Skills Hub find like `dagre-react-flow` will NOT
72 load. For DAG/graph rendering, exploit the data's own structure — LCM
73 `summary_nodes.depth` gives a layered layout with zero physics engine; SVG
74 is fine at realistic node counts (dozens, not thousands).
75- **Data stores are often created on first use, not at install.** image-studio
76 `history.db` doesn't exist until the first generation — the gallery starts
77 empty and grows. Design the empty state honestly; say so in the concept
78 rather than implying data is already there.
79- **Check the source code for schema when the DB doesn't exist yet** — read
80 the `CREATE TABLE` statements from `history.py`-style modules instead of
81 assuming a live DB to introspect.
82
83## Workflow
84
851. `ls ~/.hermes/plugins/*/plugin.yaml` — inventory kinds, tools, hooks.
862. `find` for `dashboard/plugin_api.py` — plugins already desktop-ready.
873. Grep `apps/desktop/src/plugins/` — what the app already ships (bundled
88 kanban etc.) so you never propose a duplicate.
894. For each candidate, pull the data model (DB schema from source, output
90 dirs, env redirects like `HERMES_IMAGE_STUDIO_OUTPUT`).
915. Produce a tiered verdict: Tier 1 = genuinely worth a page/pane, Tier 2 =
92 small statusbar/palette, Tier 3 = already covered / LAN-only / not visual.
936. Write concept docs (see `references/agent-plugin-conversion-audit.md` for
94 the 2026-08-03 session's full audit table and data models), then get the
95 user's green-light before building anything.
96
97## Verification
98
99- Concept is grounded: every claimed data source exists (file, dir, schema
100 read from source), every "already covered" claim checks the bundled
101 plugins list.
102- No duplicate proposals: kanban-style surfaces point at the bundled plugin.
103- No third-party repo is modified; any new backend is a wrapper plugin.