AGENTS-COLLECTION ADD-DISCORD

Add Discord Channel

install
source · Clone the upstream repo
git clone https://github.com/mk-knight23/AGENTS-COLLECTION
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/mk-knight23/AGENTS-COLLECTION "$T" && mkdir -p ~/.claude/skills && cp -r "$T/SKILLS/NANOCLAW/ADD-DISCORD" ~/.claude/skills/mk-knight23-agents-collection-add-discord && rm -rf "$T"
manifest: SKILLS/NANOCLAW/ADD-DISCORD/SKILL.md
source content

Add Discord Channel

This skill adds Discord support to NanoClaw using the skills engine for deterministic code changes, then walks through interactive setup.

Phase 1: Pre-flight

Check if already applied

Read

.nanoclaw/state.yaml
. If
discord
is in
applied_skills
, skip to Phase 3 (Setup). The code changes are already in place.

Ask the user

Use

AskUserQuestion
to collect configuration:

AskUserQuestion: Do you have a Discord bot token, or do you need to create one?

If they have one, collect it now. If not, we'll create one in Phase 3.

Phase 2: Apply Code Changes

Run the skills engine to apply this skill's code package. The package files are in this directory alongside this SKILL.md.

Initialize skills system (if needed)

If

.nanoclaw/
directory doesn't exist yet:

npx tsx scripts/apply-skill.ts --init

Or call

initSkillsSystem()
from
skills-engine/migrate.ts
.

Apply the skill

npx tsx scripts/apply-skill.ts .claude/skills/add-discord

This deterministically:

  • Adds
    src/channels/discord.ts
    (DiscordChannel class with self-registration via
    registerChannel
    )
  • Adds
    src/channels/discord.test.ts
    (unit tests with discord.js mock)
  • Appends
    import './discord.js'
    to the channel barrel file
    src/channels/index.ts
  • Installs the
    discord.js
    npm dependency
  • Records the application in
    .nanoclaw/state.yaml

If the apply reports merge conflicts, read the intent file:

  • modify/src/channels/index.ts.intent.md
    — what changed and invariants

Validate code changes

npm test
npm run build

All tests must pass (including the new Discord tests) and build must be clean before proceeding.

Phase 3: Setup

Create Discord Bot (if needed)

If the user doesn't have a bot token, tell them:

I need you to create a Discord bot:

  1. Go to the Discord Developer Portal
  2. Click New Application and give it a name (e.g., "Andy Assistant")
  3. Go to the Bot tab on the left sidebar
  4. Click Reset Token to generate a new bot token — copy it immediately (you can only see it once)
  5. Under Privileged Gateway Intents, enable:
    • Message Content Intent (required to read message text)
    • Server Members Intent (optional, for member display names)
  6. Go to OAuth2 > URL Generator:
    • Scopes: select
      bot
    • Bot Permissions: select
      Send Messages
      ,
      Read Message History
      ,
      View Channels
    • Copy the generated URL and open it in your browser to invite the bot to your server

Wait for the user to provide the token.

Configure environment

Add to

.env
:

DISCORD_BOT_TOKEN=<their-token>

Channels auto-enable when their credentials are present — no extra configuration needed.

Sync to container environment:

mkdir -p data/env && cp .env data/env/env

The container reads environment from

data/env/env
, not
.env
directly.

Build and restart

npm run build
launchctl kickstart -k gui/$(id -u)/com.nanoclaw

Phase 4: Registration

Get Channel ID

Tell the user:

To get the channel ID for registration:

  1. In Discord, go to User Settings > Advanced > Enable Developer Mode
  2. Right-click the text channel you want the bot to respond in
  3. Click Copy Channel ID

The channel ID will be a long number like

1234567890123456
.

Wait for the user to provide the channel ID (format:

dc:1234567890123456
).

Register the channel

Use the IPC register flow or register directly. The channel ID, name, and folder name are needed.

For a main channel (responds to all messages):

registerGroup("dc:<channel-id>", {
  name: "<server-name> #<channel-name>",
  folder: "discord_main",
  trigger: `@${ASSISTANT_NAME}`,
  added_at: new Date().toISOString(),
  requiresTrigger: false,
  isMain: true,
});

For additional channels (trigger-only):

registerGroup("dc:<channel-id>", {
  name: "<server-name> #<channel-name>",
  folder: "discord_<channel-name>",
  trigger: `@${ASSISTANT_NAME}`,
  added_at: new Date().toISOString(),
  requiresTrigger: true,
});

Phase 5: Verify

Test the connection

Tell the user:

Send a message in your registered Discord channel:

  • For main channel: Any message works
  • For non-main: @mention the bot in Discord

The bot should respond within a few seconds.

Check logs if needed

tail -f logs/nanoclaw.log

Troubleshooting

Bot not responding

  1. Check
    DISCORD_BOT_TOKEN
    is set in
    .env
    AND synced to
    data/env/env
  2. Check channel is registered:
    sqlite3 store/messages.db "SELECT * FROM registered_groups WHERE jid LIKE 'dc:%'"
  3. For non-main channels: message must include trigger pattern (@mention the bot)
  4. Service is running:
    launchctl list | grep nanoclaw
  5. Verify the bot has been invited to the server (check OAuth2 URL was used)

Bot only responds to @mentions

This is the default behavior for non-main channels (

requiresTrigger: true
). To change:

  • Update the registered group's
    requiresTrigger
    to
    false
  • Or register the channel as the main channel

Message Content Intent not enabled

If the bot connects but can't read messages, ensure:

  1. Go to Discord Developer Portal
  2. Select your application > Bot tab
  3. Under Privileged Gateway Intents, enable Message Content Intent
  4. Restart NanoClaw

Getting Channel ID

If you can't copy the channel ID:

  • Ensure Developer Mode is enabled: User Settings > Advanced > Developer Mode
  • Right-click the channel name in the server sidebar > Copy Channel ID

After Setup

The Discord bot supports:

  • Text messages in registered channels
  • Attachment descriptions (images, videos, files shown as placeholders)
  • Reply context (shows who the user is replying to)
  • @mention translation (Discord
    <@botId>
    → NanoClaw trigger format)
  • Message splitting for responses over 2000 characters
  • Typing indicators while the agent processes