Realtime voice conversations in Discord voice channels, plus the separate voice message attachment format.

Voice

Discord has two distinct voice surfaces: realtime voice channels (continuous conversations) and voice message attachments (the waveform preview format). The gateway supports both.

Voice channels

Setup checklist:

  1. Enable Message Content Intent in the Discord Developer Portal.
  2. Enable Server Members Intent when role/user allowlists are used.
  3. Invite the bot with bot and applications.commands scopes.
  4. Grant Connect, Speak, Send Messages, and Read Message History in the target voice channel.
  5. Enable native commands (commands.native or channels.discord.commands.native).
  6. Configure channels.discord.voice.

Use /vc join|leave|status to control sessions. The command uses the account default agent and follows the same allowlist and group policy rules as other Discord commands. Type these as slash commands in a Discord message box, not in a shell:

/vc join channel:<voice-channel-id>
/vc status
/vc leave

To inspect the bot's effective permissions before joining:

apus channels capabilities --channel discord --target channel:<voice-channel-id>

Auto-join example:

{
  channels: {
    discord: {
      voice: {
        enabled: true,
        model: "openai/gpt-6-astra",
        autoJoin: [
          {
            guildId: "123456789012345678",
            channelId: "234567890123456789",
            whenOccupied: true,
          },
        ],
        allowedChannels: [
          {
            guildId: "123456789012345678",
            channelId: "234567890123456789",
          },
        ],
        daveEncryption: true,
        decryptionFailureTolerance: 24,
        connectTimeoutMs: 30000,
        reconnectGraceMs: 15000,
        realtime: {
          provider: "openai",
          model: "gpt-realtime-2.1",
          speakerVoice: "cedar",
        },
      },
    },
  },
}

GPT-Live in Discord

Discord can use the same GPT-Live model and voice as Talk, Google Meet, and Voice Call. These surfaces share provider resolution, native delegation, and interruption policy while retaining their own audio transports. Unpinned Discord configurations keep the provider's existing default; select GPT-Live explicitly. For the Codex GPT-Live route with cove, sign in with apus models auth login --provider openai, then configure:

{
  channels: {
    discord: {
      voice: {
        enabled: true,
        realtime: {
          provider: "openai",
          model: "gpt-live-1-codex",
          speakerVoice: "cove",
        },
      },
    },
  },
}

This route reuses Talk's Gateway-owned WebRTC bridge, with ChatGPT OAuth first and Platform API-key fallback. For the public API, select gpt-live-1 and a supported public voice such as marin; Discord uses the Gateway's direct Platform-key WebSocket bridge. The model and voice must belong to the same route: cove is a Codex GPT-Live voice, and selecting it with gpt-live-1 falls back to marin. See OpenAI voice and speech.

GPT-Live owns response timing and interruption. Discord plays its continuous audio without waiting for a completed-response event, and does not add local speaker-start interruption. Microphone audio remains admitted during playback so GPT-Live can hear and handle interruptions itself. Delegated tasks use the routed Apus agent with the originating speaker's Discord identity and tool permissions. Room controls clear buffered local playback before requesting their spoken result; they keep the continuous provider stream open so it can deliver that result. The Gateway paces microphone input continuously, including silence between speaker captures. Playback preserves quiet PCM within an active stream, including pauses delivered after earlier speech has already played. When no unheard speech remains for the player's two-second idle grace, accepted audio drains before the room player is released. Speech arriving during that retirement queues under a fresh resource so it is not discarded with the old stream. Continuous playback builds a 120 ms startup buffer to absorb brief delivery gaps. A 120 ms startup deadline keeps short replies from waiting for a completed response event.

GPT-Live does not support host-enforced wake-name gating or a forced consult before every reply. Its defaults leave those policies off. Explicit requireWakeName: true or consultPolicy: "always" fails at startup with a configuration error; remove those settings or choose gpt-realtime-2.1 when you need host-controlled turns in a shared meeting. Each speaker still has a separate voice-model connection; the Apus agent conversation provides shared room context.

Notes:

Voice messages

Discord voice messages show a waveform preview and require OGG/Opus audio. Apus generates the waveform automatically, but needs ffmpeg and ffprobe on the gateway host to inspect and convert.

The agent sends a voice message with the message tool, not from a shell:

message(action="send", channel="discord", target="channel:123", path="/path/to/audio.mp3", asVoice=true)