- Replace python-dotenv with config.json env.vars block + \ substitution - Add models section for per-task model routing (heartbeat, subagent, default) - Heartbeat/subagent tasks can use different models/providers than main chat - Remove python-dotenv from dependencies - Update all docs to reflect new config approach - Reorganize docs into project/ and research/ subdirectories
318 lines
9.0 KiB
Markdown
318 lines
9.0 KiB
Markdown
# Discord Bot Setup Guide
|
|
|
|
> Complete guide to creating a Discord bot and connecting it to Aetheel.
|
|
|
|
---
|
|
|
|
## Table of Contents
|
|
|
|
1. [Overview](#overview)
|
|
2. [Create a Discord Application](#step-1-create-a-discord-application)
|
|
3. [Create the Bot](#step-2-create-the-bot)
|
|
4. [Enable Privileged Intents](#step-3-enable-privileged-intents)
|
|
5. [Invite the Bot to Your Server](#step-4-invite-the-bot-to-your-server)
|
|
6. [Configure Aetheel](#step-5-configure-aetheel)
|
|
7. [Run and Test](#step-6-run-and-test)
|
|
8. [Troubleshooting](#troubleshooting)
|
|
9. [Architecture Reference](#architecture-reference)
|
|
|
|
---
|
|
|
|
## Overview
|
|
|
|
Aetheel connects to Discord using the **Gateway API** via `discord.py`, which means:
|
|
- ✅ **No public URL needed** — works behind firewalls and NAT
|
|
- ✅ **No webhook setup** — Discord pushes events via WebSocket
|
|
- ✅ **Real-time** — instant message delivery
|
|
- ✅ **DMs + @mentions** — responds in both
|
|
|
|
### What You'll Need
|
|
|
|
| Item | Description |
|
|
|------|-------------|
|
|
| **Discord Account** | With access to a server where you have Manage Server permissions |
|
|
| **Bot Token** | From the Discord Developer Portal |
|
|
| **Python 3.14+** | Runtime for the Aetheel service |
|
|
|
|
---
|
|
|
|
## Step 1: Create a Discord Application
|
|
|
|
1. Go to [https://discord.com/developers/applications](https://discord.com/developers/applications)
|
|
2. Click **"New Application"**
|
|
3. Enter a name: `Aetheel` (or any name you prefer)
|
|
4. Accept the Terms of Service
|
|
5. Click **"Create"**
|
|
|
|
You'll be taken to your application's **General Information** page.
|
|
|
|
---
|
|
|
|
## Step 2: Create the Bot
|
|
|
|
1. Navigate to **Bot** in the left sidebar
|
|
2. The bot user is created automatically with your application
|
|
3. Click **"Reset Token"** to generate a new bot token
|
|
4. **⚠️ Copy the token now!** You won't be able to see it again.
|
|
- Save it somewhere safe — this is your `DISCORD_BOT_TOKEN`
|
|
|
|
### Optional: Bot Settings
|
|
|
|
On the same Bot page, you can configure:
|
|
|
|
| Setting | Recommended | Why |
|
|
|---------|-------------|-----|
|
|
| **Public Bot** | OFF | Only you can invite it to servers |
|
|
| **Requires OAuth2 Code Grant** | OFF | Simpler invite flow |
|
|
|
|
---
|
|
|
|
## Step 3: Enable Privileged Intents
|
|
|
|
Still on the **Bot** page, scroll down to **Privileged Gateway Intents**.
|
|
|
|
Enable the following:
|
|
|
|
| Intent | Required | Purpose |
|
|
|--------|----------|---------|
|
|
| **Message Content Intent** | ✅ Yes | Read the text content of messages |
|
|
| **Server Members Intent** | Optional | Resolve member display names |
|
|
| **Presence Intent** | No | Not needed |
|
|
|
|
> **Important:** The Message Content Intent is required. Without it, the bot will receive empty message content for guild messages.
|
|
|
|
Click **"Save Changes"**.
|
|
|
|
---
|
|
|
|
## Step 4: Invite the Bot to Your Server
|
|
|
|
1. Navigate to **OAuth2** → **URL Generator** in the left sidebar
|
|
2. Under **Scopes**, check: `bot`
|
|
3. Under **Bot Permissions**, check:
|
|
|
|
| Permission | Purpose |
|
|
|------------|---------|
|
|
| **Send Messages** | Reply to users |
|
|
| **Read Message History** | Context for conversations |
|
|
| **View Channels** | See channels the bot is in |
|
|
|
|
4. Copy the **Generated URL** at the bottom
|
|
5. Open the URL in your browser
|
|
6. Select the server you want to add the bot to
|
|
7. Click **"Authorize"**
|
|
|
|
The bot should now appear in your server's member list (offline until you start Aetheel).
|
|
|
|
---
|
|
|
|
## Step 5: Configure Aetheel
|
|
|
|
### Option A: Using config.json (recommended)
|
|
|
|
Edit `~/.aetheel/config.json` and add your token to the `env.vars` block:
|
|
|
|
```json
|
|
{
|
|
"env": {
|
|
"vars": {
|
|
"DISCORD_BOT_TOKEN": "your-discord-bot-token-here"
|
|
}
|
|
},
|
|
"discord": {
|
|
"enabled": true,
|
|
"bot_token": "${DISCORD_BOT_TOKEN}"
|
|
}
|
|
}
|
|
```
|
|
|
|
### Option B: Export environment variable
|
|
|
|
```bash
|
|
export DISCORD_BOT_TOKEN="your-discord-bot-token-here"
|
|
```
|
|
|
|
---
|
|
|
|
## Step 6: Run and Test
|
|
|
|
### Install dependencies
|
|
|
|
```bash
|
|
uv sync
|
|
# or: pip install -r requirements.txt
|
|
```
|
|
|
|
This will install `discord.py` along with the other dependencies.
|
|
|
|
### Run the bot
|
|
|
|
```bash
|
|
# Discord only
|
|
uv run python main.py --discord
|
|
|
|
# Discord + Slack together
|
|
uv run python main.py --discord
|
|
|
|
# Discord with Claude Code runtime
|
|
uv run python main.py --discord --claude
|
|
|
|
# Test mode (echo handler, no AI)
|
|
uv run python main.py --discord --test
|
|
|
|
# Debug logging
|
|
uv run python main.py --discord --log DEBUG
|
|
```
|
|
|
|
### Verify it's working
|
|
|
|
1. Check the console — you should see:
|
|
```
|
|
Aetheel Discord Adapter
|
|
Bot: @Aetheel (123456789)
|
|
Guilds: My Server
|
|
```
|
|
2. In Discord, go to a channel where the bot is present
|
|
3. Type `@Aetheel help` — you should see the help response
|
|
4. Type `@Aetheel status` — you should see the bot's status
|
|
5. Send a DM to the bot — it should respond directly
|
|
|
|
### How the bot responds
|
|
|
|
| Context | Trigger | Session Isolation |
|
|
|---------|---------|-------------------|
|
|
| **Guild channel** | @mention only | Per-channel |
|
|
| **DM** | Any message | Per-DM channel |
|
|
|
|
---
|
|
|
|
## Troubleshooting
|
|
|
|
### ❌ "Discord bot token is required"
|
|
|
|
**Problem:** `DISCORD_BOT_TOKEN` is not set or empty.
|
|
|
|
**Fix:**
|
|
1. Check your `config.json` has the token in `env.vars`
|
|
2. Make sure there are no extra spaces or quotes
|
|
3. Verify the token is from the Bot page, not the application client secret
|
|
|
|
### ❌ Bot comes online but doesn't respond to messages
|
|
|
|
**Problem:** Message Content Intent is not enabled.
|
|
|
|
**Fix:**
|
|
1. Go to [Developer Portal](https://discord.com/developers/applications) → your app → **Bot**
|
|
2. Scroll to **Privileged Gateway Intents**
|
|
3. Enable **Message Content Intent**
|
|
4. Save and restart Aetheel
|
|
|
|
### ❌ Bot doesn't respond in guild channels
|
|
|
|
**Problem:** You're not @mentioning the bot.
|
|
|
|
**Fix:**
|
|
- In guild channels, the bot only responds to @mentions: `@Aetheel hello`
|
|
- In DMs, the bot responds to any message — no @mention needed
|
|
|
|
### ❌ "Improper token has been passed"
|
|
|
|
**Problem:** The token is malformed or from the wrong place.
|
|
|
|
**Fix:**
|
|
1. Go to **Bot** page in the Developer Portal
|
|
2. Click **"Reset Token"** to generate a fresh one
|
|
3. Copy the full token (it's a long string)
|
|
4. Make sure you're using the Bot token, not the Client ID or Client Secret
|
|
|
|
### ❌ "discord.errors.PrivilegedIntentsRequired"
|
|
|
|
**Problem:** You're requesting intents that aren't enabled in the portal.
|
|
|
|
**Fix:**
|
|
1. Go to **Bot** → **Privileged Gateway Intents**
|
|
2. Enable **Message Content Intent**
|
|
3. Save changes and restart
|
|
|
|
### ❌ Bot is offline in the member list
|
|
|
|
**Problem:** Aetheel isn't running, or the token is wrong.
|
|
|
|
**Fix:**
|
|
1. Start Aetheel with `--discord` flag
|
|
2. Check the console for connection errors
|
|
3. Verify the token in `config.json` matches the one in the Developer Portal
|
|
|
|
### ❌ "Missing Permissions" when sending messages
|
|
|
|
**Problem:** The bot doesn't have Send Messages permission in that channel.
|
|
|
|
**Fix:**
|
|
1. Check the channel's permission overrides for the bot role
|
|
2. Re-invite the bot with the correct permissions (see Step 4)
|
|
3. Or manually grant the bot's role Send Messages in Server Settings → Roles
|
|
|
|
---
|
|
|
|
## Architecture Reference
|
|
|
|
### How It Works
|
|
|
|
```
|
|
┌──────────────────────┐
|
|
│ Your Discord │
|
|
│ Server │
|
|
│ │
|
|
│ #general │
|
|
│ #random │
|
|
│ DMs │
|
|
└──────┬───────────────┘
|
|
│ WebSocket (Gateway API)
|
|
│
|
|
┌──────▼───────────────┐
|
|
│ Aetheel Discord │
|
|
│ Adapter │
|
|
│ │
|
|
│ • Token resolution │
|
|
│ • @mention filter │
|
|
│ • DM handling │
|
|
│ • Message chunking │
|
|
│ (2000 char limit) │
|
|
│ • Async dispatch │
|
|
│ via to_thread() │
|
|
└──────┬───────────────┘
|
|
│ Callback
|
|
│
|
|
┌──────▼───────────────┐
|
|
│ Message Handler │
|
|
│ │
|
|
│ • Echo (test) │
|
|
│ • AI (OpenCode / │
|
|
│ Claude Code) │
|
|
│ • Memory + Skills │
|
|
│ • Action tags │
|
|
└──────────────────────┘
|
|
```
|
|
|
|
### Key Files
|
|
|
|
| File | Purpose |
|
|
|------|---------|
|
|
| `adapters/discord_adapter.py` | Core Discord adapter (Gateway, send/receive) |
|
|
| `adapters/base.py` | Abstract base class all adapters implement |
|
|
| `main.py` | Entry point — `--discord` flag enables this adapter |
|
|
| `~/.aetheel/config.json` | Your Discord token (in `env.vars` block) |
|
|
|
|
### Comparison with Other Adapters
|
|
|
|
| Feature | Slack | Telegram | Discord |
|
|
|---------|-------|----------|---------|
|
|
| **Library** | `slack_bolt` | `python-telegram-bot` | `discord.py` |
|
|
| **Connection** | Socket Mode (WebSocket) | Long polling | Gateway (WebSocket) |
|
|
| **Auth** | Bot Token + App Token | Single Bot Token | Single Bot Token |
|
|
| **Trigger (channels)** | @mention | @mention | @mention |
|
|
| **Trigger (DMs)** | Any message | Any message | Any message |
|
|
| **Text Limit** | 4000 chars | 4096 chars | 2000 chars |
|
|
| **Threading** | Native threads | Reply-to-message | N/A (per-channel) |
|
|
| **Session Isolation** | Per-thread | Per-chat | Per-channel |
|