一键导入
hermes-desktop-plugins
Write desktop app plugins that add UI panes and commands.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Write desktop app plugins that add UI panes and commands.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Use when the user wants to do anything in Unreal Engine through Epic's official editor-embedded MCP server (catalog entry: unreal-engine) — build/light/populate scenes, place and transform actors, author Blueprints, animate with Sequencer, create material instances, frame cameras, take screenshots, render, import assets, run PIE test sessions and automation tests, or automate the editor end-to-end from plain-English prompts with no Unreal knowledge required. Covers the tool-search discovery walk (list_toolsets/describe_toolset/call_tool), serial game-thread call discipline, ProgrammaticToolset batching, the Blueprint graph DSL loop, scene-craft numbers (physical light units, exposure, scale conventions), complete build recipes, save/undo hygiene, and extending the tool surface with custom Python toolsets.
Manual OAuth for remote MCP servers on headless gateways.
Configure, extend, or contribute to Hermes Agent.
Drive Blender via the catalog blender MCP, with bpy recipes.
Humanize text: strip AI-isms and add real voice.
Join a Google Meet call, transcribe live captions, optionally speak in realtime, and do the followup work afterwards. Use when the user asks the agent to sit in on a meeting, take notes, summarize, respond in-call, or action items from it.
| name | hermes-desktop-plugins |
| description | Write desktop app plugins that add UI panes and commands. |
| version | 1.0.0 |
| platforms | ["linux","macos","windows"] |
| metadata | {"hermes":{"tags":["desktop","plugins","ui","extension"],"category":"productivity","related_skills":[]}} |
Write plugins for the Hermes desktop app: statusbar items, layout panes,
command-palette commands, keybinds, routes, and themes. A plugin is a single
plain-JavaScript ESM file the app loads at runtime — no build step, no repo
changes. This skill does not cover backend plugins (~/.hermes/plugins/);
those are Python and documented separately.
$HERMES_HOME/desktop-plugins/ (usually
~/.hermes/desktop-plugins/).$HERMES_HOME/desktop-plugins/<name>/plugin.js from
templates/plugin.js (relative to this skill directory) — that's
~/.hermes/... by default, or ~/.hermes/profiles/<profile>/... under a
named profile. Keep <name> equal to the plugin id.The ONLY import surface is @hermes/plugin-sdk (plus react /
react/jsx-runtime, which resolve to the app's own React — write UI with
jsx() calls, not JSX syntax; the file is not compiled).
host.state.* — readonly reactive atoms: activeSessionId, cwd,
gateway, model, profile, viewport. Read with .get() in handlers,
useValue(atom) in components.host.request(method, params) — gateway JSON-RPC (sessions, config,
skills, cron — everything the app uses).host.onEvent(type, fn) — live gateway events ('*' for all). Returns a
disposer.host.notify({ kind, message }), host.navigate(path), host.logs(...),
host.status(), haptic('tap').ctx.register({ id, area, order?, render?, data? }) — contribute UI.
Key areas: 'statusBar.right'/'statusBar.left' (chips),
'panes' (layout zones — set title and
data: { placement, dock?, width?, height? }; the pane auto-joins a
matching zone), PALETTE_AREA (⌘K commands), KEYBINDS_AREA (rebindable
actions).placement: 'left'|'right'|'bottom'|'main' is the
semantic role — the pane stacks (tabs) with existing panes of that role.
To land on a specific EDGE instead, add dock: { pane, pos } — the same
gesture as dragging onto a pane's drop chip. pane is any pane id
(workspace is the main thread; also sessions, terminal, files,
review, logs), pos is 'top'|'bottom'|'left'|'right'|'center'.
E.g. "below the conversation" = dock: { pane: 'workspace', pos: 'bottom' }
— declare a height (e.g. '200px') so it doesn't take half the zone.area: ROUTES_AREA with data: { path: '/my-page' }
and a render — the page mounts in the workspace (main) pane like any
built-in view. Make it reachable with a sidebar nav row:
ctx.register({ id: 'nav', area: SIDEBAR_NAV_AREA, data: { path: '/my-page', label: 'My Page', codicon: 'project' } })
(renders below Artifacts, lights up at the route) — and/or a
PALETTE_AREA command calling host.navigate('/my-page').ctx.storage.get/set/remove — persistence namespaced to your plugin.Button, Input,
Textarea, Select*, Switch, Checkbox, SegmentedControl, Tabs*,
Dialog*, ConfirmDialog, DropdownMenu*, ContextMenu*, Popover*,
Tip/Tooltip*, Badge, Kbd/KbdGroup, SearchField, ScrollArea,
Separator, Skeleton, GlyphSpinner, EmptyState, ErrorState,
CopyButton, StatusDot, LogView, Codicon, DecodeText, plus cn
and icons.*. Prefer these over hand-rolled elements so the plugin looks
native; style with theme vars, never hardcoded colors.id; the folder name must match.templates/plugin.js; keep the default export shape
({ id, name, register(ctx) }).area: 'panes' with a placement hint and a
render returning your component — the app places it into a sensible
zone automatically; the user can drag it anywhere afterwards.host.request and/or subscribe with host.onEvent;
never poll faster than a few seconds.#000, black, rgb(...)). Panes
already sit on the app's editor background — leave the background alone
and use theme variables for everything else: var(--ui-text-secondary),
var(--ui-text-quaternary), var(--ui-stroke-secondary),
var(--ui-accent). For canvas drawing, resolve them once with
getComputedStyle(canvas).getPropertyValue('--ui-accent').StatusDot) is a ReferenceError at render. Double-check every
identifier in your jsx() calls appears in the import line.ResizeObserver and
re-size the canvas (width/height attributes, not just CSS) — panes resize
constantly (sash drags, layout switches); a mount-time-only size leaves
blank space or blurry scaling.jsx('div', { children: ... }) from react/jsx-runtime.@hermes/plugin-sdk, react, and
react/jsx-runtime; other specifiers fail to resolve.$atom.get()), never from render
closures — rapid events will otherwise see stale values.useValue) only in the leaf that
renders the value.