Tickd.ai
← The Tickd Guide

Tutorials & Guides

How to Build a Discord Bot that Auto-Drafts GitHub Issues from Raw Chat Bug Reports Using Claude 3.5 Sonnet

Tired of copy-pasting messy, unstructured Discord bug reports into GitHub? Build a Python bot that uses Claude 3.5 Sonnet to automatically turn chat chaos into perfectly formatted markdown issues.

Updated 10/5/2026

The Problem with Discord Bug Reports

If you run an open-source project, an indie game, or a small SaaS, your Discord server is likely where bugs go to liveβ€”and where your sanity goes to die. Users don't write structured bug reports. They write stream-of-consciousness essays. You get a screenshot, a vague complaint about something "not working," and maybe, if you're lucky, a mention of their operating system.

Copying these chaotic chat logs, deciphering what actually went wrong, and manually formatting them into clean GitHub issues is a soul-crushing chore.

We can do better. By combining a simple Python Discord bot with the reasoning power of /platforms/claude, we can build an automated triage assistant. It listens for a specific emoji reaction on any message, parses the messy chat context, structures it into a pristine markdown GitHub issue, and drafts it for you.

Here is how to build it.

The Architecture

The workflow is straightforward: 1. A user reports a bug in Discord. 2. You (or a moderator) react to the message with a specific emoji (let's use πŸ›). 3. The bot fetches the target message and its immediate context (to capture follow-up replies). 4. We send this unstructured text to Claude 3.5 Sonnet, asking it to extract the steps to reproduce, expected vs. actual behaviour, and system details. 5. The bot uses the GitHub API to draft the issue.

Let's get our environment set up.

Step 1: Dependencies and Environment

You will need a few libraries. We are using discord.py for the Discord interface, anthropic to talk to Claude, and PyGithub to handle the GitHub integration.

`bash pip install discord.py anthropic PyGithub python-dotenv `

Create a .env file in your project directory to store your credentials:

`env DISCORD_TOKEN=your_discord_bot_token ANTHROPIC_API_KEY=your_anthropic_api_key GITHUB_TOKEN=your_github_personal_access_token GITHUB_REPO=your_username/your_repo_name `

(Note: If you run into issues authenticating your Anthropic client, check the official help docs at [https://claude-support.com](https://claude-support.com) for troubleshooting steps.)

Step 2: Designing the Claude Prompt

To ensure Claude returns a highly structured, reliable markdown payload, we need to instruct it clearly. We don't want conversational filler or polite banter. We want a clean GitHub-ready markdown document.

We will define a system prompt that enforces this structure. If you need help refining your LLM instructions for similar workflows, check out our interactive /prompts for inspiration.

Here is our system prompt:

`python SYSTEM_PROMPT = """ You are an expert QA engineer and technical writer. Your task is to take a messy, unstructured chat log describing a software bug and convert it into a highly professional, structured GitHub Issue in markdown format.

Your output must contain only the markdown for the issue. Do not include any conversational intro or outro text.

Structure the issue as follows: - Title: A concise, descriptive title (maximum 10 words). - Description: A brief summary of the issue. - Steps to Reproduce: A numbered list of steps, inferred logically from the chat text. - Expected Behaviour: What should have happened. - Actual Behaviour: What actually happened. - Environment Info: Operating system, browser, or versions mentioned (or 'Not specified' if missing). - Context: A quote of the original chat log for reference. """ `

Step 3: Writing the Bot Code

Now, let's write the core Python script. We'll set up a Discord client that listens for a raw_reaction_add event. This ensures the bot can process reactions even on older messages that aren't cached in memory.

`python import os import discord from discord.ext import commands from anthropic import Anthropic from github import Github from dotenv import load_dotenv

load_dotenv()

Initialize APIs discord_token = os.getenv("DISCORD_TOKEN") anthropic_client = Anthropic(api_key=os.getenv("ANTHROPIC_API_KEY")) github_client = Github(os.getenv("GITHUB_TOKEN")) repo = github_client.get_repo(os.getenv("GITHUB_REPO"))

Setup Discord Bot with necessary intents intents = discord.Intents.default() intents.message_content = True intents.reactions = True bot = commands.Bot(command_prefix="!", intents=intents)

@bot.event async def on_ready(): print(f"Logged in as {bot.user.name} (ID: {bot.user.id})") print("------")

@bot.event async def on_raw_reaction_add(payload): # We only care about the bug emoji if str(payload.emoji) != "πŸ›": return

channel = bot.get_channel(payload.channel_id) message = await channel.fetch_message(payload.message_id)

Optional: Restrict usage to moderators/admins # member = payload.member # if not member.guild_permissions.manage_messages: # return

Let the channel know we are on it await channel.send(f"βš™οΈ Processing bug report from {message.author.mention}...", delete_after=10)

Gather context: target message + up to 3 subsequent messages to catch details context_msgs = [] async for msg in channel.history(limit=5, after=message.created_at, oldest_first=True): context_msgs.append(f"{msg.author.display_name}: {msg.content}") chat_log = f"{message.author.display_name}: {message.content}\n" + "\n".join(context_msgs)

Send context to Claude try: prompt = f"Extract the bug report from this chat log:\n\n{chat_log}" response = anthropic_client.messages.create( model="claude-3-5-sonnet-20241022", max_tokens=1500, temperature=0.1, system=SYSTEM_PROMPT, messages=[{"role": "user", "content": prompt}] ) issue_markdown = response.content[0].text # Extract the first line as the title, clean up markdown headers lines = issue_markdown.strip().split("\n") title = "[Discord Bug] " + lines[0].replace("**Title**:", "").replace("#", "").strip() body = "\n".join(lines[1:]).strip()

Create the issue on GitHub created_issue = repo.create_issue(title=title, body=body)

Send a success message back to Discord await channel.send( f"βœ… **GitHub Issue Created!**\n" f"Title: *{title}*\n" f"Link: {created_issue.html_url}" )

except Exception as e: await channel.send(f"❌ Failed to generate issue. Error: {str(e)}")

if __name__ == "__main__": bot.run(discord_token) `

Step 4: Testing Your Bot

Run your script localy to test things out:

`bash python bot.py `

Now, head over to your Discord server, post a messy report, and react to it with the πŸ› emoji.

For instance, if someone types:

> "Ugh, the login page keeps spinning when I use Safari on my phone. Works fine on my laptop but mobile is completely broken. I just get a grey screen and no error message."

Your bot will catch this, feed it to Claude, and create a perfectly structured issue on GitHub complete with "Steps to Reproduce" (1. Open mobile Safari, 2. Navigate to login page, etc.) and "Environment Info" (Safari on mobile), all without you lifting a finger.

Optimising the Pipeline

This simple setup is highly customisable. If your repository uses strict issue templates, you can easily modify the SYSTEM_PROMPT to output specific template keys or inject tags into your PyGithub call (e.g., tagging the issue as triage or discord-reported).

If you want to dive deeper into the mechanics of API payloads, schemas, and prompting architectures, take a look at our comprehensive /glossary for a breakdown of foundational LLM design patterns. It's a great way to keep your development pipeline ticking along nicely without manual intervention.

claudediscordgithubpythonautomation

Keep going

Build something with the prompt generator, decode the jargon in the glossary, or compare the tools on our platform deep-dives.