ai-assistant-discord-bot/docs/BOT_USAGE.md
Claude Discord Bot 4c00cd97e6 Week 2 complete: Discord bot MVP with full integration
Completed HIGH-001 through HIGH-004:

HIGH-001: Discord bot with channel message routing
- bot.py: 244 lines with ClaudeCoordinator class
- @mention trigger mode for safe operation
- Session lifecycle integration with SessionManager
- Typing indicators and error handling
- 20/20 tests passing

HIGH-002: Response formatter with intelligent chunking
- response_formatter.py: expanded to 329 lines
- format_response() with smart boundary detection
- Code block preservation and splitting
- 26/26 tests passing

HIGH-003: Slash commands for bot management
- commands.py: 411 lines with ClaudeCommands cog
- /reset with interactive confirmation dialog
- /status with Discord embed display
- /model for runtime model switching
- 18/18 tests passing

HIGH-004: Concurrent message handling
- Per-channel asyncio.Lock implementation
- Same-channel serialization (prevents race conditions)
- Cross-channel parallelization (maintains performance)
- 7/7 concurrency tests passing

Total: 134/135 tests passing (99.3%)
Production-ready Discord bot MVP

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 18:42:50 +00:00

13 KiB

Discord Bot Usage Documentation

Overview

The Claude Coordinator Discord bot (claude_coordinator/bot.py) provides channel-based message routing to Claude CLI sessions. Each Discord channel maps to a specific project with isolated sessions and custom configurations.

Implementation: 244 lines of Python code
Test Coverage: 20 comprehensive test cases (455 lines), 100% passing

Architecture

Main Components

  • ClaudeCoordinator (discord.ext.commands.Bot subclass)
    • Message routing and filtering
    • Session lifecycle management
    • Integration with SessionManager, Config, ClaudeRunner
    • Error handling and Discord response formatting

Key Features

  1. @Mention Trigger Mode: Bot only responds when explicitly mentioned (safe for MVP)
  2. Channel-to-Project Mapping: Each channel routes to a specific project directory
  3. Session Persistence: Sessions maintained per-channel across restarts
  4. Typing Indicator: Shows "Bot is typing..." while Claude processes
  5. Error Handling: Graceful handling of timeouts, failures, and edge cases
  6. Response Chunking: Automatically splits long responses at Discord's 2000 char limit

Installation

1. Ensure Dependencies are Installed

The bot requires:

  • discord.py >= 2.6.4
  • aiosqlite >= 0.22.1
  • pyyaml >= 6.0.3

These are already in pyproject.toml and should be installed via uv sync.

2. Configuration

Create ~/.claude-coordinator/config.yaml:

projects:
  my-project:
    name: "my-project"
    channel_id: "1234567890123456789"  # Discord channel ID (as string)
    project_dir: "/path/to/project"
    allowed_tools:
      - "Bash"
      - "Read"
      - "Write"
      - "Edit"
    system_prompt: "You are a helpful coding assistant for this project."
    model: "sonnet"  # or "opus", "haiku"

To get a Discord channel ID:

  1. Enable Developer Mode in Discord (User Settings → Advanced → Developer Mode)
  2. Right-click a channel → Copy Channel ID

3. Get Discord Bot Token

  1. Go to https://discord.com/developers/applications
  2. Create New Application
  3. Navigate to Bot tab → Add Bot
  4. Copy the Bot Token
  5. Set environment variable:
    export DISCORD_TOKEN="your-token-here"
    

4. Invite Bot to Server

  1. In Discord Developer Portal → OAuth2 → URL Generator
  2. Select scopes: bot
  3. Select permissions: Send Messages, Read Message History, View Channels
  4. Copy generated URL and open in browser
  5. Select server and authorize

Running the Bot

Manual Execution

cd /opt/projects/claude-coordinator
export DISCORD_TOKEN="your-token-here"
uv run python -m claude_coordinator.bot

Create /etc/systemd/system/claude-coordinator.service:

[Unit]
Description=Claude Discord Coordinator Bot
After=network.target

[Service]
Type=simple
User=discord-bot
WorkingDirectory=/opt/projects/claude-coordinator
Environment="DISCORD_TOKEN=your-token-here"
ExecStart=/home/discord-bot/.local/bin/uv run python -m claude_coordinator.bot
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

Enable and start:

sudo systemctl daemon-reload
sudo systemctl enable claude-coordinator
sudo systemctl start claude-coordinator
sudo systemctl status claude-coordinator

View logs:

sudo journalctl -u claude-coordinator -f

Usage

Basic Usage

  1. Go to a configured Discord channel
  2. Mention the bot with your message:
    @ClaudeCoordinator Can you help me debug this function?
    
  3. Bot shows typing indicator while processing
  4. Claude's response appears in the channel

Session Continuity

Sessions are persistent per-channel:

  • First message creates a new session
  • Subsequent messages resume the same session
  • Session history maintained in SQLite database
  • Sessions persist across bot restarts

Example Conversation

User: @ClaudeCoordinator Can you list the files in this project?

Bot: I'll list the files in /path/to/project for you.
     [Claude's response with file listing]

User: @ClaudeCoordinator Can you read setup.py?

Bot: [Reads and displays setup.py contents, maintaining context from previous message]

Project Isolation

  • Each channel has its own isolated session
  • Sessions run in the configured project_dir
  • Only configured allowed_tools are available
  • Custom system_prompt sets project-specific behavior

Message Filtering Logic

The bot processes a message if ALL of the following are true:

  1. Message author is NOT a bot
  2. Bot was mentioned in the message (@ClaudeCoordinator)
  3. Channel is configured in config.yaml

Otherwise, the message is silently ignored.

Error Handling

Empty Message

If you mention the bot with no content:

User: @ClaudeCoordinator

Bot: ❌ Please provide a message after mentioning me.

Claude Failure

If Claude CLI command fails:

Bot: ❌ **Error running Claude:**

Command failed: invalid syntax

Timeout (>5 minutes)

Bot: ❌ **Timeout:** Claude took too long to respond (>5 minutes).

Unexpected Errors

All exceptions are caught and reported:

Bot: ❌ **Unexpected error:**

[error details]

Testing

Run the test suite:

cd /opt/projects/claude-coordinator
uv run pytest tests/test_bot.py -v

Test Coverage:

  • Bot initialization and configuration
  • Message filtering (bot messages, mentions, unconfigured channels)
  • Message content extraction (removing mentions, whitespace)
  • Session management (creation, resumption, persistence)
  • Claude integration (config passing, response handling)
  • Error handling (empty messages, Claude failures)
  • Typing indicator verification

Results: 20/20 tests passing (100%)

Monitoring

Database Location

Session data stored in:

~/.claude-coordinator/sessions.db

Inspect Sessions

cd /opt/projects/claude-coordinator
uv run python << 'EOF'
import asyncio
from claude_coordinator.session_manager import SessionManager

async def main():
    async with SessionManager() as sm:
        sessions = await sm.get_all_sessions()
        for s in sessions:
            print(f"Channel: {s['channel_id']}")
            print(f"  Project: {s['project_name']}")
            print(f"  Session: {s['session_id']}")
            print(f"  Messages: {s['message_count']}")
            print(f"  Last Active: {s['last_active']}")
            print()

asyncio.run(main())
EOF

Logs

With systemd service:

# Follow logs in real-time
sudo journalctl -u claude-coordinator -f

# View last 100 lines
sudo journalctl -u claude-coordinator -n 100

# View logs from today
sudo journalctl -u claude-coordinator --since today

Manual execution logs go to stdout:

2026-02-13 18:00:00 - claude_coordinator.bot - INFO - ClaudeCoordinator bot initialized
2026-02-13 18:00:01 - claude_coordinator.bot - INFO - Loaded configuration with 3 projects
2026-02-13 18:00:02 - discord.client - INFO - logging in using static token
2026-02-13 18:00:03 - claude_coordinator.bot - INFO - Logged in as ClaudeBot (ID: 123456789)
2026-02-13 18:00:03 - claude_coordinator.bot - INFO - Connected to 1 guilds
✓ Bot ready: ClaudeBot

Advanced Configuration

Multiple Projects

Configure different channels for different projects:

projects:
  web-app:
    name: "web-app"
    channel_id: "111111111111111111"
    project_dir: "/home/cal/projects/web-app"
    allowed_tools: ["Bash", "Read", "Write", "Edit", "Grep", "Glob"]
    model: "sonnet"
    
  data-pipeline:
    name: "data-pipeline"
    channel_id: "222222222222222222"
    project_dir: "/home/cal/projects/data-pipeline"
    allowed_tools: ["Bash", "Read", "Write"]  # More restrictive
    system_prompt: "You are a data engineering assistant. Focus on Python and SQL."
    model: "opus"
    
  docs-site:
    channel_id: "333333333333333333"
    project_dir: "/home/cal/projects/docs"
    allowed_tools: ["Read", "Write", "Edit"]  # No Bash execution
    system_prompt_file: "/home/cal/prompts/technical-writer.txt"
    model: "haiku"  # Faster for documentation

External System Prompts

Instead of inline system_prompt, use a file:

projects:
  my-project:
    # ... other config ...
    system_prompt_file: "/path/to/prompt.txt"

The file will be loaded and passed to Claude on each invocation.

Security Considerations

  1. Tool Restrictions: Use allowed_tools to limit what Claude can do

    • Production projects: Consider disabling Bash tool
    • Read-only access: Only allow Read, Grep, Glob
  2. Channel Access Control: Use Discord role permissions to control who can access bot channels

  3. Environment Variables: Never commit DISCORD_TOKEN to git

    • Use environment variables or systemd service config
    • Store in a secure secrets manager
  4. Database Permissions: Session database should only be readable by bot user

    chmod 600 ~/.claude-coordinator/sessions.db
    

Troubleshooting

Bot doesn't respond

  1. Check bot was mentioned: Must use @ClaudeCoordinator, not just typing its name
  2. Check channel is configured: Channel ID must be in config.yaml
  3. Check bot is running: systemctl status claude-coordinator
  4. Check logs: journalctl -u claude-coordinator -f

"Timeout" errors

  • Claude CLI took >5 minutes to respond
  • This is configured in ClaudeRunner (default: 300 seconds)
  • Increase timeout in claude_coordinator/claude_runner.py if needed

Bot crashes on startup

  1. Check DISCORD_TOKEN is set: echo $DISCORD_TOKEN
  2. Check config file exists: ls ~/.claude-coordinator/config.yaml
  3. Validate config syntax: uv run python -c "import yaml; yaml.safe_load(open('~/.claude-coordinator/config.yaml'))"
  4. Check database permissions: ls -la ~/.claude-coordinator/sessions.db

Sessions not resuming

  • Check database exists: ls ~/.claude-coordinator/sessions.db
  • Verify session was saved (check logs for "Successfully processed message")
  • Inspect database to confirm session_id was stored

Architecture Details

Message Flow

Discord Message
    ↓
on_message() event handler
    ↓
[Filter: Is bot message?] → Yes → Ignore
    ↓ No
[Filter: Bot mentioned?] → No → Ignore
    ↓ Yes
[Filter: Channel configured?] → No → Ignore
    ↓ Yes
_handle_claude_request()
    ↓
Extract message content (remove mentions)
    ↓
[Empty message?] → Yes → Send error
    ↓ No
Start typing indicator
    ↓
Get session from SessionManager (None if new)
    ↓
Run ClaudeRunner with session_id + project config
    ↓
[Success?] → No → Send error message
    ↓ Yes
Save/update session in database
    ↓
Format response (split at 2000 chars if needed)
    ↓
Send response to Discord channel

Session Lifecycle

User sends first message
    ↓
SessionManager.get_session(channel_id) → None
    ↓
ClaudeRunner.run(session_id=None)  # New session
    ↓
Claude CLI creates new session, returns session_id
    ↓
SessionManager.save_session(channel_id, session_id)
    ↓
[Subsequent messages]
    ↓
SessionManager.get_session(channel_id) → session_data
    ↓
ClaudeRunner.run(session_id=session_data['session_id'])  # Resume
    ↓
SessionManager.update_activity(channel_id)  # Update timestamp

Development

Running Tests

# All tests
uv run pytest tests/test_bot.py -v

# Specific test class
uv run pytest tests/test_bot.py::TestMessageFiltering -v

# Single test
uv run pytest tests/test_bot.py::TestMessageFiltering::test_ignores_bot_messages -v

# With coverage
uv run pytest tests/test_bot.py --cov=claude_coordinator.bot

Adding New Features

  1. Update claude_coordinator/bot.py with new functionality
  2. Add tests to tests/test_bot.py
  3. Run full test suite: uv run pytest tests/test_bot.py -v
  4. Update this documentation

Code Structure

  • __init__: Initialize bot with intents and components
  • setup_hook: Async initialization (database, config loading)
  • on_ready: Log connection status
  • on_message: Main event handler with filtering logic
  • _handle_claude_request: Process message, call Claude, send response
  • _extract_message_content: Remove bot mentions from message
  • close: Clean shutdown of resources

Future Enhancements

Potential improvements for future versions:

  1. Slash Commands: Support /claude <message> in addition to @mentions
  2. Thread Support: Create threads for long conversations
  3. Reaction Controls: React with to stop processing, ♻️ to retry
  4. Usage Tracking: Track API costs per channel/user
  5. Admin Commands: /session reset, /session info, /config reload
  6. Rate Limiting: Prevent spam/abuse
  7. Multi-user Sessions: Track per-user sessions instead of per-channel
  8. Attachment Support: Process code files attached to messages

Support

For issues or questions:

  • Check logs: journalctl -u claude-coordinator -f
  • Review test output: uv run pytest tests/test_bot.py -v
  • Verify configuration: Ensure config.yaml is valid and channel IDs are correct
  • Test manually: Run uv run python -m claude_coordinator.bot to see startup errors