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.
- Set environment variables: Add
DISCORD_BOT_TOKEN
,LINEAR_API_KEY
, andLINEAR_TEAM_ID
to your Val Town environment - Configure Discord bot with proper permissions and intents
- Set up the cron job to run every minute
- Start using: React to Discord messages with š§æ to create tickets!
Set these in your Val Town environment:
Variable | Description | Required |
---|---|---|
DISCORD_BOT_TOKEN | Your Discord bot token | ā |
LINEAR_API_KEY | Your Linear API key | ā |
LINEAR_TEAM_ID | The Linear team ID where tickets should be created (UUID format) | ā |
- Go to Discord Developer Portal
- Create a new application and bot
- Copy the bot token to
DISCORD_BOT_TOKEN
in your envirionment variables
- In Discord Developer Portal, go to OAuth2 ā URL Generator
- Select "bot" scope. Selecting this will unfurl a new
Bot Permissions
section below - Then select
View Channels
,Read Message History
andAdd Reactions
- Use the generated URL to invite your bot to your Discord server
Critical: Enable Message Content Intent
- In Discord Developer Portal, go to "Bot" ā "Privileged Gateway Intents"
- Enable "Message Content Intent" ā
Without this, your bot can see messages exist but cannot read the actual text content of messages.
- Go to Linear Settings ā
Security & Access
āPersonal API Key
- Copy it to
LINEAR_API_KEY
in your envirionment variables
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
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:
- Enable Developer Mode in Discord (Settings ā Advanced ā Developer Mode)
- Right-click on channel ā Copy ID
- Right-click on server name ā Copy ID
- Go to your
discord-reaction-cron.ts
file in Val Town - Set the cron schedule to run every minute:
* * * * *
- Cron job runs every minute (
discord-reaction-cron.ts
) - Connects to Discord using Discord.js SDK
- Checks monitored channels for messages with target emoji reactions (š§æ)
- 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)
- Title:
- Prevents duplicates by tracking processed messages in Val Town blob storage
- Cleans up Discord connection after each run
āāā 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
discord-reaction-cron.ts
- The main automation that runs every minute to check for new reactionsbackend/config.ts
- Configuration constants and environment helpersbackend/discord.ts
- Discord.js SDK integration with message formattingbackend/linear.ts
- Linear SDK integration for ticket creation
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;
- 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
"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
- Check Val Town logs for detailed error messages
- Verify all environment variables are set correctly
- Test with a simple message that has clear text content
- Check Discord Developer Portal for bot permissions and intents
- 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
)
- Enable Message Content Intent - This is critical for reading message content
- Use the correct permissions integer (
2147549248
) when inviting the bot - Use UUID format for team ID - Not the team key
- Test with messages that have actual text content - Empty messages will show as "Message from username"
- 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!