Skip to main content

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

1

Create Webhook

In your Discord server:
  1. Go to Server Settings โ†’ Integrations โ†’ Webhooks
  2. Click New Webhook
  3. Choose the target channel (e.g., #ai-events)
  4. Copy the webhook URL
2

Configure Environment

Add the webhook URL to .env:
DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/123456789/abcdefg
3

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:
src/discord_poster.py
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:
src/discord_poster.py
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:
src/discord_poster.py
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:
**Daytona HackSprint SF** โ†’ **Daytona HackSprint SF**

Example Formatted Event

**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:
src/discord_poster.py
# 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:
src/discord_poster.py
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

1

Use meaningful webhook names

Set a descriptive name when creating the webhook:
Name: Dream Foundry Results
Channel: #ai-events
2

Validate content length

Check message length before posting:
if len(content) > 1900:
    print(f"Warning: Long message ({len(content)} chars) will be split")
3

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
4

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:
  1. Check youโ€™re in the correct channel
  2. Verify webhook is enabled (not deleted)
  3. Check Discord isnโ€™t filtering the webhook messages
  4. 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

  1. Never commit webhook URLs to version control
  2. Use .env files and add .env to .gitignore
  3. Rotate webhooks if accidentally exposed
  4. Limit permissions - webhooks can only post, not read

Example .gitignore

# Environment variables
.env
.env.local
.env.*.local

# Secrets
*_secret*
*_token*
*_key*

Build docs developers (and LLMs) love