Skip to content

Discord

Netclaw connects to Discord over the Gateway WebSocket API — outbound connections only, no public URLs needed. You create a Discord bot, give netclaw one token, and it shows up in your server.

  • Netclaw installed and initialized (netclaw init)
  • A Discord server where you have the “Manage Server” permission
  • Developer Mode enabled in Discord (for copying IDs)

Head to discord.com/developers/applications and create a new application.

Discord Applications page

Click New Application, give it a name, and hit Create.

New Application dialog

Go to Bot in the left sidebar. Click Reset Token to generate a bot token and copy it immediately — Discord only shows it once.

Bot settings page

If you lose the token, you can always reset it here, but you’ll need to update your netclaw config with the new value.

Scroll down on the Bot page to Privileged Gateway Intents and enable Message Content. Without this, netclaw receives message events but can’t read their text.

Privileged Gateway Intents with Message Content enabled

Go to OAuth2 > URL Generator. Check the bot scope.

OAuth2 scopes selection

Then select bot permissions:

Bot permissions checklist

Required permissions: Send Messages, Create Public Threads, Send Messages in Threads, Manage Threads, Embed Links, Read Message History, Add Reactions.

Manage Threads is needed so netclaw can rename threads with session titles as conversations progress.

Copy the generated URL at the bottom of the page.

Generated OAuth2 URL

Open it in your browser. Discord asks which server to add the bot to — pick yours and click Continue.

OAuth install approval dialog

Discord then lists the permissions the bot is requesting. Confirm they match the set from step 4 and click Authorize.

Discord OAuth2 permissions confirmation with the Authorize button

The bot appears in your server’s member list once the daemon is running.

Under Installation in the left sidebar, set the install method to None. This prevents users from installing the bot to other servers through Discord’s app directory.

Installation settings set to None

If you want others to install via a link you control, use Discord Provided Link instead.

Installation with Discord Provided Link

Run netclaw config, navigate to Channels, and enable Discord. Enter your bot token when prompted — netclaw stores it encrypted and saves the config automatically.

Terminal window
netclaw config

The Channels area in netclaw config

The Channels area in netclaw config — enable Discord and enter its bot token here (the adapter list also shows Slack and Mattermost).

For scripted or headless installs, store the token with netclaw secrets and edit the config file directly:

Terminal window
netclaw secrets set Discord.BotToken your-bot-token

Then enable Discord in ~/.netclaw/config/netclaw.json:

{
"Discord": {
"Enabled": true,
"DefaultChannelId": "123456789012345678"
}
}

Environment variables work too — useful for Docker and CI:

Terminal window
export NETCLAW_Discord__BotToken="your-bot-token"
export NETCLAW_Discord__Enabled="true"

Enter channel names or IDs (comma-separated) in netclaw config → Channels. Netclaw resolves each entry against the Discord API to its canonical channel ID before saving. The stored AllowedChannelIds field holds IDs, not display names; display names are shown dynamically in the config UI. Names that cannot be resolved remain in AllowedChannelIds verbatim and are flagged with a warning — they are inert until the bot can see the channel, at which point a background refresh rewrites them to canonical IDs. Entries added one-at-a-time via the add-channel flow are rejected at entry time if they do not resolve. A genuine auth or network failure blocks the entire save.

FieldTypeDefaultDescription
EnabledboolfalseTurn on Discord
BotTokenstringBot token from the Developer Portal. Store with netclaw secrets set.
DefaultChannelIdstringChannel ID for the default channel
MentionOnlybooltrueOnly respond when @-mentioned
AllowDirectMessagesboolfalseAccept DMs
MentionRequiredInDmboolfalseRequire @-mention even in DMs
AllowedChannelIdsstring[][]Channel allow-list. Empty + no default = all channel messages denied
AllowedUserIdsstring[][]User allow-list. Empty = everyone in allowed channels is accepted
ChannelAudiencesobject{}Per-channel audience overrides. Keys are channel IDs or "dm". Values: "personal", "team", "public".

The token lives in ~/.netclaw/config/secrets.json (encrypted at rest).

Discord ACL is default-deny. Three settings decide who talks to the bot and where.

The bot only responds in channels that pass the allow-list:

  • DefaultChannelId allows one channel
  • AllowedChannelIds allows multiple
  • If both are empty, every channel message is denied. This is the number one setup mistake.
{
"Discord": {
"DefaultChannelId": "123456789012345678",
"AllowedChannelIds": ["234567890123456789", "345678901234567890"]
}
}

Finding channel IDs: right-click a channel in Discord with Developer Mode on, click “Copy Channel ID.”

AllowedUserIds restricts who gets responses:

  • Empty (default) — everyone in allowed channels is accepted
  • Non-empty — only listed user IDs get responses, everyone else is silently dropped

Finding user IDs: right-click a user in Discord with Developer Mode on, click “Copy User ID.”

Users in AllowedUserIds are treated as TrustedInternal by the security model. Everyone else is UntrustedExternal.

DMs are off by default:

{
"Discord": {
"AllowDirectMessages": true
}
}

With DMs on, users can just type normally — MentionRequiredInDm defaults to false, so no @-mention needed. Each user gets a single long-running DM session (unlike channels, where each root message starts a new session).

Override the default audience per-channel with ChannelAudiences:

{
"Discord": {
"ChannelAudiences": {
"123456789012345678": "team",
"dm": "personal"
}
}
}

The "dm" key is reserved — it matches every direct message rather than a channel ID. A channel-ID entry takes precedence over it. An unrecognized audience value is rejected outright: the message is denied rather than falling back to a default.

Security Model has the full breakdown on how audiences map to tools and permissions.

When someone messages the bot in a regular channel, netclaw creates a public thread on its first reply and continues the conversation there. The thread starts as “Netclaw” and netclaw renames it once the LLM generates a session title.

Thread replies don’t need a @-mention — if there’s an active session in the thread, the bot responds to everything.

Idle conversations are freed from memory after 2 hours (individual sessions after 1 hour, unless an approval request is pending). On daemon restart, up to 200 messages of thread history are backfilled so in-progress conversations resume.

MentionOnly: true (the default) means the bot ignores messages that don’t @-mention it. Two exceptions:

  • Thread replies — if a thread already has an active session, the bot responds without needing a mention
  • Daemon restart recovery — if the daemon restarts and a user continues a thread, the session is re-created from the thread’s message history

Netclaw strips the @-mention before passing text to the LLM.

Discord natively renders markdown — bold, italic, code blocks, headers, lists, links. Responses longer than 2,000 characters are split at newline boundaries.

When a tool call needs approval, netclaw posts an interactive button prompt in the thread. The prompt shows the tool name, action, and pattern(s). The full set is five buttons: Once, This chat, Always here, Always anywhere, and Deny — though Always here is omitted when the working directory is a session scratch path or too shallow for a folder-scoped grant. Always anywhere grants the command everywhere, so use it sparingly. netclaw shows fewer buttons when some don’t apply — a command it can’t cleanly parse (shell control flow, or unbalanced quotes) drops to just Once and Deny. Only the user who triggered the request can approve.

If posting the button prompt fails, netclaw falls back to a text prompt where you reply with the letter shown next to each option.

After a decision, netclaw updates the original message in-place with a checkmark or denied icon.

Discord reminders deliver to guild text channels only — user DMs are not supported as reminder targets. Accepted formats:

  • <#123456789012345678> — Discord channel mention
  • channel:123456789012345678 — explicit channel prefix

The LLM can start a conversation with the generic send_channel_message tool — pass channel_key: discord and a destination (a guild text channel or a DM) resolved via lookup_channel_user or lookup_channel_destination. ACL rules still apply.

The bot drops: empty messages (no text, no attachments), other bots’ messages, its own messages, DMs when AllowDirectMessages is off, and un-mentioned channel messages when MentionOnly is on and there’s no active thread.

Messages over 4,000 characters are truncated.

Restart the daemon and check status:

Terminal window
netclaw daemon stop && netclaw daemon start
netclaw status

Discord should show connected. If it shows disabled or disconnected, check the troubleshooting guide.

Then @-mention the bot in an allowed channel. If it creates a thread and responds, you’re set.

Common problems and fixes are in Channel Troubleshooting. The hits:

  • Connected but silentAllowedChannelIds is empty and no DefaultChannelId is set, so all traffic gets denied
  • Invalid bot token — HTTP 401 on startup means the token is wrong or was regenerated in the Developer Portal
  • Gateway disconnected — the daemon couldn’t establish a connection. Usually a network issue or Discord outage.
  • Message Content privileged intent not enabled — turn it on under Privileged Gateway Intents in the Developer Portal