InitRunner

Discord Bot

Get a Discord bot agent running in five steps. For the full trigger reference, see Triggers.

Old envelopes still load. Convert them with initrunner doctor --fix PATH. See Envelope Migration.

Prerequisites

  • InitRunner installed (pip install initrunner or uv tool install initrunner)
  • An API key for your provider (OPENAI_API_KEY, ANTHROPIC_API_KEY, etc.)
  • The Discord optional dependency: uv sync --extra discord (or pip install initrunner[discord])

Step 1: Create a Discord Application

  1. Go to the Discord Developer Portal.
  2. Click New Application, give it a name, and click Create.
  3. Go to the Bot tab in the left sidebar.
  4. Click Reset Token and copy the token — you'll need it in Step 3.

Step 2: Enable Message Content Intent

Still on the Bot tab:

  1. Scroll down to Privileged Gateway Intents.
  2. Enable Message Content Intent.
  3. Click Save Changes.

Without this intent the bot connects but silently receives empty message bodies.

Step 3: Set Environment Variables

export DISCORD_BOT_TOKEN="your-token-here"
export OPENAI_API_KEY="your-api-key"   # or your provider's key

Or, to persist keys across sessions, add them to ~/.initrunner/.env:

DISCORD_BOT_TOKEN=your-token-here
OPENAI_API_KEY=your-api-key

A .env file next to your role.yaml also works. Running initrunner setup writes the provider key there automatically. Existing environment variables always take precedence over .env values.

Step 4: Invite the Bot to Your Server

  1. Go to the OAuth2 tab in the Developer Portal.
  2. Under OAuth2 URL Generator, select the bot scope.
  3. Under Bot Permissions, select:
    • Send Messages
    • Read Message History
  4. Copy the generated URL and open it in your browser.
  5. Select the server you want to add the bot to and click Authorize.

Step 5: Create a Role and Run

Create a role.yaml:

name: discord-assistant
description: A Discord bot that responds to DMs and @mentions
model:
  provider: openai
  name: gpt-5-mini
  temperature: 0.1
  max_tokens: 4096
prompt: |
  You are a helpful assistant responding to Discord messages.
  Keep responses concise.
triggers:
  - type: discord
    token_env: DISCORD_BOT_TOKEN
guardrails:
  max_tokens_per_run: 50000
  daemon_daily_token_budget: 200000

Start the daemon:

initrunner run role.yaml --daemon

You should see Discord bot connected in the logs.

Quick alternative: the bundled starter

To try a bot without writing a role file, run the starter that ships with InitRunner:

initrunner run discord --daemon

It needs DISCORD_BOT_TOKEN and a provider key.

To customise it, copy it out and edit the YAML:

initrunner examples copy discord -o ./my-bot/
initrunner run ./my-bot/role.yaml --daemon

The starter has no allowlist. Like the ephemeral bot it replaces, it answers anyone who can reach it. Add allowed_user_ids to the trigger before you invite it to a server.

--bot discord was removed in v2026.8.11. It never read triggers from the role: it built one from CLI arguments, dropping token_env, allow_all, channel_ids, allowed_roles, and --allowed-users along the way. With no allowlist flags the result had allow_all: false and empty lists, which the adapter reads as no check at all. --daemon builds the trigger from YAML and adds hot reload, retry, and circuit breaking.

One behavior difference worth knowing: the starter runs a single agent turn per message, where run --bot forced the autonomous loop.

For production, use the role.yaml approach above for access control and budgets. See CLI Reference.

Testing

  • @mention — In a server channel, type @YourBot what time is it?
  • DM — Open a direct message with the bot and send any text.
  • Long responses — Responses over 2000 characters are automatically chunked at newline boundaries.

Configuration Options

All options go under triggers[]:

FieldTypeDefaultDescription
token_envstr"DISCORD_BOT_TOKEN"Environment variable holding the bot token.
channel_idslist[str][]Channel IDs to respond in. Empty = all channels. Does not affect DMs.
allowed_roleslist[str][]Server role names required to interact. Empty = allow everyone. DMs are denied when only roles are configured.
allowed_user_idslist[str][]Discord user IDs allowed to interact. Works in both guild channels and DMs.
allow_allboolfalseRespond to anyone even when no allowlist is set. Since v2026.6.5.
prompt_templatestr"{message}"Template for the prompt. {message} is replaced with the user's text.

Example with restrictions:

triggers:
  - type: discord
    token_env: DISCORD_BOT_TOKEN
    channel_ids: ["1234567890"]
    allowed_roles: ["Bot-User", "Admin"]
    allowed_user_ids: ["111222333444555666"]
    prompt_template: "Discord user asks: {message}"

Security and Public Access

By default the bot responds to anyone who can DM it or @mention it in a shared server. This means every member of every server the bot is in can use it. Lock it down before making it available to others:

  • Use allowed_user_ids for the most reliable access control. Unlike allowed_roles, user IDs work in DMs. When both allowed_roles and allowed_user_ids are set, a user ID match grants DM access. To find a user ID: enable Developer Mode (Settings > Advanced), right-click a user > Copy User ID.
  • Use allowed_roles to restrict access to specific server roles. When only roles are configured, DMs are automatically denied (DMs have no role context).
  • Use channel_ids to confine the bot to specific guild channels. channel_ids restricts guild channels only — DMs are not affected.
  • Acknowledge open access. Since v2026.6.5, a bot with no allowlist and allow_all unset logs a loud startup warning that it will respond to any user. Set an allowlist (channel_ids, allowed_roles, or allowed_user_ids) or allow_all: true to silence it. A future release will reject unconfigured bots by default (fail-closed).
  • Set daemon_daily_token_budget in guardrails to cap API costs. Without a budget, a public bot can run up unlimited charges.
  • Keep the bot token secret. Anyone with the token can impersonate the bot. Never commit it to version control — use environment variables or a secrets manager.
  • Limit server exposure. If the bot has access to tools (filesystem, HTTP, shell, etc.), keep it in a private server only. A public server lets strangers invoke those tools through the bot.

Troubleshooting

Bot connects but never responds

The Message Content Intent is not enabled. Go to the Developer Portal > Bot > Privileged Gateway Intents and enable it (see Step 2).

ModuleNotFoundError: No module named 'discord'

The optional dependency is not installed. Run:

uv sync --extra discord
# or
pip install initrunner[discord]

Env var DISCORD_BOT_TOKEN not set

Export the token before starting the daemon:

export DISCORD_BOT_TOKEN="your-token-here"

Bot responds in wrong channels

Set channel_ids to a list of channel ID strings. To get a channel ID, enable Developer Mode in Discord (Settings > Advanced > Developer Mode), then right-click a channel and select Copy Channel ID.

On this page