Overview
Discord is the final destination for Dream Foundry results. After selecting a winner, the winning artifact (a formatted Discord post) is published to a Discord channel via webhook, sharing AI events with your community.
Discord integration uses webhooks, which donโt require a bot. Just create a webhook URL and youโre ready to post.
Why Discord?
Dream Foundryโs demo use case is generating AI event posts for Discord:
โI want a bot that posts AI events to our Discord every week.โ
The winning agent produces a markdown-formatted post with:
10+ events happening in the Bay Area
Event details : Date, location, type, URL
Special emphasis on the Daytona AI Hackathon
Discord formatting : Bold titles, emojis, clickable links
Setup and Configuration
Create Webhook
In your Discord server:
Go to Server Settings โ Integrations โ Webhooks
Click New Webhook
Choose the target channel (e.g., #ai-events)
Copy the webhook URL
Configure Environment
Add the webhook URL to .env: DISCORD_WEBHOOK_URL = https://discord.com/api/webhooks/123456789/abcdefg
Test Connection
Verify the webhook works: python -m src.discord_poster
This sends a test message to your channel.
How It Works
Webhook Validation
The integration checks if Discord is properly configured:
def get_webhook_url () -> Optional[ str ]:
"""Get Discord webhook URL from environment."""
url = os.getenv( "DISCORD_WEBHOOK_URL" )
if url and url.startswith( "https://discord.com/api/webhooks/" ):
return url
return None
def is_discord_configured () -> bool :
"""Check if Discord webhook is configured."""
return get_webhook_url() is not None
Posting Messages
Messages are sent via HTTP POST to the webhook URL:
def post_to_discord (
content : str ,
username : str = "Dream Foundry" ,
avatar_url : Optional[ str ] = None ,
) -> tuple[ bool , str ]:
"""Post content to Discord via webhook."""
webhook_url = get_webhook_url()
if not webhook_url:
return False , "Discord webhook URL not configured"
payload = {
"content" : content,
"username" : username,
}
if avatar_url:
payload[ "avatar_url" ] = avatar_url
response = requests.post(webhook_url, json = payload, timeout = 10 )
if response.status_code not in [ 200 , 204 ]:
return False , f "Discord API error: { response.status_code } "
return True , "Posted to Discord"
Message Splitting
Discord has a 2000 character limit per message. Long posts are automatically split:
MAX_LENGTH = 1900 # Leave room for safety
if len (content) <= MAX_LENGTH :
messages = [content]
else :
# Split by event blocks (marked by **Title**)
blocks = content.split( " \n **" )
current_msg = ""
for i, block in enumerate (blocks):
if i > 0 :
block = "**" + block
if len (current_msg) + len (block) + 1 <= MAX_LENGTH :
current_msg += ( " \n " if current_msg else "" ) + block
else :
if current_msg:
messages.append(current_msg)
current_msg = block
if current_msg:
messages.append(current_msg)
Messages are split by event blocks to avoid breaking individual events across multiple messages.
Usage Examples
Basic Message
Send a simple text message:
from src.discord_poster import post_to_discord
success, msg = post_to_discord( "Hello from Dream Foundry!" )
if success:
print ( "Message sent!" )
else :
print ( f "Failed: { msg } " )
Winner Announcement
Post the winnerโs artifact:
from src.discord_poster import post_winner_announcement
success, msg = post_winner_announcement(
winner_id = "gamma" ,
winner_score = 94.4 ,
artifact_content = winner_artifact,
objective = "Generate weekly AI events for Discord" ,
)
print (msg) # "Posted to Discord (1 message)"
This creates a formatted announcement:
๐ **DREAM FOUNDRY - Winner Announcement** ๐
**Objective:** Generate weekly AI events for Discord
**Winner:** Agent Gamma (The Insider)
**Score:** 94.4/100
---
[Winner's events list follows...]
Custom Webhook Identity
Customize the webhookโs display name and avatar:
from src.discord_poster import post_to_discord
post_to_discord(
content = "Competition results are in!" ,
username = "AI Events Bot" ,
avatar_url = "https://example.com/bot-avatar.png" ,
)
Discord Markdown Support
Winner artifacts use Discord markdown formatting:
Bold
Links
Emojis
Code Blocks
Lists
**Daytona HackSprint SF** โ **Daytona HackSprint SF**
**Daytona HackSprint SF**
๐๏ธ Saturday, January 24, 2026
๐ San Francisco, CA
๐ฏ Hackathon
๐ [ Register ]( https://lu.ma/kga3qtfc )
Build with Daytona's new AI dev platform! Compete for prizes and ship real products.
---
Rate Limiting
Discord webhooks have rate limits:
5 messages per 2 seconds per webhook
30 messages per minute per webhook
Dream Foundry handles this by adding delays between messages:
# Post each message
for i, msg in enumerate (messages):
response = requests.post(webhook_url, json = payload, timeout = 10 )
# Small delay between messages to avoid rate limiting
if i < len (messages) - 1 :
import time
time.sleep( 0.5 )
Sending too many messages too quickly results in 429 Too Many Requests errors.
Testing
Test the Discord integration directly:
python -m src.discord_poster
This runs the test code at the bottom of the file:
if __name__ == "__main__" :
from dotenv import load_dotenv
load_dotenv()
if is_discord_configured():
print ( "Discord is configured!" )
success, msg = post_to_discord( "๐งช Test message from Dream Foundry!" )
print ( f "Result: { success } - { msg } " )
else :
print ( "Discord not configured. Add DISCORD_WEBHOOK_URL to .env" )
Best Practices
Use meaningful webhook names
Set a descriptive name when creating the webhook: Name: Dream Foundry Results
Channel: #ai-events
Validate content length
Check message length before posting: if len (content) > 1900 :
print ( f "Warning: Long message ( { len (content) } chars) will be split" )
Handle failures gracefully
Always check the return tuple: success, msg = post_to_discord(content)
if not success:
log( f "Discord post failed: { msg } " )
# Fall back to logging or email
Avoid spamming
Add delays between multiple posts: import time
for event in events:
post_to_discord(event)
time.sleep( 1 ) # 1 second delay
Troubleshooting
Webhook URL Invalid
Error : Discord webhook URL not configured
Solution :
Verify URL starts with https://discord.com/api/webhooks/
Check .env file has correct URL
Ensure no extra spaces or quotes in .env
404 Not Found
Error : Discord API error: 404
Solution :
Webhook may have been deleted
Recreate webhook in Discord server settings
Update .env with new URL
401 Unauthorized
Error : Discord API error: 401
Solution :
Webhook token in URL is invalid
Generate a new webhook
429 Rate Limited
Error : Discord API error: 429
Solution :
Youโre sending messages too quickly
Wait 60 seconds before retrying
Increase delay between messages (see src/discord_poster.py:102)
Messages Not Appearing
Problem : No errors but messages donโt show in Discord
Solutions :
Check youโre in the correct channel
Verify webhook is enabled (not deleted)
Check Discord isnโt filtering the webhook messages
Test with a simple message: post_to_discord("test")
Security Considerations
Webhook URLs are sensitive! Anyone with the URL can post to your channel.
Protect Your Webhook
Never commit webhook URLs to version control
Use .env files and add .env to .gitignore
Rotate webhooks if accidentally exposed
Limit permissions - webhooks can only post, not read
Example .gitignore
# Environment variables
.env
.env.local
.env.*.local
# Secrets
*_secret*
*_token*
*_key*