Inside a Discord Voice Channel Session

+15 Mana ✨

Introduction

Setup is done and the bot can join a voice channel. This lesson is the runtime half: the commands that put the bot in a channel, what it does once it is there, and the habits that keep a voice channel session reliable instead of chaotic.

Key Concepts

  • /voice join: The command, typed in a text channel, that brings the bot into the voice channel you are currently in.
  • Per-user audio stream: Discord delivers each speaker's audio separately, so the bot tracks users independently.
  • Echo prevention: The bot pausing its own listening while it speaks, so it does not transcribe its own voice.
  • Allowlist: DISCORD_ALLOWED_USERS, the set of users whose audio the bot will actually process.

Real World Context

A team runs a Discord voice channel during a working session. Someone asks, out loud, "what did we decide about the cache timeout yesterday?" Hermes, sitting in the channel, hears it, transcribes it, checks its memory, and answers out loud, while also dropping the transcript and the answer into the text channel for anyone reading rather than listening. That is the experience this lesson sets up, and a handful of details decide whether it feels smooth or broken.

Deep Dive

Joining and leaving. The commands are typed in a Discord text channel where the bot is present:

text
/voice join      bot joins the voice channel you are currently in
/voice channel   an alias for /voice join
/voice leave     bot disconnects from the voice channel
/voice status    show the voice mode and the connected channel

You must already be in a voice channel before running /voice join. The bot joins yours; it does not pick a channel for you.

What happens once joined. The runtime loop runs like this:

  1. The bot listens to each user's audio as an independent stream.
  2. It detects the end of a turn. After at least 0.5 seconds of speech, 1.5 seconds of silence marks the turn as finished. That silence window is deliberately tighter than the 3.0 seconds the CLI loop uses, because a live channel needs a snappier back-and-forth.
  3. It transcribes the captured audio with Whisper STT, using whichever provider you configured earlier.
  4. It runs the full agent pipeline: session, tools, and memory, exactly as text mode does.
  5. It speaks the reply back into the voice channel with TTS.

The text channel mirrors everything. The bot does not only speak. Transcripts of what it heard appear in the text channel as [Voice] @user: what they said, and the agent's response is posted there as text as well as spoken in the channel. The text channel used is the one where /voice join was issued. This gives a written record of a spoken session and lets people who are reading rather than listening still follow along.

Echo prevention. A bot that could hear itself would transcribe its own reply and then answer it, on and on. Hermes prevents this by pausing its audio listener while it plays a TTS reply, so its own voice never re-enters the pipeline.

Access control. Only users listed in DISCORD_ALLOWED_USERS are heard. Everyone else's audio in the channel is silently ignored. In a shared voice channel this is what stops the bot from reacting to every nearby conversation, so the allowlist is not only a security setting. It is what makes the feature usable in a room with other people in it.

Operating it well. Three habits, taken straight from the documentation. Keep the allowlist tight, so the bot answers only the right people. Use a dedicated test channel at first, so experiments do not disrupt a real working channel. And verify that ordinary chat voice replies, the earlier lessons of this section, already work before attempting voice channels. A voice channel stacks STT, TTS, and a live audio connection all at once, and you want the simpler layers already proven before you add the hardest one.

Common Pitfalls

  1. Running /voice join while not in a voice channel: The bot joins the channel you are in. If you are not in one, there is nothing for it to join. Enter the voice channel first, then issue the command.
  2. Expecting the bot to hear everyone: Only users in DISCORD_ALLOWED_USERS are processed; all other audio is ignored. Someone who is not on the allowlist will appear to be talking to a bot that cannot hear them.

Best Practices

  1. Keep DISCORD_ALLOWED_USERS tight: In a shared channel, the allowlist is what keeps the bot responding to the intended people and ignoring everyone else.
  2. Prove the earlier layers first: Confirm chat voice replies work before trying voice channels, and start in a dedicated test channel so the live audio loop is the only new variable you are debugging.

Summary

  • /voice join brings the bot into the voice channel you are already in; /voice leave disconnects it.
  • Once joined, the bot listens per user, ends a turn after 1.5 seconds of silence, transcribes, runs the agent, and speaks back.
  • Transcripts and replies are mirrored into the text channel where /voice join was issued, and echo prevention stops the bot from hearing itself.
  • Only users in DISCORD_ALLOWED_USERS are heard; keep that list tight and verify chat voice replies before attempting voice channels.

Code Examples

bash
# Typed in a Discord text channel, while you are in a voice channel:
/voice join      # bot joins your current voice channel
/voice status    # show the voice mode and the connected channel
/voice leave     # bot disconnects

# Only allowlisted users are heard in the channel:
# ~/.hermes/.env
#   DISCORD_ALLOWED_USERS=284102345871466496
✓ Completed