Files
Aetheel/docs/project/discord-features.md
tanmay11k 82c2640481 feat: openclaw-style secrets (env.vars + \) and per-task model routing
- 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
2026-02-20 23:49:05 -05:00

8.6 KiB

Discord Advanced Features

All Discord features are config-driven via ~/.aetheel/config.json under the discord key. No code changes needed.


Default Config

{
  "discord": {
    "enabled": false,
    "listen_channels": [],
    "reply_to_mode": "first",
    "history_enabled": true,
    "history_limit": 20,
    "channel_overrides": {},
    "ack_reaction": "👀",
    "typing_indicator": true,
    "reaction_mode": "own",
    "exec_approvals": false,
    "exec_approval_tools": ["Bash", "Write", "Edit"],
    "slash_commands": true,
    "components_enabled": true
  }
}

Reply Threading

Controls whether the bot replies to the user's message using Discord's native reply feature (the quoted message above the response).

"reply_to_mode": "first"
Value Behavior
"off" Plain messages, no reply reference
"first" First chunk of the response replies to the user's message
"all" Every chunk replies to the user's message

If the original message gets deleted before the bot responds, it falls back to a plain message automatically.


Channel History Context

Injects recent channel messages into the AI's system prompt so it has conversational context beyond the current message.

"history_enabled": true,
"history_limit": 20
  • history_enabled — global toggle, default true
  • history_limit — number of recent messages to fetch, default 20
  • History is only fetched for guild channels, not DMs (DMs already have session continuity)
  • Messages are formatted as [username]: content and injected under a "Recent Channel History" section in the system prompt
  • The bot's own messages appear as [assistant]

Per-Channel Overrides

You can enable, disable, or change the limit per channel:

"channel_overrides": {
  "1234567890": {
    "history_enabled": true,
    "history_limit": 50
  },
  "9876543210": {
    "history_enabled": false
  }
}

Keys are Discord channel IDs (strings). Any field you omit falls back to the global default.

Use cases:

  • Disable history in a high-traffic channel to save context window
  • Increase the limit in a project channel where long context matters
  • Disable entirely for a channel where privacy is a concern

Ack Reactions

Adds a reaction emoji to the user's message while the bot is processing, then removes it when the response is sent. Gives immediate visual feedback that the bot received the message.

"ack_reaction": "👀"
  • Set to any valid emoji: "👀", "⏳", "🤔", etc.
  • Set to "" (empty string) to disable
  • The reaction is removed automatically after the response is sent
  • If the bot lacks Add Reactions permission in a channel, it silently skips

Typing Indicator

Shows the "Aetheel is typing..." indicator in the channel while the AI processes the message.

"typing_indicator": true
  • true — typing indicator shown during processing (default)
  • false — no typing indicator

The indicator stays active for the entire duration of the AI call. Combined with ack reactions, users get two layers of feedback: the reaction appears instantly, and the typing indicator persists until the response arrives.


Reaction Handling

Controls whether the bot processes emoji reactions as messages to the AI.

"reaction_mode": "own"
Value Behavior
"off" Reactions are ignored entirely
"own" Only reactions on the bot's own messages are processed
"all" Reactions on any message in the channel are processed

When a reaction is processed, it's sent to the AI as:

[Reaction: 👍 on message: <original message text>]

The AI can then respond contextually — for example, a 👎 on a suggestion could prompt the bot to offer alternatives.

Bot reactions and reactions from other bots are always ignored.


Slash Commands

Registers native Discord slash commands that appear in the / menu.

"slash_commands": true

Available Commands

Command Description
/ask <message> Ask Aetheel a question. Shows "thinking..." while processing.
/status Check bot status (same as typing status in chat)
/help Show help (same as typing help in chat)

Commands are synced with Discord on bot startup. First sync can take up to an hour to propagate globally — guild-level commands appear faster.

Set to false to disable slash command registration entirely.

Bot Permissions

For slash commands to work, the bot must be invited with the applications.commands OAuth2 scope in addition to bot. If you originally invited without it, re-invite using:

OAuth2 → URL Generator → Scopes: bot, applications.commands


Interactive Components

Enables the bot to send messages with buttons and select menus.

"components_enabled": true

Components are used internally by:

  • Exec approval prompts (approve/deny buttons)
  • Any future interactive features

The adapter exposes send_components_message() for programmatic use:

adapter.send_components_message(
    channel_id="123456789",
    text="Choose an option:",
    buttons=[
        {"label": "Option A", "style": "primary", "custom_id": "opt_a"},
        {"label": "Option B", "style": "secondary", "custom_id": "opt_b"},
        {"label": "Delete", "style": "danger", "custom_id": "delete"},
    ],
    select_options=[
        {"label": "Python", "value": "python", "description": "Snake language"},
        {"label": "TypeScript", "value": "ts", "description": "JS but typed"},
    ],
    callback=my_callback_fn,
)

Button styles: primary (blurple), secondary (gray), success (green), danger (red).

Set to false to disable — approval prompts and interactive messages fall back to plain text.


Exec Approvals

Adds a human-in-the-loop confirmation step for dangerous AI tool use. When the AI tries to use a gated tool, a button prompt appears in the channel asking the user to approve or deny.

"exec_approvals": false,
"exec_approval_tools": ["Bash", "Write", "Edit"]
  • exec_approvals — master toggle, default false
  • exec_approval_tools — list of tool names that require approval

How It Works

  1. AI decides to use a gated tool (e.g. Bash)
  2. Bot sends an embed with approve/deny buttons:
    ⚠️ Exec Approval Required
    Tool: Bash
    Action: <description of what the AI wants to do>
    [✅ Approve] [❌ Deny]
    
  3. Only the user who sent the original message can click the buttons
  4. If approved, the tool executes normally
  5. If denied or timed out (2 minutes), the action is blocked

Customizing Gated Tools

Add or remove tools from the approval list:

"exec_approval_tools": ["Bash", "Write", "Edit", "WebFetch"]

Tools not in this list are auto-approved. Set the list to [] to approve everything (while keeping the feature enabled for future use).


Listen Channels

Channels where the bot responds to all messages without requiring an @mention.

"listen_channels": ["1234567890", "9876543210"]

In all other guild channels, the bot only responds when @mentioned. DMs always respond to all messages regardless of this setting.

You can also set this via environment variable:

DISCORD_LISTEN_CHANNELS=1234567890,9876543210

Required Bot Permissions

For all features to work, invite the bot with these permissions:

Permission Required For
Send Messages Responding to users
Read Message History History context injection
View Channels Seeing channels
Add Reactions Ack reactions
Use External Emojis Custom ack reaction emojis
Embed Links Exec approval prompts

OAuth2 scopes: bot, applications.commands

Privileged intents (in Developer Portal → Bot):

  • Message Content Intent (required)
  • Server Members Intent (recommended)

Example Configs

Minimal (just the basics)

{
  "discord": {
    "enabled": true
  }
}

Uses all defaults: reply threading on first message, history on, ack 👀, typing on, reactions on own messages, slash commands on.

Privacy-focused

{
  "discord": {
    "enabled": true,
    "history_enabled": false,
    "ack_reaction": "",
    "reaction_mode": "off",
    "slash_commands": false
  }
}

Full control with approvals

{
  "discord": {
    "enabled": true,
    "reply_to_mode": "all",
    "history_limit": 50,
    "ack_reaction": "⏳",
    "exec_approvals": true,
    "exec_approval_tools": ["Bash", "Write", "Edit", "WebFetch"],
    "channel_overrides": {
      "123456789": { "history_limit": 100 },
      "987654321": { "history_enabled": false }
    }
  }
}