{ id, tui } object. When Herm activates the plugin it calls tui(api), your code registers whatever it needs through the api object, and everything you register is automatically cleaned up the moment the plugin deactivates. There is no teardown boilerplate to write.
What plugins can do
Plugins have five extension points to work with:Slots — inject UI into fixed locations
Slots — inject UI into fixed locations
Slots are host-managed regions of the shell where plugins can paint content. Each slot receives a typed props object so your renderer always knows the current session id, tab index, or streaming state. Available slots:
The host decides the composition mode for each slot call site:
| Slot name | Where it renders | Props |
|---|---|---|
app_bottom | One-row gutter below the composer | { sid, tab, streaming } |
sidebar_content | Stacked section inside the right sidebar | { sid } |
sidebar_footer | Pinned row at the bottom of the sidebar | { sid } |
prompt_right | Inline, right of the composer input | { sid } |
splash_footer | Below the splash logo on an empty session | {} |
append(default) — your contribution stacks after lower-orderplugins.replace— your contribution supplants the host’s default child.single_winner— only the lowest-ordercontribution renders; the rest are dropped.
Routes — add a top-level tab
Routes — add a top-level tab
Register a named route and Herm adds it as a navigable tab after the five built-in groups (Chat, Sessions, Profiles & Automation, Config, Eikon). You can navigate to it programmatically with
api.route.navigate("YourTabName").Commands — add entries to the command palette
Commands — add entries to the command palette
Register one or more commands and they appear in the Ctrl+K palette under any category label you choose. Each command gets a stable
value string and an onSelect callback.Events — react to the gateway stream
Events — react to the gateway stream
Subscribe to the live gateway event stream with
api.event.on(fn). React to any GatewayEvent type — show a toast, update local state, or trigger a navigation.Eikon rasterizers — custom image-to-text backends
Eikon rasterizers — custom image-to-text backends
Contribute a new rasterizer to the Eikon Studio tab. You supply a
name, a knobs schema (cycle options, toggles, sliders), an available() check, and an async render(win, knobs) function. The Studio handles all spatial work and renders your knob controls generically.Current limitation: bundled plugins only
External loading from npm packages or~/.herm/plugins/ is on the roadmap but not yet available. Today every plugin must be compiled into the Herm bundle. Wiring yours in takes two steps:
Drop your file into the bundled directory
Create your plugin module at
src/plugins/bundled/hello.tsx. It must export a default HermPlugin value with a unique id and a tui function.Plugin
id values must be globally unique. Use a reverse-DNS-style prefix so yours will not collide with bundled plugins or future community plugins — for example acme.hello, not just hello.Default enablement
Plugins are enabled by default. If you want your plugin to ship turned off — useful during early development — setenabled: false on the plugin object:
Where plugin state persists
All persistent data lives in a single file:~/.hermes/herm/tui.json (or $HERM_CONFIG_DIR/tui.json when that variable is set). Herm uses this file for:
plugin.enabled— per-plugin on/off overrides keyed by pluginid.- Plugin KV data — anything you write with
api.kv.set(key, value), stored under your plugin’sidnamespace automatically. You never need to prefix keys yourself.
Next steps
- API Reference — complete type signatures for every surface on the
apiobject, all slot names and props, and the lifecycle model. - Examples — copy-pasteable code for common patterns: status bars, custom tabs, event listeners, persistent settings, and custom rasterizers.