Skip to content

Discord Integration

Connect your herdctl agents to Discord, allowing users to interact with AI agents through chat messages and slash commands. Each agent appears as a distinct bot with its own identity, presence, and configuration.

herdctl uses a per-agent bot architecture where each Discord-enabled agent has its own Discord Application and bot token. This design provides several benefits:

Distinct Identities

Each agent appears as a separate bot with its own name, avatar, and presence status

Independent Configuration

Different agents can monitor different channels with different response modes

Scalable Architecture

Add new agents without affecting existing bot configurations

Clear User Experience

Users always know which agent they’re talking to by the bot’s identity

Discord Server
├── #support
│ └── @SupportBot responds to mentions (support-agent)
├── #dev-chat
│ └── @CoderBot responds to all messages (coder-agent)
└── DMs
└── @SupportBot auto-responds (support-agent)

Each agent connects to Discord with its own bot account. When a user messages or mentions the bot, herdctl triggers a Claude session to respond.

ModeBehaviorBest For
mentionResponds only when @mentionedShared channels where multiple bots exist
autoResponds to all messagesDedicated support channels, DMs

herdctl supports two different Discord integrations:

IntegrationTypePurposeConfiguration
ChatTwo-wayInteractive conversationschat.discord
Notification HooksOne-wayJob completion alertshooks.after_run

The chat integration documented on this page enables interactive, two-way conversations:

  • Bot responds to user messages and mentions
  • Maintains conversation context
  • Users can ask questions and get responses
  • Configured in the chat.discord section of agent config

Notification hooks send one-way alerts when jobs complete:

  • Post job results to a channel
  • Conditional notifications (e.g., only when a price drops)
  • No user interaction—just announcements
  • Configured in the hooks.after_run section

Example notification hook:

hooks:
after_run:
- type: discord
channel_id: "${DISCORD_CHANNEL_ID}"
bot_token_env: DISCORD_BOT_TOKEN
when: "metadata.shouldNotify"

Before setting up Discord integration, ensure you have:

  • A Discord account
  • Administrator or Manage Server permissions on the target Discord server
  • Access to the Discord Developer Portal
  • herdctl installed and configured
  • Your agent configuration file ready
  1. Open the Discord Developer Portal

    Navigate to https://discord.com/developers/applications and sign in with your Discord account.

  2. Create a New Application

    Click the New Application button in the top-right corner.

    Enter a name for your application. This name appears in OAuth authorization screens but not as the bot’s display name.

  3. Navigate to the Bot Section

    In the left sidebar, click Bot.

  4. Configure the Bot Username

    Click Edit next to the bot’s username. This is the name users will see in Discord.

    Example names:

    • Support Bot for a customer support agent
    • Code Assistant for a development agent
    • Marketing Bot for a content agent
  5. Set the Bot Avatar (Optional)

    Click on the bot’s avatar to upload a custom image. This helps users identify the bot.

  6. Copy the Bot Token

    Click Reset Token to generate a new token (or Copy if one exists).

  7. Save the Token Securely

    Add the token to your environment:

    Terminal window
    # Add to your shell profile or .env file
    export SUPPORT_DISCORD_TOKEN="your-bot-token-here"

herdctl requires these Privileged Gateway Intents to function properly:

  1. In your Discord Application, go to Bot settings

  2. Scroll down to Privileged Gateway Intents

  3. Enable the following intents:

    IntentRequiredPurpose
    Message Content IntentYesRead message text to respond to users
    Server Members IntentNoNot required for basic functionality
    Presence IntentNoNot required for basic functionality
  4. Click Save Changes

When inviting the bot, herdctl needs these permissions:

PermissionPurpose
Send MessagesReply to user messages
Read Message HistoryBuild conversation context
Use Slash CommandsHandle /help, /reset, /status commands
View ChannelsSee channels the bot has access to

The combined permission integer is: 2147551232

  1. In your Discord Application, go to OAuth2 > URL Generator

  2. Under Scopes, select:

    • bot
    • applications.commands
  3. Under Bot Permissions, select:

    • Send Messages
    • Read Message History
    • Use Slash Commands
    • View Channels

    Or use permission integer: 2147551232

  4. Copy the generated URL at the bottom of the page

  5. Open the URL in your browser

  6. Select the server where you want to add the bot

  7. Click Authorize

  8. Complete the CAPTCHA if prompted

The bot will now appear in your server’s member list (offline until you start herdctl).

Configure Discord in your agent’s YAML file under the chat.discord section:

name: support-agent
description: "Customer support agent"
chat:
discord:
bot_token_env: SUPPORT_DISCORD_TOKEN
guilds:
- id: "123456789012345678"
channels:
- id: "987654321098765432"
name: "#support"
mode: mention
chat:
discord:
# Environment variable containing the bot token (required)
bot_token_env: SUPPORT_DISCORD_TOKEN
# Session expiry in hours (default: 24)
session_expiry_hours: 24
# Log level: minimal, standard, verbose (default: standard)
log_level: standard
# Optional: slash command registration mode
# global = available everywhere (slower to propagate)
# guild = faster updates for one guild (recommended for local dev)
command_registration:
scope: global # global | guild
# guild_id: "123456789012345678" # required when scope: guild
# Output configuration - control what SDK messages appear in Discord
output:
tool_results: true # Show tool result embeds (default: true)
tool_result_max_length: 900 # Max chars in tool output (default: 900, max: 1000)
system_status: true # Show system status embeds (default: true)
result_summary: true # Show completion summary embed (default: true)
errors: true # Show error embeds (default: true)
typing_indicator: true # Show typing indicator while processing (default: true)
# Bot presence/activity (optional)
presence:
activity_type: watching # playing, watching, listening, competing
activity_message: "for support requests"
# Guild (server) configurations
guilds:
- id: "123456789012345678" # Discord server ID
channels:
- id: "987654321098765432" # Channel ID
name: "#support" # For documentation (optional)
mode: mention # mention or auto
context_messages: 10 # Messages to include as context
- id: "111222333444555666"
name: "#general"
mode: auto
context_messages: 5
# DM settings for this guild's members (optional)
dm:
enabled: true
mode: auto
allowlist: ["user-id-1", "user-id-2"] # Only these users (optional)
blocklist: ["spam-user-id"] # Block specific users (optional)
# Global DM settings (applies to all DMs)
dm:
enabled: true
mode: auto
FieldTypeDefaultDescription
bot_token_envstringRequired. Environment variable name containing the bot token
session_expiry_hoursnumber24Hours before a conversation session expires
log_levelstringstandardLogging verbosity: minimal, standard, verbose
command_registrationobject{ scope: global }Slash command registration mode (global or guild)
presenceobjectBot presence/activity configuration
guildsarrayList of Discord servers to operate in
dmobjectGlobal DM configuration
FieldTypeDescription
activity_typestringActivity type: playing, watching, listening, competing
activity_messagestringActivity text shown in the bot’s status
FieldTypeDefaultDescription
scopestringglobalglobal registers app commands globally; guild registers to one guild for faster propagation
guild_idstringRequired when scope: guild; target guild for registration
FieldTypeDescription
idstringRequired. Discord server (guild) ID
channelsarrayChannels to monitor in this guild
dmobjectDM settings for members of this guild
FieldTypeDefaultDescription
idstringRequired. Discord channel ID
namestringHuman-readable name (for documentation)
modestringmentionResponse mode: mention or auto
context_messagesnumber10Number of recent messages to include as context
FieldTypeDefaultDescription
enabledbooleantrueAllow direct messages
modestringautoResponse mode for DMs
allowliststring[]Only allow DMs from these user IDs
blockliststring[]Block DMs from these user IDs

Control which SDK messages are surfaced in Discord. When your agent uses tools (Bash, Read, Write, etc.) or the SDK emits system/error messages, these settings determine what appears in the channel.

FieldTypeDefaultDescription
output.tool_resultsbooleantrueShow tool result embeds when the agent uses tools
output.tool_result_max_lengthnumber900Maximum characters shown in tool output (max: 1000)
output.system_statusbooleantrueShow system status embeds (e.g., “Compacting context…”)
output.result_summarybooleantrueShow a summary embed when the agent finishes (duration, cost, tokens)
output.errorsbooleantrueShow error embeds when the SDK reports errors
output.typing_indicatorbooleantrueShow typing indicator while processing. Set to false on long-running jobs to prevent Discord timeout errors

All output types appear as compact Discord embeds with color coding:

Message TypeEmbed ColorExample Content
Tool result (success)Blurple🔧 Bash> git status with output preview
Tool result (error)Red🔧 Bash — command output with error
System statusGray⚙️ System — “Compacting context…”
Result summaryGreen/Red✅ Task Complete — duration, turns, cost, token usage
ErrorRed❌ Error — error description

Tool result embeds include the tool name with an emoji, the input summary (command, file path, or search pattern), execution duration, output length, and a truncated preview of the output in a code block.

Minimal output (text responses only):

chat:
discord:
bot_token_env: DISCORD_BOT_TOKEN
output:
tool_results: false
system_status: false
errors: false

Full visibility (all message types):

chat:
discord:
bot_token_env: DISCORD_BOT_TOKEN
output:
tool_results: true
tool_result_max_length: 500
system_status: true
result_summary: true
errors: true

herdctl uses environment variables for Discord tokens to keep secrets out of configuration files.

Use a consistent naming pattern for your bot tokens:

Terminal window
# Pattern: {AGENT_NAME}_DISCORD_TOKEN
export SUPPORT_DISCORD_TOKEN="your-support-bot-token"
export CODER_DISCORD_TOKEN="your-coder-bot-token"
export MARKETING_DISCORD_TOKEN="your-marketing-bot-token"

Add to ~/.bashrc, ~/.zshrc, or equivalent:

Terminal window
export SUPPORT_DISCORD_TOKEN="your-token-here"

Then reload:

Terminal window
source ~/.bashrc # or ~/.zshrc

In your agent YAML, reference the environment variable name (not the value):

chat:
discord:
bot_token_env: SUPPORT_DISCORD_TOKEN # The variable NAME

herdctl reads the token from process.env.SUPPORT_DISCORD_TOKEN at runtime.

Discord IDs are unique 17-19 digit numbers. You’ll need IDs for servers (guilds), channels, and users.

  1. Open Discord (desktop or web app)

  2. Go to User Settings (gear icon near your username)

  3. Navigate to App Settings > Advanced

  4. Enable Developer Mode

With Developer Mode enabled, right-click on any server, channel, or user to see a Copy ID option:

ItemHow to Copy
Server IDRight-click the server icon in the sidebar > Copy Server ID
Channel IDRight-click the channel name > Copy Channel ID
User IDRight-click a user’s name > Copy User ID
Message IDRight-click a message > Copy Message ID
guilds:
- id: "1234567890123456789" # Server ID (18 digits)
channels:
- id: "9876543210987654321" # Channel ID (19 digits)
Terminal window
herdctl start

Look for connection messages in the logs:

[support-agent] Connecting to Discord...
[support-agent] Connected to Discord: SupportBot#1234
[support-agent] Slash commands registered successfully

The bot should appear online in your Discord server with the configured presence:

SupportBot - Watching for support requests

In a channel configured with mode: mention:

You: @SupportBot How do I reset my password?
SupportBot: To reset your password, follow these steps...

In a channel configured with mode: auto:

You: How do I reset my password?
SupportBot: To reset your password, follow these steps...

herdctl automatically registers slash commands for every Discord-enabled agent:

CommandDescription
/helpShow available commands and usage
/pingQuick health check
/configShow runtime-relevant agent configuration
/toolsShow allowed/denied tools and MCP servers
/usageShow last run stats and cumulative session totals
/skillsList discovered skills for this agent
/skillTrigger a skill (with autocomplete)
/statusShow bot connection status and session info
/sessionShow current session and run state for this channel
/resetClear conversation context and start fresh
/newAlias for starting a fresh conversation
/stopStop the active run in this channel
/cancelAlias for /stop
/retryRetry the last prompt in this channel

Discord slash commands are not regular chat messages. Type / in the message box, then pick the command under your bot’s app name in Discord’s command picker. Discord sends this as an interaction event (not a normal message), which herdctl handles via the command manager.

Try them in any channel where the bot is active:

/status

Shows available commands and basic usage information:

/help

Example output:

🤖 Support Bot Commands
/help - Show this message
/usage - Show latest run usage
/skills - List discovered skills
/status - Show bot status and stats
/reset - Clear conversation context
Chat with me:
• @SupportBot your question - In channels
• Just type in DMs - Direct messages

Shows detailed connection status and statistics:

/status

Example output:

🟢 Support Bot Status
Connected: Yes
Uptime: 2h 34m
Session: Active (expires in 21h)
Stats:
• Messages received: 47
• Responses sent: 43
• Current channel: #support

Clears the conversation context for the current channel:

/reset

Example output:

✨ Conversation reset! Starting fresh.

Use /reset when:

  • The bot seems confused or stuck on a previous topic
  • You want to start a completely new conversation
  • The session has accumulated too much irrelevant context

If DMs are enabled, send a direct message to the bot:

You (DM): Hello!
SupportBot: Hello! How can I help you today?

You can have multiple agents (each with their own bot) in the same Discord server. This is useful for specialized agents:

agents/support-agent.yaml
name: support-agent
chat:
discord:
bot_token_env: SUPPORT_DISCORD_TOKEN
guilds:
- id: "123456789012345678"
channels:
- id: "support-channel-id"
name: "#support"
mode: mention
# agents/coder-agent.yaml
name: coder-agent
chat:
discord:
bot_token_env: CODER_DISCORD_TOKEN
guilds:
- id: "123456789012345678" # Same server
channels:
- id: "dev-channel-id"
name: "#dev-chat"
mode: auto
  1. Use distinct bot names and avatars - Help users identify which bot they’re addressing

  2. Use mention mode in shared channels - Prevents bots from responding to each other or creating confusion

  3. Dedicate channels when possible - Assign specific channels to specific bots with auto mode

  4. Document bot purposes - Add channel topics explaining which bot handles what

ScenarioRecommendation
Two bots in same channelUse mode: mention for both
Bot in dedicated channelUse mode: auto
Support + Dev botsSeparate channels or mention mode

Discord chat integration maintains conversation context so your agent can have multi-turn conversations and “remember” what was discussed.

  • Scope: Sessions are per-channel (or per-DM conversation)
  • Identity: Session ID is based on channel ID
  • Expiry: Sessions expire after session_expiry_hours (default: 24 hours)
  • Persistence: Sessions survive bot restarts within the expiry window

When a user sends a message, the agent receives:

  1. The current message as the prompt
  2. Recent conversation history from the session
  3. The channel/user context

This allows natural conversations:

User: What's the current price of the Hyken chair?
Bot: The Hyken chair is currently $189 at Staples.
User: When did you last check?
Bot: I checked prices 2 hours ago at 10:30 AM.
User: Is that below my target?
Bot: Yes! Your target is $200, so $189 is $11 below target.

The bot remembers the chair and target price from earlier in the conversation.

chat:
discord:
bot_token_env: DISCORD_BOT_TOKEN
session_expiry_hours: 24 # Default: 24 hours

Choose expiry based on your use case:

Use CaseRecommended Expiry
Support bot24-48 hours
Quick Q&A1-4 hours
Long-running projects72+ hours
Stateless responses1 hour

Users can clear their session context using /reset:

/reset

This is useful when:

  • The bot is confused about context from earlier
  • Starting a completely new topic
  • Testing fresh conversation flows

Control how many recent messages are included as context:

guilds:
- id: "123456789012345678"
channels:
- id: "987654321098765432"
mode: mention
context_messages: 10 # Include last 10 messages

More context = better continuity but higher token usage.

ScenarioRecommended Mode
Shared channel with humansmention
Shared channel with other botsmention
Dedicated support channelauto
Direct messagesauto
High-traffic general channelmention

For multiple agents in the same server:

  1. Dedicated channels: Give each bot its own channel with auto mode

    #support → SupportBot (auto)
    #dev-help → CoderBot (auto)
  2. Shared channels: Use mention mode so users choose which bot to address

    #general → SupportBot (mention) + CoderBot (mention)

Open DMs (friendly bot):

dm:
enabled: true
mode: auto

Restricted DMs (team only):

dm:
enabled: true
mode: auto
allowlist:
- "user-id-1"
- "user-id-2"

No DMs (channel-only):

dm:
enabled: false

Block specific users:

dm:
enabled: true
mode: auto
blocklist:
- "spam-user-id"

Discord has rate limits on message sending. To avoid issues:

  1. Don’t use auto mode in high-traffic channels - Use mention mode instead
  2. Keep responses concise - Avoid very long multi-paragraph responses
  3. Reduce context_messages for busy channels - Lower token usage means faster responses

If you see rate limit warnings in logs, consider:

  • Switching busy channels to mention mode
  • Reducing session expiry to limit context size
  • Using shorter context_messages values

Cause: The environment variable specified in bot_token_env is not set or is empty.

Solution:

Terminal window
# Check if the variable is set
echo $SUPPORT_DISCORD_TOKEN
# Set it if missing
export SUPPORT_DISCORD_TOKEN="your-token-here"

Cause: Message Content Intent is not enabled in the Discord Developer Portal.

Solution:

  1. Go to Discord Developer Portal
  2. Select your application
  3. Go to Bot > Privileged Gateway Intents
  4. Enable Message Content Intent
  5. Save changes

”Missing Access” or “Missing Permissions”

Section titled “”Missing Access” or “Missing Permissions””

Cause: The bot lacks required permissions in the channel.

Solution:

  1. Check that the bot role has Send Messages, Read Message History permissions
  2. Check channel-specific permission overrides
  3. Re-invite the bot with correct permissions

Cause: herdctl isn’t running or connection failed.

Solution:

  1. Start herdctl: herdctl start
  2. Check logs for connection errors
  3. Verify token is valid (not expired or reset)

Cause: Various configuration issues.

Checklist:

  • Is the channel ID correct in the config?
  • Is the mode appropriate? (mention requires @mention)
  • Is Message Content Intent enabled?
  • Check logs for “messageIgnored” events

Cause: The bot token is incorrect or has been reset.

Solution:

  1. Go to Discord Developer Portal
  2. Navigate to your application’s Bot section
  3. Click Reset Token
  4. Update your environment variable with the new token

Enable verbose logging to troubleshoot issues:

chat:
discord:
bot_token_env: SUPPORT_DISCORD_TOKEN
log_level: verbose # Shows detailed debug information

Verbose logs include:

  • All received messages and whether they were processed
  • Connection state changes
  • Rate limit events
  • Channel configuration resolution

Use the /status slash command in Discord to check the bot’s connection status and statistics.

Discord rate limits are handled automatically by the connector. If you see frequent rate limit warnings:

  1. Reduce message frequency
  2. Avoid rapid-fire responses
  3. Consider using shorter context windows (context_messages)

Rate limit events are logged at the standard level:

[support-agent] Rate limited by Discord API: { route: '/channels/123/messages', timeToReset: 5000 }