84e17db0bd
Bot-Mode canonical chats (the ONE forever DM per bot) and room plumbing sessions are plugin-owned scratch conversations. They are now created with an explicit follow_profile_config contract, persisted in the session row's model_config, so session.resume rebuilds from the member profile's CURRENT config instead of restoring the stored model/provider pin from an old row. That stale pin is what left bot DMs stuck on a dead provider (e.g. 'out of Nous credits' after the profile was switched to ollama-cloud) while the same bot worked fine in rooms — the mirror image of the room-plumbing bug (#89497 class). Normal 1:1 user chats keep the stored-runtime restore: opening an older chat must show the model it actually used. - tui_gateway/methods_session.py: accept follow_profile_config on session.create - tui_gateway/server.py: persist the marker in the row; skip stored-runtime overrides on resume when present - apps/desktop/src/plugins/hermes-bots/plugin.js: send the contract from createCanonicalChat and ensureGroupChatSession - tests: backend override + row-persist coverage; desktop source-contract coverage for both session kinds
Bundled plugins
Drop a <name>/plugin.{ts,tsx} here that default-exports a HermesPlugin and
it registers automatically at boot (vite glob in ../contrib/plugins.ts), with
the same inventory + live enable/disable contract as runtime plugins.
Keep this tree for real shipped plugins (and the small authoring fixtures that
dogfood the SDK). One-off demos that rebuild a core chrome piece 1:1 do not
belong here — they double the UI and confuse Settings ▸ Plugins. Publish those
in the companion
hermes-example-plugins
repo instead.
User- and agent-authored plugins load at runtime from
$HERMES_HOME/desktop-plugins/<name>/plugin.js (the disk door) — see the
hermes-desktop-plugins skill.