ElevenLabs Sound Effects: official Hermes Agent plugin

# ElevenLabs Sound Effects for Hermes Agent > Part of the [Hermes Official Plugins](../README.md), Nous Research's official plugins for Hermes Agent. Official [Hermes Agent](https://github.com/NousResearch/hermes-agent) plugin for the [ElevenLabs Sound Effects API](https://elevenlabs.io/docs/capabilities/sound-effects). It gives the agent one tool: | Tool | What it does | |---|---| | `elevenlabs_sound_effect` | Turns a text description into an audio file (0.5 to 30 seconds, optionally a seamless loop) | Ask for "the sound of a heavy wooden door creaking open in a stone hall", "a short retro coin pickup blip" or "90s hip-hop drum loop, 90 BPM, loopable" and Hermes generates it and saves it. The tool hands the agent a `MEDIA:` line for the file; when the agent puts it in its reply, the file is sent as an attachment on Telegram, Discord, Slack and the other messaging platforms. MP3 (the default format) plays inline on most chat apps; Ogg Opus and WAV can arrive as plain files (Telegram shows them that way). On Discord, Hermes releases after v0.22.5 send MP3 and WAV as normal attachments that play inline (v0.22.5 and earlier sent them as voice messages). In Hermes Desktop the same line becomes an inline sound card (below). In the terminal you get the file path. The plugin also ships: | Part | What it does | |---|---| | `elevenlabs-sound-design` skill | How to write ElevenLabs prompts (from ElevenLabs' own prompting guide), make loops, pick a format for where the sound goes (game engine, video, UI, chat), build a sound pack, and deliver per surface | | `sfx_tool.py` (in the skill) | Local post-processing with ffmpeg: mono downmix, trim silence, loudness-normalise, fades, loop-seam click check, convert to OGG/WAV/MP3, pack a named set into a folder + `manifest.json` + zip (or a game variation set with matched-loudness checks). Costs no ElevenLabs credits | | Desktop sound card | Each generated sound shows in the chat as a card: waveform, play/pause, gapless loop audition, download in each format, reveal, and **Next** actions (Hermes Desktop with tool-media renderers; older Desktops use their built-in player) | | Desktop sound library | ⌘K → **ElevenLabs: open sound library**: every sound this profile made, with its prompt and settings | ## Install ```bash hermes plugins install elevenlabs-sound-effects ``` Or straight from this repo: `hermes plugins install NousResearch/hermes-official-plugins#elevenlabs-sound-effects`. The installer asks for your ElevenLabs API key if `ELEVENLABS_API_KEY` is not set yet (create one under **Profile → API keys** at ). It is the same key Hermes's ElevenLabs text-to-speech voice uses, so if you already have that set up there is nothing to enter. A restricted key needs the **Sound Effects** permission enabled (separate from Text to Speech). The tool only appears to the agent once the key is set. Plugins are installed per profile: use `hermes -p plugins install elevenlabs-sound-effects` for another profile. The only Python dependency is `httpx`, which Hermes already ships. ## Settings In Hermes Desktop: **Capabilities → Plugins**, then the gear icon on the plugin (the settings page is titled with the package name, `elevenlabs-sound-effects`). Everywhere else, with `hermes config set`: | Setting | Default | What it does | |---|---|---| | `api_key` | (unset) | Your ElevenLabs API key, stored in `.env` as `ELEVENLABS_API_KEY`: `hermes config set ELEVENLABS_API_KEY ` | | `sound_model` | `eleven_text_to_sound_v2` | `eleven_text_to_sound_v2` or `eleven_text_to_sound_v3`: `hermes config set plugins.entries.elevenlabs-sound-effects.settings.sound_model eleven_text_to_sound_v3` | | `output_format` | `mp3_44100_128` | `mp3_44100_128`, `mp3_44100_192`, `opus_48000_128`, `opus_48000_192`, `wav_44100`, `wav_48000`: `hermes config set plugins.entries.elevenlabs-sound-effects.settings.output_format wav_48000`. ElevenLabs documents 192 kbps MP3 for its Creator plan and above and 44.1 kHz WAV for Pro and above; if your plan refuses a format, the tool reports ElevenLabs' error. | | `api_base_url` | `https://api.elevenlabs.io` | Change only for an ElevenLabs data-residency endpoint, e.g. `https://api.eu.residency.elevenlabs.io` | The agent chooses the per-sound parameters itself: the description (at most 450 characters; longer prompts are refused before anything is sent), the length (`duration_seconds`, 0.5 to 30; omit it and ElevenLabs picks one), `loop`, and `prompt_influence` (0 to 1; higher follows the prompt more literally, lower varies more). The tool also takes an optional `model` per call (`eleven_text_to_sound_v2` or `eleven_text_to_sound_v3`); without it the `sound_model` setting applies. ## Where files go Each sound is saved to `/cache/generated/audio/sfx___.` and never overwrites an earlier one. The Desktop card and library serve a file only while it has a single link: after a backup tool hard-links your Hermes folder (rsnapshot, `cp -al`), those sounds play in Desktop's built-in player instead of the card, and the library can't play or download them until the extra links are removed (the files themselves are untouched). Ask the agent to copy it into your project if you want it somewhere else. Each generation also appends one line to `/plugin-data//sounds.jsonl` (the plugin's own data folder, per profile): the sound id, prompt, requested length, the length of the audio ElevenLabs returned, loop, prompt influence, model, format, file name, size, the credits ElevenLabs billed, and the chat it came from. The Desktop library reads it. Nothing in it leaves your machine. ## Hermes Desktop The Desktop half is opt-in, also after `hermes plugins install` from the CLI (which turns on only the agent half): open **Capabilities → Plugins**, switch to the list view, and turn on **Desktop: ElevenLabs Sound Effects** on the plugin's row. Without it Desktop still plays every sound, in its built-in audio player. **Sound card.** The tool always hands the agent a plain `MEDIA:` line, the one every surface plays. Hermes Desktop works out which tool produced that file and, when it was `elevenlabs_sound_effect` and the Desktop half is on, lets this plugin draw it as a sound card instead of the built-in audio player. That needs a Hermes Desktop with tool-media renderers (on `main` since commit `567569267a`; first in the next release after v0.22.5). On older Desktops, or with the Desktop half off, the same line plays in Desktop's built-in player. The card also hands the sound back to the built-in player whenever it can't play it itself: a sound made in another profile, a removed record, or a file the plugin won't serve (see [Where files go](#where-files-go)). Nothing depends on which surface a chat was started on, and the agent never writes a card line. The card shows the prompt, length, loop, model, format and credits billed, a waveform you can click to seek, Play/Pause, a **Loop** toggle that repeats the sound gaplessly so you can hear the seam, **Download** (the original, or MP3 / WAV / OGG converted by ffmpeg on the machine Hermes runs on; saved through Desktop's Save dialog on your computer), and **Reveal** in your file manager. **Next** offers 3 variations, shorter, longer, make it loop and try the other model. Each row shows its cost worked out from what ElevenLabs billed for this sound (an automatic-length sound is billed a flat amount per generation, so its per-second price isn't known, and the row says so), and sends a chat message to the agent naming the tool and its arguments. Nothing is billed until the agent runs the tool. On Desktop builds that tell plugins which chat shows a card, the message goes to that chat, and nowhere else: if that chat is not on screen, Desktop shows a notice instead. Older builds send it to the chat you last typed in. **Sound library.** ⌘K → **ElevenLabs: open sound library** opens a tab listing every sound the tool made in the active profile, MP3, Ogg Opus and WAV alike, with per-format counts and sizes, a format filter and a prompt search. Each row plays, downloads, reveals, **Reuse prompt** (into the composer) and **Open chat** (the conversation that made it). It reloads when a sound is generated, when you switch profile or connection, and when you save the plugin's settings; it never polls. **Remote Hermes.** The Desktop half runs in the Desktop app, so install the plugin on the Hermes machine (agent half) and into the Desktop you use: **Capabilities → Plugins → Install from Git** with `NousResearch/hermes-official-plugins/elevenlabs-sound-effects` and **Desktop UI** checked, then turn on the Desktop switch. Without that, Desktop lists the half as unavailable for the remote backend and sounds play in its built-in player. The files stay on the Hermes machine. Playback and downloads stream through Hermes, so they work the same. On a registered remote connection Reveal is replaced by a note saying which host holds the file; where Desktop can't tell (a per-profile remote override) the library names the host the backend reports and Reveal explains when the file is not on this computer. Format conversion needs ffmpeg on that host; without it only the original format is offered and the menu says why. ## Cost and privacy Every call is a paid ElevenLabs generation billed to your account: ElevenLabs charges per second of audio when a duration is set (about 10 credits per second, as billed to us) and a flat amount per generation otherwise (about 50 credits, for 2 s and 3 s automatic clips alike; see their [pricing](https://elevenlabs.io/pricing/api)). Loops can come back longer than requested (we measured 1 s → 1.5 s and 2 s → 2.25 s, billed 10 and 20 credits): the tool reports the real length as `length_seconds` beside `requested_duration_seconds`, and the card shows both. The tool reports the `character-cost` header ElevenLabs returns as `billed_characters`. Desktop format conversions and the processing script run locally and cost nothing. What leaves your machine: the sound description and the parameters above, sent to `api_base_url` with your API key. Nothing else from the conversation is sent. ## Local processing script The bundled skill runs `skills/elevenlabs-sound-design/scripts/sfx_tool.py` (Python standard library plus `ffmpeg`/`ffprobe` on PATH) when a sound needs processing (`python` instead of `python3` where only that exists, as on Windows): ```bash python3 sfx_tool.py process in.wav --out out.ogg --trim --loudness -16 --fade-ms 10 # one-shot: trim + normalise + fade + convert python3 sfx_tool.py process loop.mp3 --out loop.ogg # plain conversion keeps a loop's edges python3 sfx_tool.py loopfix loop.wav --out fixed.wav # crossfade the seam (+ crossfade_level_db) python3 sfx_tool.py loopcheck fixed.wav # seamless | click | silent, worst channel (+ a note when the seam dips) python3 sfx_tool.py pack a.mp3 b.mp3 --name "UI pack" --out-dir . --format ogg # folder + manifest.json + zip python3 sfx_tool.py process take1.mp3 --out t1.wav --trim --loudness -18 --mono # a positional game one-shot: mono, levelled python3 sfx_tool.py pack t1.wav t2.wav t3.wav --name "Footstep Gravel" --out-dir . --variations # footstep_gravel_01..03 + loudness_spread_lu ``` Every run prints one JSON line (`{"ok": true, ...}` or `{"ok": false, "code": ..., "error": ...}`), including when ffmpeg is missing, an input is not audio or an output can't be written. Codes: `ffmpeg_missing`, `bad_input`, `bad_args`, `ffmpeg_failed`, `interrupted`, `internal`. `process` reports the loudness it measured on the output (`output.integrated_lufs`, `output.true_peak_dbtp`): `--loudness` aims at the target under a -1.5 dBTP ceiling, so a peaky clip can land below it. ## Development ```bash cd elevenlabs-sound-effects HERMES_AGENT_REPO=../../hermes-agent PYTHONPATH=../../hermes-agent python -m pytest -q hermes plugins validate . npm ci && npm test && npm run typecheck && npm run build # Desktop half: src/*.tsx → desktop/plugin.js ``` The tests load the plugin through Hermes's real plugin discovery and dispatch the tool through the real registry against a local stand-in for `POST /v1/sound-generation` that checks requests against ElevenLabs' published OpenAPI schema; they never call ElevenLabs. `tests/test_library.py` reads the provenance records back through `dashboard/plugin_api.py`; `tests/test_sfx_tool_script.py` runs the script (its ffmpeg cases skip where ffmpeg is absent); `tests/sound.test.mjs` covers the card's Next actions and helpers, and `tests/plugin.test.mjs` registers the real Desktop half against a stub SDK with and without Desktop's tool-media renderer area. The Desktop half is TypeScript in `src/`, bundled with esbuild into `desktop/plugin.js`, which is committed (Hermes Desktop loads it as is). It imports only `@hermes/plugin-sdk` and `react`; `sdk.d.ts` declares the SDK names it uses, and newer SDK calls are feature-detected. Rebuild and commit `desktop/plugin.js` after any change under `src/`. ## License MIT, see [LICENSE](LICENSE).