Files
thoughtful-dcbot/.github/copilot-instructions.md

4.2 KiB

Thoughtful Discord Bot - AI Coding Instructions

Project Overview

A Go Discord bot that integrates with the Thoughtful API for managing ideas through Discord commands. Built with discordgo library, uses JSON for user config persistence.

Architecture

Component Structure

  • bot.go: Main entry point. Handles Discord session, registers handlers, manages bot lifecycle
  • commands/: Modular command system where each command is a separate file
    • commands.go: Command registry and interaction router
    • storage.go: JSON-based user config persistence (users.json)
    • Individual command files: setup.go, list.go, delete.go, logout.go

Key Design Patterns

Command Registration Pattern: Each command implements the Cmd struct:

type Cmd struct {
    Command             *discordgo.ApplicationCommand
    Handler             func(s *discordgo.Session, ic *discordgo.InteractionCreate)
    AutocompleteHandler func(s *discordgo.Session, ic *discordgo.InteractionCreate) // optional
}

All commands are registered via getAllCommands() in commands/commands.go.

Dual Command Interface: The bot supports both:

  • Slash commands (e.g., /setup, /list) via Discord's ApplicationCommand API
  • Legacy text commands (e.g., .thought Title; Description) for backward compatibility

User State Management: Per-user configs (Thoughtful instance URL + API key) stored in users.json. Thread-safe access via mutex in commands/storage.go.

Modal-Based Setup: /setup uses Discord modals (not option prompts) to collect sensitive credentials privately.

External Dependencies

  • Thoughtful API: External idea management service. Requires:
    • Base URL (user-provided, e.g., https://instance.com)
    • API key authentication via API-Authentication header
    • Endpoints: /api/ideas/create, /api/ideas/list, /api/ideas/delete
  • Discord API: via github.com/bwmarrin/discordgo library

Developer Workflows

Running Locally

# Set environment variable
$env:DISCORD_BOT_TOKEN="your_token_here"

# Run directly
go run .

Docker Deployment

The bot is designed for Docker Compose deployment. See docker-compose.yml:

  • Uses golang:1.25 image (note: uncommon version - likely should be 1.21 or 1.22)
  • Auto-pulls git changes on container start
  • Requires .env file with DISCORD_BOT_TOKEN

Adding New Commands

  1. Create new file in commands/ (e.g., mycommand.go)
  2. Implement newMyCommand() returning *Cmd
  3. Add to getAllCommands() in commands/commands.go
  4. Command automatically registers on bot startup

Project-Specific Conventions

Error Handling

  • Use respondError() helper for interaction failures (defined in command files)
  • Silent failures acceptable for autocomplete handlers
  • Channel messages for .thought command errors

User Identification

Discord interactions may have User OR Member.User depending on context:

user := ic.User
if user == nil {
    user = ic.Member.User
}

Always check both when accessing user data.

API Communication

  • Always trim trailing slashes from instance URLs: url = strings.TrimSuffix(url, "/")
  • Use API-Authentication header (not Authorization)
  • 401 status codes mean invalid/expired API keys

Storage Layer

  • Never edit users.json directly - always use storage.go functions
  • Operations are mutex-protected but not transactional
  • Corrupted JSON automatically resets to empty map

Critical Gotchas

  1. Intents Required: Bot needs IntentsGuildMessages (set in bot.go). Message Content Intent must be enabled in Discord Developer Portal.

  2. Slash Command Updates: Slash commands persist in Discord. To update, uncomment command cleanup code in commands/commands.go.

  3. Modal Response Type: Setup uses InteractionResponseModal, not InteractionResponseChannelMessageWithSource.

  4. Autocomplete Filtering: Delete command autocomplete should filter by user input but currently returns all ideas - see commands/delete.go.

  5. No Database: All state in users.json. Loss of this file = all users must re-run /setup.