A Hermes Desktop plugin that swaps the composer's two Enter keys.
| Key | Stock | With this plugin |
|---|---|---|
Enter |
send message | insert a line break |
Shift+Enter |
line break | send message |
Everything else keeps working: Cmd/Ctrl+Enter still queues a follow-up mid-turn, Enter inside the @ / / completion drawer still picks the highlighted item, and IME composition is untouched.
It also offers:
- Command to Diagnose if not working
- Command to Toggle it ON/OFF on the fly (app restart persistent)
Drop the enter-swap/ folder into your Hermes desktop-plugins folder. The location varies from system, simplest way to locate is going into the app settings > Plugins and click on the open folder button.
The folder name must stay enter-swap - it has to match the plugin id.
The app watches that directory and loads the file within a few seconds. If nothing happens, open the palette and run Reload desktop plugins. Then check Settings → Plugins shows "Enter / Shift+Enter swap".
Renderer-only: no gateway restart, no config.yaml change, no Python backend.
- Temporarily:
Cmd/Ctrl+K→ Toggle Enter / Shift+Enter swap. Persists across restarts. - Properly: Settings → Plugins → switch it off.
- Permanently: delete the folder.
Hermes core marks composer.send (enter) and composer.newline (shift+enter) as read-only in apps/desktop/src/lib/keybinds/actions.ts, so the Shortcuts panel can't rebind them - that's the only reason this plugin exists. There's an open upstream request to make them rebindable. If your version lets you remap these in Settings → Shortcuts, use that instead of this.
There's no supported API for the swap. COMPOSER_AREAS - the composer's plugin surface - states in its own header that core keeps ownership of the transcript, input, and submit engine; the seams augment the composer, they never replace it. Middleware can rewrite a draft, but it can't rebind a key.
What the plugin does instead: a capture-phase keydown listener on the composer editor, ahead of React.
- plain
Enter→ swallow the event,document.execCommand('insertLineBreak'). Realbeforeinput/inputevents, so the app's draft sync and undo history stay correct - manual DOM surgery would break both. Shift+Enter→ swallow it, re-dispatch a synthetic plainEnterbehind a re-entrancy flag, so core's own submit path runs untouched. That matters:enteris bound to bothcomposer.sendandcomposer.steer, and which fires depends on your settings. Reimplementing submit would silently discard that.
Survives an app update: It lives in $HERMES_HOME, outside the app bundle, and your enable/disable choice is remembered.
What can break at any moment: the behavior. It depends on two internal DOM contracts - the composer-rich-input and composer-completion-drawer slot names - and on plain-Enter-keydown remaining the send trigger. If a release changes those, the swap stops and you get stock Enter=send back. It never leaves the composer broken: there's a structural selector fallback, and if nothing matches it warns once and does nothing.
Verified against v0.19.0 (2026.7.20) on Windows.
Cmd/Ctrl+K → Diagnose Enter / Shift+Enter swap. It reports which selectors matched and which composer-* slots exist in your build, as a toast and in the renderer console under [enter-swap] probe. Open an issue with that output.
A Hermes disk plugin is evaluated in the renderer with full app authority - the gateway RPC door, storage, navigation. That's true of every disk plugin, by design, because a local file could already run code on your machine. plugin.js is ~200 lines with comments. Read it before you install it.