• Townie
    AI
  • Blog
  • Docs
  • Pricing
  • We’re hiring!
Log inSign up
project logo

charmaine

Discord-to-Linear

Discord -> Linear ticket based on emoji reaction trigger
Public
Like
2
Discord-to-Linear
Home
Code
3
backend
3
README.md
C
discord-reaction-cron.ts
Branches
1
Pull requests
Remixes
3
History
Environment variables
5
Val Town is a collaborative website to build and scale JavaScript apps.
Deploy APIs, crons, & store data – all from the browser, and deployed in milliseconds.
Sign up now
Code
/
README.md
Code
/
README.md
Search
5/24/2025
Viewing readonly version of main branch: v88
View latest version
README.md

Discord to Linear Ticket Automation

This automation creates Linear tickets from Discord messages when they receive a specific emoji reaction (🧿). It runs as a cron job every minute to check for new reactions.

🚀 Quick Start

  1. Set environment variables: Add DISCORD_BOT_TOKEN, LINEAR_API_KEY, and LINEAR_TEAM_ID to your Val Town environment
  2. Configure Discord bot with proper permissions and intents
  3. Set up the cron job to run every minute
  4. Start using: React to Discord messages with 🧿 to create tickets!

📋 Environment Variables

Set these in your Val Town environment:

VariableDescriptionRequired
DISCORD_BOT_TOKENYour Discord bot token✅
LINEAR_API_KEYYour Linear API key✅
LINEAR_TEAM_IDThe Linear team ID where tickets should be created (UUID format)✅

🔧 Setup Instructions

1. Create Discord Bot

  1. Go to Discord Developer Portal
  2. Create a new application and bot
  3. Copy the bot token to DISCORD_BOT_TOKEN

2. Configure Discord Bot Permissions

Use permissions integer: 2147549248

  1. In Discord Developer Portal, go to OAuth2 → URL Generator
  2. Select "bot" scope
  3. Paste permissions integer: 2147549248
  4. Use the generated URL to invite your bot to your Discord server

This includes:

  • ✅ View Channels
  • ✅ Read Message History
  • ✅ Add Reactions

3. Enable Required Bot Intents

Critical: Enable Message Content Intent

  1. In Discord Developer Portal, go to "Bot" → "Privileged Gateway Intents"
  2. Enable "Message Content Intent" ✅

Without this, your bot can see messages exist but cannot read the actual text content, resulting in empty ticket titles.

4. Get Linear API Key

  1. Go to Linear Settings → API
  2. Create a new Personal API key
  3. Copy it to LINEAR_API_KEY

5. Find Your Linear Team ID

Your team ID must be in UUID format (e.g., 6312a2a0-633b-47dc-a225-81d5d1759bf4).

Method 1: From Linear URL

  • Go to your Linear team
  • Copy the UUID from the URL: https://linear.app/your-team/team/UUID-HERE

Method 2: Use Linear API

  • Make a GraphQL query to get your teams and find the correct UUID

6. Configure Monitored Channels

Edit discord-reaction-cron.ts and update these values:

const monitoredChannels = [ "1327384540187983926", // Replace with your channel ID // Add more channel IDs as needed ]; const guildId = "1327384540187983923"; // Replace with your server ID

To get these IDs:

  1. Enable Developer Mode in Discord (Settings → Advanced → Developer Mode)
  2. Right-click on channel → Copy ID
  3. Right-click on server name → Copy ID

7. Set Up Cron Schedule

  1. Go to your discord-reaction-cron.ts file in Val Town
  2. Set the cron schedule to run every minute: * * * * *

🎯 How It Works

  1. Cron job runs every minute (discord-reaction-cron.ts)
  2. Connects to Discord using Discord.js SDK
  3. Checks monitored channels for messages with target emoji reactions (🧿)
  4. Creates Linear tickets for new reactions with:
    • Title: [Discord] <actual message content>
    • Description: Full message content + link to Discord message
    • Labels: "discord-import"
    • Priority: Medium (configurable)
  5. Prevents duplicates by tracking processed messages in Val Town blob storage
  6. Cleans up Discord connection after each run

📁 Project Structure

├── discord-reaction-cron.ts     # Main automation (runs every minute)
├── backend/
│   ├── config.ts               # Configuration constants
│   ├── discord.ts              # Discord.js SDK wrapper
│   └── linear.ts               # Linear SDK wrapper
└── README.md

🔗 Key Files

  • discord-reaction-cron.ts - The main automation that runs every minute to check for new reactions
  • backend/config.ts - Configuration constants and environment helpers
  • backend/discord.ts - Discord.js SDK integration with message formatting
  • backend/linear.ts - Linear SDK integration for ticket creation

⚙️ Configuration

Edit /backend/config.ts to customize:

export const CONFIG = { TARGET_EMOJI: "nazar_amulet", // Emoji name that triggers tickets LINEAR_LABEL_NAME: "discord-import", // Label added to tickets LINEAR_PRIORITY: 3, // 1=Urgent, 2=High, 3=Medium, 4=Low MAX_TITLE_LENGTH: 100, // Maximum characters in ticket title } as const;

🛠️ Built With

  • Discord.js SDK (v14.14.1) - Official Discord JavaScript SDK for reliable bot interactions
  • Linear SDK (v22.0.0) - Official Linear SDK for seamless issue management
  • Val Town Blob Storage - For tracking processed messages and preventing duplicates
  • TypeScript - For type safety and better development experience

🔍 Troubleshooting

Common Issues

"Required environment variable not set" error:

  • Check that all three environment variables are configured in Val Town
  • Verify there are no extra spaces in the values (they are automatically trimmed)

Tickets created with "Message from username" instead of actual content:

  • Enable "Message Content Intent" in Discord Developer Portal
  • This is the most common issue - the bot can see messages but not read content without this intent

"teamId must be a UUID" error:

  • Ensure LINEAR_TEAM_ID is in UUID format (e.g., 6312a2a0-633b-47dc-a225-81d5d1759bf4)
  • Don't use the team key (e.g., "VAL") - use the full UUID

Bot not responding to reactions:

  • Verify the bot is in the Discord server and has correct permissions
  • Check that you're using the exact emoji name configured in TARGET_EMOJI
  • Ensure the channel ID is correct in the monitored channels list

Cron job not running:

  • Verify the cron schedule is set to * * * * * in Val Town
  • Check Val Town logs for any startup errors

Getting Help

  1. Check Val Town logs for detailed error messages
  2. Verify all environment variables are set correctly
  3. Test with a simple message that has clear text content
  4. Check Discord Developer Portal for bot permissions and intents

📊 Monitoring

  • Check Val Town logs for cron job execution and any errors
  • Monitor Linear tickets with the "discord-import" label
  • Track processed messages in Val Town blob storage (keys like processed_MESSAGE_ID_EMOJI)

🎉 Success Tips

  1. Enable Message Content Intent - This is critical for reading message content
  2. Use the correct permissions integer (2147549248) when inviting the bot
  3. Use UUID format for team ID - Not the team key
  4. Test with messages that have actual text content - Empty messages will show as "Message from username"
  5. Monitor the logs - They provide detailed information about what's happening

The automation creates tickets with format: [Discord] <actual message content>

React to any Discord message with 🧿 and watch it automatically become a Linear ticket!

FeaturesVersion controlCode intelligenceCLI
Use cases
TeamsAI agentsSlackGTM
DocsShowcaseTemplatesNewestTrendingAPI examplesNPM packages
PricingNewsletterBlogAboutCareers
We’re hiring!
Brandhi@val.townStatus
X (Twitter)
Discord community
GitHub discussions
YouTube channel
Bluesky
Open Source Pledge
Terms of usePrivacy policyAbuse contact
© 2025 Val Town, Inc.