Module 2

Slash Commands

Learn how to create slash commands that users can discover and use! Build interactive commands like /help, /ping, and more.

4 sections
Beginner

Learning Objectives

By the end of this module, you will be able to:

Define slash commands in a commands file
Create basic command handlers (/help, /ping)
Handle command parameters and user mentions
Register commands with Towns Protocol
1

Command Definitions

Create a file that defines all your bot's slash commands.

Creating src/commands.ts

This file tells Towns Protocol what commands your bot has. Each command needs a name and description.

src/commands.ts
import type { PlainMessage, SlashCommand } from '@towns-protocol/proto'

const commands = [
  {
    name: 'help',
    description: 'Show bot help and available commands',
  },
  {
    name: 'ping',
    description: 'Check if the bot is responsive',
  },
  {
    name: 'stats',
    description: 'Show community or user stats',
  },
] as const satisfies PlainMessage<SlashCommand>[]

export default commands

Command Naming Tips

  • • Use lowercase, single words (help, ping, stats)
  • • Keep descriptions short and clear
  • • Commands appear in autocomplete when users type "/"

Challenge: Define 3 Commands

Add help, ping, and info commands

2

Basic Command Handlers

Implement handlers that respond when users type your commands.

1. Help Command

The /help command shows users what your bot can do.

/help command
bot.onSlashCommand('help', async (handler, { channelId }) => {
  try {
    await handler.sendMessage(channelId, `
🤖 **Bot Help**

**Available Commands:**
\`/help\` - Show this help message
\`/ping\` - Check bot status
\`/stats\` - View community stats

Type \`/\` to see all commands!
    `)
  } catch (error) {
    console.error('Error in /help:', error)
  }
})

2. Ping Command

The /ping command lets users check if your bot is working.

/ping command
bot.onSlashCommand('ping', async (handler, { channelId }) => {
  try {
    await handler.sendMessage(channelId, '🏓 Pong! Bot is online.')
  } catch (error) {
    console.error('Error in /ping:', error)
  }
})

Error Handling

Always wrap commands in try/catch. This prevents one failing command from crashing your entire bot!

Challenge: Create a Help Command

Make it list /help, /ping, and /stats commands

3

Command Parameters

Handle arguments and user mentions in your commands.

User Mentions

Commands can accept user mentions like /stats @user

/stats with mentions
bot.onSlashCommand('stats', async (handler, { channelId, userId, mentions }) => {
  try {
    if (mentions && mentions.length > 0) {
      // User mentioned someone: /stats @user
      const targetUser = mentions[0]
      await handler.sendMessage(channelId, `
📊 **Stats for ${targetUser.displayName}**

💬 Messages: 150
👍 Reactions: 45
📅 Joined: 2 weeks ago
      `)
    } else {
      // No mention: show community stats
      await handler.sendMessage(channelId, `
📊 **Community Stats**

👥 Members: 1,234
💬 Messages Today: 567
🔥 Most Active: Alice
      `)
    }
  } catch (error) {
    console.error('Error in /stats:', error)
  }
})

Parameter Structure

  • mentions - Array of mentioned users
  • userId - Who ran the command
  • channelId - Where it was run

Challenge: Stats with Mentions

Show user stats if mentioned, otherwise show community stats

4

Command Registration

Register your commands so users can discover them in Towns.

Step 1: Get Your Bot Token

To register commands, you need your bot's token from Towns:

  1. 1. Open Towns app
  2. 2. Type /bearer-token in any channel
  3. 3. Copy the long token that appears in the side panel
  4. 4. This is your APP_PRIVATE_DATA token

Step 2: Automatic Registration

Your commands are automatically registered when your bot starts! When you initialize your bot with commands, they're synced to Towns:

src/index.ts
// Commands are automatically synced on bot initialization
const bot = await makeTownsBot(privateData, jwtSecret, {
  commands: myCommands // ✨ Automatically registered!
})

// Your bot is now ready with slash commands!
bot.onSlashCommand('help', async (handler, event) => {
  // Handle the command
})

Auto-Discovery

Users can type "/" in Towns and see your commands in autocomplete! They can discover what your bot does without asking.

Updating Commands

If you add, remove, or change commands, simply restart your bot. Commands are automatically synced on every restart!

Module 2 Complete!

Awesome! You've learned how to create slash commands. Users can now type "/" and discover your bot's features through an intuitive command interface!

What You've Built:

Command definitions file
Help and ping commands
Commands with user mentions
Command registration workflow

Next Up:

Handle messages and reactions
Welcome new members
Build interactive features