# 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: ```go 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](../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](../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 ```sh # 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](../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](../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: ```go 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](../bot.go#L40)). 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](../commands/commands.go#L30-L33). 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](../commands/delete.go#L86-L100). 5. **No Database**: All state in `users.json`. Loss of this file = all users must re-run `/setup`.