A flexible Slack bot framework that allows you to create multiple bots powered by local CLI scripts (PowerShell, C#, Python, etc.). Bots communicate with Slack through a simple JSON protocol, enabling rich interactions without requiring scripts to implement the Slack API directly.
SlackServer acts as a bridge between Slack and your local scripts. Instead of writing complex Slack bot logic, you write simple scripts that output JSON commands, and SlackServer handles all the Slack API interactions.
π NEW HERE? Start with the Quick Start Guide (15 minutes) to get your @mention bot running!
- β Multi-Bot Support: Configure multiple bots in a single YAML file
- β Language Agnostic: Write bots in PowerShell, C#, Python, Bash, or any language
- β Simple JSON Protocol: Output JSON lines to control Slack (messages, reactions, blocks, etc.)
- β Rich Formatting: Full support for Slack Block Kit, reactions, threads, ephemeral messages
- β Pattern Matching: Use regex to match specific messages including @mentions
- β Channel & DM Support: Bots can respond in channels or direct messages
- β Windows Service Ready: Deploy as a Windows service or systemd service
This guide will walk you through creating a Slack bot that responds when @mentioned in a channel.
- Go to Slack API: Visit https://api.slack.com/apps
- Click "Create New App"
- Choose "From scratch"
- Enter App Name: e.g., "MyBot" (this will be your bot's @mention name)
- Select Workspace: Choose your workspace
- Click "Create App"
Socket Mode allows your bot to receive events without needing a public URL.
- Go to "Socket Mode" in the left sidebar
- Toggle "Enable Socket Mode" to ON
- Name your token: e.g., "SlackServer Connection"
- Click "Generate"
- Copy the App-Level Token (starts with
xapp-) - Save this!β οΈ - Click "Done"
-
Go to "OAuth & Permissions" in the left sidebar
-
Scroll to "Scopes" β "Bot Token Scopes"
-
Click "Add an OAuth Scope" and add these scopes:
Required Scopes:
app_mentions:read- Read messages that @mention your botchat:write- Send messageschannels:history- Read messages in channelsim:history- Read messages in DMsusers:read- Get user information
Optional Scopes:
reactions:write- Add/remove emoji reactionsfiles:write- Upload files
-
Go to "Event Subscriptions" in the left sidebar
-
Toggle "Enable Events" to ON
-
Expand "Subscribe to bot events"
-
Click "Add Bot User Event" and add:
app_mention- When someone @mentions your botmessage.channels- Messages in channels (if you want to respond without @mention)message.im- Direct messages to your bot
-
Click "Save Changes"
- Go to "Install App" in the left sidebar
- Click "Install to Workspace"
- Review permissions and click "Allow"
- Copy the "Bot User OAuth Token" (starts with
xoxb-) - Save this!β οΈ
- Open Slack and go to the channel where you want the bot
- Type:
/invite @MyBot(replace with your bot's name) - Press Enter
- Your bot should now appear in the channel
You'll need the channel ID for configuration:
- Right-click the channel name in Slack
- Select "View channel details"
- Scroll down - Channel ID is at the bottom (starts with
C, e.g.,C01234ABCDE) - Copy the Channel ID
-
Copy
config.example.yamltoconfig.yaml:cp config.example.yaml config.yaml
-
Edit
config.yamlwith your tokens and channel:
slack:
appToken: "xapp-1-YOUR-APP-LEVEL-TOKEN" # From Step 2
botToken: "xoxb-YOUR-BOT-USER-TOKEN" # From Step 5
logLevel: "Information"
bots:
# Bot that responds to @mentions
- name: "Question Bot"
description: "Answers questions when @mentioned"
type: channel
channelId: "C01234ABCDE" # Your channel ID from Step 7
messagePattern: "<@\\w+>\\s+.*" # Matches "@bot_name question"
script: "pwsh ./scripts/question-bot.ps1"
timeout: 30Pattern Explanation:
<@\\w+>- Matches the @mention (Slack sends it as<@U01234>)\\s+- Matches whitespace.*- Matches the rest of the message (the question)
Create scripts/question-bot.ps1:
#!/usr/bin/env pwsh
# Question bot - responds to @mentions
param(
[string]$Message = $env:TRIGGER_MESSAGE,
[string]$Channel = $env:TRIGGER_CHANNEL,
[string]$Timestamp = $env:TRIGGER_TS,
[string]$User = $env:TRIGGER_USER
)
function Send-SlackAction {
param([hashtable]$Action)
$json = $Action | ConvertTo-Json -Compress -Depth 10
Write-Output $json
}
# Extract the question (remove the @mention part)
$question = $Message -replace '<@\w+>\s*', ''
# Post a thinking message
Send-SlackAction @{
action = "post_message"
channel = $Channel
thread_ts = $Timestamp
text = "π€ Let me think about that..."
store_as = "thinking_msg"
}
Start-Sleep -Milliseconds 500
# Process the question (call your CLI tool here)
# Example: calling a simple echo, but you could call any CLI
$answer = "You asked: '$question'"
$answer += "`n`nThis is where you would call your CLI tool!"
$answer += "`nExample: `python ./my-cli-tool.py `"$question`"`"
# Update with the answer
Send-SlackAction @{
action = "update_message"
channel = $Channel
message_ref = "thinking_msg"
text = "β
*Answer:*`n$answer"
}
# You could also post a rich formatted response
Send-SlackAction @{
action = "post_blocks"
channel = $Channel
thread_ts = $Timestamp
text = "Response details"
blocks = @(
@{
type = "section"
text = @{
type = "mrkdwn"
text = "*Your Question:*`n> $question"
}
}
@{
type = "divider"
}
@{
type = "section"
text = @{
type = "mrkdwn"
text = "*Answer:*`n$answer"
}
}
)
}
exit 0Make script executable (Linux/Mac):
chmod +x scripts/question-bot.ps1# Build the C# test bot (optional, but good to verify)
cd TestBotCli
dotnet build -c Release
cd ..
# Run SlackServer
dotnet runYou should see:
info: SlackServer.Services.SlackListenerService[0]
Loaded 1 bot(s) from config.yaml
info: SlackServer.Services.SlackListenerService[0]
- Question Bot: channel | <@\w+>\s+.* | pwsh ./scripts/question-bot.ps1
info: SlackServer.Services.SlackListenerService[0]
Connecting to Slack via Socket Mode...
info: SlackServer.Services.SlackListenerService[0]
β
Connected to Slack! Ready to process bot commands.
- Go to your Slack channel
- Type:
@MyBot what is the weather? - Press Enter
Your bot should:
- Post "π€ Let me think about that..."
- Update it to show the answer
- Post a formatted response in the thread
bots:
- name: "Auto Responder"
type: channel
channelId: "C01234ABCDE"
messagePattern: ".*help.*" # Matches any message containing "help"
script: "pwsh ./scripts/help-bot.ps1"
timeout: 15bots:
- name: "DM Bot"
type: bot_dm # Only responds to DMs
messagePattern: ".*" # Matches any DM
script: "python ./bots/dm-handler.py"
timeout: 30bots:
- name: "Help Bot"
type: channel
channelId: "C01234ABCDE"
messagePattern: "^help"
script: "pwsh ./scripts/help.ps1"
timeout: 10
- name: "Deploy Bot"
type: channel
channelId: "C01234ABCDE"
messagePattern: "^deploy (staging|production)"
script: "pwsh ./scripts/deploy.ps1"
timeout: 120
- name: "Question Bot"
type: channel
channelId: "C01234ABCDE"
messagePattern: "<@\\w+>\\s+.*"
script: "pwsh ./scripts/question-bot.ps1"
timeout: 30# Example: Call Python CLI tool
$question = $Message -replace '<@\w+>\s*', ''
$result = python ./my-tool.py $question | Out-String
Send-SlackAction @{
action = "post_message"
channel = $Channel
thread_ts = $Timestamp
text = $result
}# Example: Call C# CLI tool
$answer = dotnet run --project ./MyCliTool -- $question | Out-String
Send-SlackAction @{
action = "post_message"
channel = $Channel
thread_ts = $Timestamp
text = "β
Result:`n``````$answer``````"
}Bots communicate by outputting line-delimited JSON (one JSON object per line) to stdout.
TRIGGER_MESSAGE # The full message text (includes @mention)
TRIGGER_CHANNEL # Channel ID (e.g., C01234ABCDE)
TRIGGER_TS # Message timestamp (unique ID)
TRIGGER_USER # User ID who sent the message (e.g., U01234ABCDE)
TRIGGER_USER_NAME # Username (display name)
BOT_NAME # Name of the bot from config{"action": "post_message", "channel": "$TRIGGER_CHANNEL", "text": "Hello!"}{"action": "post_message", "channel": "$TRIGGER_CHANNEL", "thread_ts": "$TRIGGER_TS", "text": "Reply"}{"action": "post_message", "channel": "$CHANNEL", "text": "Processing...", "store_as": "msg1"}
{"action": "update_message", "channel": "$CHANNEL", "message_ref": "msg1", "text": "Done!"}{
"action": "post_blocks",
"channel": "$TRIGGER_CHANNEL",
"thread_ts": "$TRIGGER_TS",
"text": "Fallback text",
"blocks": [
{
"type": "header",
"text": {"type": "plain_text", "text": "π Report"}
},
{
"type": "section",
"text": {"type": "mrkdwn", "text": "*Status:* β
Success"}
}
]
}{"action": "delete_message", "channel": "$CHANNEL", "message_ref": "msg1"}See DESIGN.md for complete protocol documentation.
Location: scripts/test-bot.ps1
Demonstrates all response types:
- Simple text messages
- Thread replies
- Rich Block Kit formatting
- Message updates (progress indicators)
Trigger: Send test ps in configured channel
Location: TestBotCli/
Demonstrates:
- Message analysis (length, word count)
- JSON code snippets in messages
- Progress indicators with updates
- Rich formatted blocks
Trigger: Send test cs in configured channel
# Publish the app
dotnet publish -c Release -o C:\SlackServer
# Copy config.yaml to publish directory
copy config.yaml C:\SlackServer\
# Create Windows service
sc.exe create SlackServer binPath="C:\SlackServer\SlackServer.exe" start=auto
sc.exe start SlackServer# Publish
dotnet publish -c Release -o /opt/slackserver
# Copy config
cp config.yaml /opt/slackserver/
# Create service file: /etc/systemd/system/slackserver.service
[Unit]
Description=SlackServer Bot Framework
After=network.target
[Service]
Type=notify
WorkingDirectory=/opt/slackserver
ExecStart=/usr/bin/dotnet /opt/slackserver/SlackServer.dll
Restart=always
User=slackserver
[Install]
WantedBy=multi-user.target
# Enable and start
sudo systemctl daemon-reload
sudo systemctl enable slackserver
sudo systemctl start slackserverSee TROUBLESHOOTING.md for detailed solutions to common issues.
Bot doesn't respond:
- Check logs for "Bot matched message"
- Verify channel ID in config
- Ensure bot is invited to channel:
/invite @YourBot - Test pattern at https://regex101.com/
"Permission denied" errors:
- Go to Slack App β OAuth & Permissions
- Verify all required scopes are added
- Click "Reinstall App" after adding scopes
Bot not connecting:
- Verify Socket Mode is enabled
- Check tokens start with
xapp-andxoxb- - Check logs for connection errors
Script not executing:
- Verify script path is correct
- Make script executable:
chmod +x(Linux/Mac) - Test manually with environment variables
More help: See TROUBLESHOOTING.md
- π QUICKSTART.md - 15-minute setup guide for @mention bots
- β TODO.md - Setup checklist to track your progress
- π README.md - This file - complete user guide
- ποΈ ARCHITECTURE.md - System architecture, diagrams, and component details
- π DESIGN.md - JSON protocol specification and implementation plan
- π STATUS.md - Current implementation status and roadmap
- π SUMMARY.md - Complete implementation summary
- βοΈ config.example.yaml - Configuration file examples
- π§ TROUBLESHOOTING.md - Solutions to common issues
- π¬
scripts/question-bot.ps1- @Mention bot that integrates with CLI tools - π§ͺ
scripts/test-bot.ps1- PowerShell bot demonstrating all features - π§
TestBotCli/- C# bot with message analysis
- Slack API Documentation
- Block Kit Builder - Design rich messages
- SlackNet Library - .NET Slack client
MIT License - See LICENSE file for details
Contributions welcome! Please read the design document first to understand the architecture.
#!/usr/bin/env pwsh
$message = $env:TRIGGER_MESSAGE
$channel = $env:TRIGGER_CHANNEL
$ts = $env:TRIGGER_TS
@{
action = "post_message"
channel = $channel
thread_ts = $ts
text = "You said: $message"
} | ConvertTo-Json -Compress | Write-Output#!/usr/bin/env python3
import os
import json
channel = os.getenv('TRIGGER_CHANNEL')
ts = os.getenv('TRIGGER_TS')
message = os.getenv('TRIGGER_MESSAGE')
# Post response
print(json.dumps({
'action': 'post_message',
'channel': channel,
'thread_ts': ts,
'text': f'Python bot received: {message}'
}))var channel = Environment.GetEnvironmentVariable("TRIGGER_CHANNEL")!;
var ts = Environment.GetEnvironmentVariable("TRIGGER_TS")!;
var message = Environment.GetEnvironmentVariable("TRIGGER_MESSAGE")!;
Console.WriteLine(JsonSerializer.Serialize(new {
action = "post_message",
channel = channel,
thread_ts = ts,
text = $"C# bot says: {message}"
}, new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower }));Ready to build your bot? Follow the setup guide above and start creating! π