Thread-Based Support
Automatically create a dedicated thread for every support request so your main channels stay clean and organized.
The problem
When multiple users ask questions in the same support channel, conversations overlap and become impossible to follow. Important questions get buried. Users do not know if their issue is being tracked.
The solution
A bot that watches a support channel and automatically:
- Creates a new thread when a user @mentions the bot
- Sends an acknowledgment inside the thread
- Handles follow-up messages within the thread
- Optionally integrates with AI for automated responses
Each support request gets its own contained thread, making it easy to track, resolve, and archive.
Full working code
#!/usr/bin/env python3"""Thread-Based Support — auto-create threads for support requests."""
import jsonimport subprocessimport sys
SUPPORT_CHANNELS = {"support", "help", "questions"} # Channel names to watch
def run_discli(*args): """Run a discli command with JSON output and return parsed result.""" result = subprocess.run( ["discli", "--json", *args], capture_output=True, text=True, ) if result.returncode != 0: print(f"[error] discli {' '.join(args)}: {result.stderr.strip()}", file=sys.stderr) return None try: return json.loads(result.stdout) except json.JSONDecodeError: return None
def run_discli_plain(*args): """Run a discli command without JSON output.""" result = subprocess.run( ["discli", *args], capture_output=True, text=True, ) if result.returncode != 0: print(f"[error] discli {' '.join(args)}: {result.stderr.strip()}", file=sys.stderr)
# Track active threads so we can handle follow-upsactive_threads = {} # thread_id -> {"author_id": str, "channel_id": str}
# Start listeningproc = subprocess.Popen( ["discli", "--json", "listen", "--events", "messages"], stdout=subprocess.PIPE, text=True,)
print("Thread support bot running. Ctrl+C to stop.", file=sys.stderr)
for line in proc.stdout: line = line.strip() if not line: continue
try: event = json.loads(line) except json.JSONDecodeError: continue
channel_id = event.get("channel_id", "") channel_name = event.get("channel", "") author = event.get("author", "unknown") author_id = event.get("author_id", "") message_id = event.get("message_id", "") content = event.get("content", "")
# --- New support request: bot mentioned in a watched channel --- if ( event.get("mentions_bot") and channel_name in SUPPORT_CHANNELS and channel_id not in active_threads ): # Create a thread from the user's message thread = run_discli( "thread", "create", channel_id, message_id, f"Support - {author}", )
if thread and thread.get("id"): thread_id = thread["id"] active_threads[thread_id] = { "author_id": author_id, "channel_id": channel_id, }
# Send welcome message in the thread run_discli( "thread", "send", thread_id, f"Hi {author}! I've created this thread for your request.\n\n" f"**Your question:** {content}\n\n" f"A team member will respond here shortly. " f"Please share any additional details in this thread.", )
print(f"[thread] Created '{thread.get('name')}' for {author}", file=sys.stderr) continue
# --- Follow-up in an active thread --- if channel_id in active_threads: # Skip bot messages to avoid loops if event.get("is_bot"): continue
# Show typing while processing subprocess.Popen( ["discli", "typing", channel_id, "--duration", "3"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, )
# Simple acknowledgment (replace with AI in production) thread_info = active_threads[channel_id] run_discli( "thread", "send", channel_id, f"Thanks for the additional details, {author}. " f"A team member has been notified and will respond soon.", )
print(f"[follow-up] {author} in thread {channel_id}", file=sys.stderr)Step-by-step explanation
Configure watched channels
The SUPPORT_CHANNELS set defines which channels trigger thread creation. Only messages in these channels that @mention the bot will create a new thread.
SUPPORT_CHANNELS = {"support", "help", "questions"}You can use channel IDs instead of names for more precise matching, especially if you have multiple servers with similarly named channels.
Listen for messages
The script starts a discli listen process that streams all messages as JSON. Each message includes the channel name, channel_id, and a mentions_bot flag.
discli --json listen --events messagesCreate a thread
When the bot is mentioned in a support channel, it creates a thread attached to the user’s message. The thread name includes the author for easy identification.
discli --json thread create CHANNEL_ID MESSAGE_ID "Support - Alice"The command returns a JSON object with the new thread’s id, which the script stores for follow-up tracking.
{ "id": "1234567890123456789", "name": "Support - Alice", "parent_channel": "support", "parent_channel_id": "9876543210987654321", "message_id": "1111111111111111111"}Send an acknowledgment
The bot immediately sends a welcome message inside the thread so the user knows their request was received.
discli thread send THREAD_ID "Hi Alice! I've created this thread for your request..."Handle follow-ups
The script tracks active thread IDs in a dictionary. When a new message arrives in a known thread, it shows a typing indicator and responds. The example sends a simple acknowledgment, but this is where you would plug in AI or a ticket system.
Edge cases and pitfalls
CREATE_PUBLIC_THREADS permission. Your bot must have the Create Public Threads permission in the channels it watches. Without this, the thread create command will fail with a 403 error.
Thread auto-archive. Discord automatically archives threads after 1 hour of inactivity (24 hours for boosted servers). Once archived, messages in the thread will not trigger events. If you need longer-lived threads, periodically send a keep-alive message or instruct users to unarchive.
Thread limits. Servers have a maximum of 1000 active threads. If your server handles high support volume, implement a thread-closing mechanism that archives resolved threads.
Duplicate threads. If a user mentions the bot multiple times quickly, the script might create duplicate threads. The channel_id not in active_threads check prevents this for the parent channel, but consider adding a per-user cooldown for robustness.
Extending the system
AI-powered responses
Replace the static acknowledgment with Claude to provide instant answers in threads. See AI Support Agent for the integration pattern.
Resolution workflow
Add a close command (e.g., “!resolved”) that archives the thread and logs the resolution. Track open vs. resolved threads for metrics.
Human handoff
When the AI cannot answer confidently, notify a support role with discli message send "#staff-alerts" "New ticket needs human review: ..." and include a link to the thread.
Priority routing
Parse the initial message for keywords like “urgent”, “broken”, or “billing” and assign priority labels. Route high-priority threads to specific staff members via DM with discli dm send.