Files
optimclaw/channels-src/discord
a8e83210ff feat(discord): add gateway channel flow in wasm (#944)
* feat(discord): restore gateway channel flow in wasm

* chore(discord): bump channel version to 0.2.1

* fix(discord): address review feedback on gateway channel PR

- Add #[serde(default)] to DiscordMessageMetadata for backward compat
  with old Option<String> serialized metadata
- Restore mention polling alongside Gateway (on_poll processes gateway
  events first, then runs poll_for_mentions if configured)
- Update on_respond to handle source_message_id with message_reference
  for mention-poll reply threading
- Implement Gateway presence status: dnd before pairing, online after
- Implement Gateway resume (OP 6) with session_id tracking, falling
  back to fresh identify on Invalid Session (OP 9)
- Extract WebsocketSessionState and spawn_websocket_poll to reduce
  nesting in start_websocket_runtime
- Simplify should_apply_dm_pairing tautology
- Remove completed plan docs
- Fix clippy items_after_test_module in extensions handler

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* fix(discord): address review findings in gateway channel PR

- Fix gateway presence always showing "online" by filtering empty
  owner_id strings from workspace store reads
- Fix interaction followup using POST instead of PATCH to
  /messages/@original, which left deferred "thinking" state unresolved
- Restore mention-poll pagination (up to 5 pages of 100 messages)
- Remove dead ed25519-dalek and hex dependencies from WASM crate
- Remove unused _channel_id parameter from remember_processed_id
- Clean up redundant let binding in send_pairing_reply

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* fix(discord): address second-round review findings

- Log warning when gateway event queue JSON fails to deserialize
  instead of silently returning empty (zmanian review item 1)
- Defer presence update from OP 10 Hello to after OP 0 READY, per
  Discord gateway protocol which requires READY before non-Identify
  commands (zmanian review item 2)
- Add 0-25% random jitter to websocket reconnect backoff per Discord's
  reconnection recommendations (zmanian suggestion)
- Extract WebsocketPollContext struct to replace 19-parameter
  spawn_websocket_poll function (zmanian suggestion)
- Document intent bitmask 4609 = GUILDS + GUILD_MESSAGES +
  DIRECT_MESSAGES in capabilities JSON (zmanian suggestion)

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

---------

Co-authored-by: zhyaoyu <[email protected]>
Co-authored-by: [email protected] <[email protected]>
Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
2026-03-28 22:20:40 -07:00
..

Discord Channel for IronClaw

WASM channel for Discord integration - handle slash commands and button interactions via webhooks.

Features

  • Slash Commands - Process Discord slash commands
  • Button Interactions - Handle button clicks
  • Thread Support - Respond in threads
  • DM Support - Handle direct messages

Setup

  1. Create a Discord Application at https://discord.com/developers/applications

  2. Create a Bot and get the token

  3. Set up Interactions URL to point to your IronClaw instance

  4. Copy the Application ID and Public Key

  5. Store in IronClaw secrets:

    ironclaw secret set discord_bot_token YOUR_BOT_TOKEN
    

    Note: The discord_bot_token secret is used for Discord REST API calls. Interaction signature verification is performed inside the Discord channel module and uses the channel config field webhook_secret (set this to your Discord app public key hex).

Discord Configuration

Register Slash Commands

curl -X POST \
  -H "Authorization: Bot YOUR_BOT_TOKEN" \
  -H "Content-Type: application/json" \
  https://discord.com/api/v10/applications/YOUR_APP_ID/commands \
  -d '{
    "name": "ask",
    "description": "Ask the AI agent",
    "options": [{
      "name": "question",
      "description": "Your question",
      "type": 3,
      "required": true
    }]
  }'

Set Interactions Endpoint

In your Discord app settings, set:

  • Interactions Endpoint URL: https://your-ironclaw.com/webhook/discord

Usage Examples

Slash Command

User types: /ask question: What is the weather?

The agent receives:

User: @username
Content: /ask question: What is the weather?

Button Click

When a user clicks a button in a message, the agent receives:

User: @username
Content: [Button clicked] Original message content

Error Handling

If an internal error occurs (e.g., metadata serialization failure), the tool attempts to send an ephemeral message to the user:

❌ Internal Error: Failed to process command metadata.

Check the host logs for detailed error information.

Advanced Usage

Gateway Mode

The Discord channel now defaults to Discord Gateway transport for inbound message intake. The bundled identify payload requests intents 4609, which expands to:

  • GUILDS (1)
  • GUILD_MESSAGES (512)
  • DIRECT_MESSAGES (4096)

Gateway DMs now follow the same pairing policy as webhook DMs. Unpaired users receive a pairing instruction reply in the DM channel before the message is allowed through to the agent. If you want stricter access control than pairing, set owner_id; that lock still applies to both webhook and Gateway traffic.

Gateway presence simply reflects a successful authenticated Gateway connection and advertises online. Pairing still controls whether DMs are allowed through to the agent, but it no longer changes the visible Discord status.

Mention Polling

The Discord channel can also poll configured channels for @bot mentions.

Example channel config:

{
  "require_signature_verification": true,
  "webhook_secret": "YOUR_DISCORD_PUBLIC_KEY_HEX",
  "polling_enabled": true,
  "poll_interval_ms": 30000,
  "mention_channel_ids": ["123456789012345678"],
  "owner_id": null,
  "dm_policy": "pairing",
  "allow_from": []
}

Access Control

  • owner_id: when set, only that Discord user can interact with the bot.
  • dm_policy: open allows all DMs; pairing requires approval.
  • allow_from: allowlist entries for DM pairing checks (*, user id, or username).
  • Gateway DMs respect dm_policy and pairing just like webhook DMs.

Embeds

To send embeds, include an embeds array in the metadata_json field of the agent's response. The structure should match the Discord API embed object.

Troubleshooting

"Invalid Signature"

  • Check that webhook_secret is set to your Discord app public key hex in the Discord channel config.
  • Validation happens inside the Discord WASM channel.
  • If require_signature_verification is true and webhook_secret is empty, the channel returns HTTP 500 with a configuration error.

"401 Unauthorized"

  • Check that discord_bot_token is set correctly in IronClaw secrets.
  • Ensure the bot is added to the server.

"Interaction Failed"

  • The interaction might have timed out (Discord requires a response within 3 seconds).
  • The interactions_endpoint_url might be unreachable.

Building

cd channels-src/discord
cargo build --target wasm32-wasi --release

License

MIT/Apache-2.0