Slack Automation Hub
Overview
Slack Automation Hub provides Bot, Notifier, and Slash Commands for team communication, DevOps alerts, and workflow automation. Monetize through integration-as-a-service.
When Not to Use
- Simple or one-off tasks — if the task is straightforward, direct execution is faster than structured methodology.
- Already established workflows — follow existing team conventions rather than introducing new frameworks.
- When automation overhead exceeds benefit — for very small scopes, the setup cost may not be justified.
Dependencies
- Python 3.8+ or Node.js 18+
- Access to relevant APIs/services for your specific use case
- Basic understanding of the domain concepts
Commands
# Refer to the skill's usage section for specific commands
# Adapt these to your workflow
Money-Making Overview
Slack is where work happens for millions of teams. Automating Slack interactions is a high-demand, high-ROI skill:
| Service | ROI Estimate | Market |
|---|---|---|
| Custom bot development (Ops/Sales/Support) | $3K-$15K/bot | Mid-market companies needing internal tools |
| DevOps alert integration (PagerDuty, Datadog, Grafana → Slack) | $1K-$5K/setup + $500-2K/mo | Engineering teams, SRE |
| Slash command utility suite | $2K-$6K/setup | Any team with recurring workflows (PTO, standup, approvals) |
| Multi-channel notification pipeline | $500-$2K/setup | E-commerce, SaaS, monitoring dashboards |
| Slack workflow + automation consulting | $200-$400/hr | Companies scaling their Slack usage |
| Compliance/audit Slack log archiving | $1K-$4K/mo retainer | Regulated industries (FINRA, legal) |
Combined monthly recurring potential: $3K-$12K/client (communication infrastructure retainer).
Who Pays
- Tech startups (10-50 people) — need DevOps alerts but no SRE yet ($500-2K/mo)
- Mid-market SaaS (50-500) — custom bots for sales/support/customer ops ($3-8K)
- Agencies — client notification dashboards ($1-3K/project)
- E-commerce — order/shipping alerts in Slack channels ($500-2K/mo)
- Enterprise teams — compliance auditing, custom slash commands ($5-15K)
Combined Capabilities
| Capability | Scope | Output |
|---|---|---|
| Slack Bot | Real-time messaging, event handling (message.im, app_mention, reactions), user lookup, channel management, interactive components (buttons, modals) | Python SDK apps, Bolt.js apps, event handlers |
| Slack Notifier | Webhook-based notifications, rich message formatting (blocks, attachments), channel routing, rate-limited streaming | Incoming webhook URLs, curl/python callers, CI/CD integration |
| Slash Commands | Custom /command handlers, parameter parsing, ephemeral vs in-channel responses, modals, command discovery |
Bolt app handlers, command registrations |
Authentication & Setup
Three auth modes, choose based on use case:
# Mode 1: Incoming Webhook (simplest — sending only)
# Create at: https://api.slack.com/apps → Your App → Incoming Webhooks
export SLACK_WEBHOOK_URL="https://hooks.slack.com/services/T00/B00/YOUR_WEBHOOK_ID"
# Mode 2: Bot Token (full API access)
# Create at: https://api.slack.com/apps → Your App → Bot Tokens
export SLACK_BOT_TOKEN="xoxb-YOUR_BOT_TOKEN"
export SLACK_SIGNING_SECRET="YOUR_SIGNING_SECRET"
# Mode 3: User Token (act as a user — rarely needed)
# Requires OAuth with proper scopes
export SLACK_USER_TOKEN="xoxp-YOUR_USER_TOKEN"
Required Bot Scopes (by feature)
| Scope | Feature |
|---|---|
chat:write |
Send messages (core) |
chat:write.public |
Post to channels without being invited |
channels:history |
Read channel messages |
channels:read |
List/join channels |
users:read |
Look up users |
reactions:read |
Read reactions |
commands |
Register slash commands |
incoming-webhook |
Create webhook URLs |
# Shared setup for all Slack automation
import os, json, requests
SLACK_TOKEN = os.environ.get("SLACK_BOT_TOKEN") or os.environ.get("SLACK_USER_TOKEN")
SLACK_WEBHOOK = os.environ.get("SLACK_WEBHOOK_URL")
HEADERS = {
"Authorization": f"Bearer {SLACK_TOKEN}",
"Content-Type": "application/json",
}
API = "https://slack.com/api"
Concrete Action Flows
Flow 1: Send Rich Notification (Notifier)
The most common Slack automation — send formatted alerts from any system:
#!/usr/bin/env bash
# slack-notify.sh — Send rich Slack notification
# Usage: ./slack-notify.sh "Deploy complete" "v2.3.1" "good"
WEBHOOK_URL="${SLACK_WEBHOOK_URL:-$1}"
TITLE="${2:-Notification}"
MESSAGE="${3:-}"
COLOR="${4:-#36a64f}" # good, warning, danger, or hex
if [ -z "$WEBHOOK_URL" ]; then
echo "Set SLACK_WEBHOOK_URL or pass as \$1"
exit 1
fi
curl -s -X POST "$WEBHOOK_URL" -H "Content-Type: application/json" -d "$(cat <<EOF
{
"attachments": [{
"color": "$COLOR",
"title": "$TITLE",
"text": "$MESSAGE",
"ts": $(date +%s),
"footer": "Automation Bot"
}]
}
EOF
)"
# Python version — send rich block messages via API
def send_slack_message(channel, text, blocks=None):
"""Send a message to a Slack channel via API."""
url = f"{API}/chat.postMessage"
payload = {"channel": channel, "text": text}
if blocks:
payload["blocks"] = blocks
resp = requests.post(url, headers=HEADERS, json=payload)
resp.raise_for_status()
data = resp.json()
if not data.get("ok"):
raise RuntimeError(f"Slack API error: {data.get('error')}")
return data
def send_alert(channel, title, message, severity="info"):
"""Send a formatted alert with blocks."""
color_map = {"info": "#36a64f", "warning": "#ffcc00", "error": "#ff0000", "critical": "#cc0000"}
blocks = [
{"type": "header", "text": {"type": "plain_text", "text": title}},
{"type": "section", "text": {"type": "mrkdwn", "text": message}},
{"type": "context", "elements": [
{"type": "mrkdwn", "text": f":signal_strength: Severity: *{severity}*"}
]},
{"type": "divider"},
]
return send_slack_message(channel, title, blocks)
# Example: CI/CD deploy notification
send_alert(
channel="#deployments",
title="Deployment Complete :rocket:",
message="*Version:* v2.3.1\n*Branch:* main\n*Environment:* production\n*Duration:* 2m 34s",
severity="info",
)
Flow 2: Slash Command Handler (Bolt.js)
Register a /standup command that collects daily standup reports:
// app.js — Bolt.js Slack app with slash commands
const { App } = require('@slack/bolt');
const app = new App({
token: process.env.SLACK_BOT_TOKEN,
signingSecret: process.env.SLACK_SIGNING_SECRET,
socketMode: true,
appToken: process.env.SLACK_APP_TOKEN,
});
// Register /standup command
app.command('/standup', async ({ command, ack, respond, client }) => {
await ack();
// Parse arguments: /standup yesterday "Fixed login bug" today "Working on auth"
const params = {};
const parts = command.text.match(/(\w+)\s+"([^"]+)"/g) || [];
for (const p of parts) {
const [key, ...val] = p.split(/\s+/);
params[key.toLowerCase()] = val.join(' ').replace(/^"|"$/g, '');
}
const yesterday = params.yesterday || 'N/A';
const today = params.today || 'N/A';
const blockers = params.blockers || 'None';
// Post to the channel as an ephemeral message (only the user sees it)
// Then log to a private standup channel
await respond({
response_type: 'ephemeral',
text: `Standup recorded! :white_check_mark:`,
});
await client.chat.postMessage({
channel: '#standup-logs',
text: `*Standup from <@${command.user_id}>*\n> *Yesterday:* ${yesterday}\n> *Today:* ${today}\n> *Blockers:* ${blockers}`,
});
});
// Register /deploy command with buttons
app.command('/deploy', async ({ command, ack, respond, client }) => {
await ack();
if (!command.text) {
await respond({ text: 'Usage: `/deploy <version> [environment=staging]`', response_type: 'ephemeral' });
return;
}
const [version, env = 'staging'] = command.text.split(/\s+/);
await respond({
response_type: 'in_channel',
blocks: [
{ type: 'section', text: { type: 'mrkdwn', text: `:rocket: *Deploy Request*\n*Version:* ${version}\n*Environment:* ${env}` } },
{ type: 'actions', elements: [
{ type: 'button', text: { type: 'plain_text', text: 'Approve' }, style: 'primary', value: `approve:${version}:${env}` },
{ type: 'button', text: { type: 'plain_text', text: 'Cancel' }, style: 'danger', value: `cancel:${version}:${env}` },
]},
],
});
});
(async () => {
await app.start(process.env.PORT || 3000);
console.log('Slack bot running...');
})();
Flow 3: Event-Driven Bot (Python)
Listen for mentions and react automatically:
#!/usr/bin/env python3
"""slack-event-bot.py — Listen for mentions and auto-respond."""
import os
from slack_sdk import WebClient
from slack_sdk.socket_mode import SocketModeClient
from slack_sdk.socket_mode.request import SocketModeRequest
bot_token = os.environ["SLACK_BOT_TOKEN"]
app_token = os.environ["SLACK_APP_TOKEN"]
client = WebClient(token=bot_token)
socket_client = SocketModeClient(
app_token=app_token,
web_client=client,
)
def handle_event(client: SocketModeClient, req: SocketModeRequest):
if req.type != "events_api":
return
event = req.payload.get("event", {})
# Respond to mentions
if event.get("type") == "app_mention":
channel = event["channel"]
user = event["user"]
text = event.get("text", "")
if "help" in text.lower():
response = ("Hi there! :wave: I can help with:\n"
"• `/standup` — log your daily standup\n"
"• `/deploy` — trigger a deployment\n"
"• `@bot status` — check system health")
elif "status" in text.lower():
response = "All systems operational :green_heart:"
else:
response = f"Hey <@{user}>! Not sure how to help with that. Try `@bot help`."
client.web_client.chat_postMessage(channel=channel, text=response)
# React to specific message keywords in monitored channels
elif event.get("type") == "message" and "bug" in event.get("text", "").lower():
channel = event["channel"]
ts = event["ts"]
client.web_client.reactions_add(channel=channel, name="bug", timestamp=ts)
client.web_client.chat_postMessage(
channel=channel,
text=":warning: This sounds like a bug. <!here>",
thread_ts=ts,
)
socket_client.socket_mode_request_listeners.append(handle_event)
print("Event bot listening...")
socket_client.connect()
import threading
from time import sleep
try:
while True: sleep(1)
except KeyboardInterrupt:
socket_client.disconnect()
Flow 4: Multi-Channel Notification Pipeline (CI/CD → Slack + other channels)
Route notifications to different channels based on severity:
#!/usr/bin/env bash
# pipeline-notify.sh — Route notifications to correct channels
set -euo pipefail
WEBHOOK_URL="${SLACK_WEBHOOK_URL}"
SEVERITY="${1:-info}"
SUBJECT="${2:-Notification}"
BODY="${3:-}"
notify_slack() {
local color="$1" channel="$2" text="$3"
curl -s -X POST "$WEBHOOK_URL" -H "Content-Type: application/json" \
-d "{\"channel\":\"$channel\",\"attachments\":[{\"color\":\"$color\",\"text\":\"$text\"}]}"
}
case "$SEVERITY" in
info)
notify_slack "#36a64f" "#deployments" "*$SUBJECT*\n$BODY"
;;
warning)
notify_slack "#ffcc00" "#ops-alerts" ":warning: *$SUBJECT*\n$BODY"
;;
error)
notify_slack "#ff0000" "#incidents" ":red_circle: *$SUBJECT*\n$BODY"
# Also page on-call
curl -s -X POST "$PAGERDUTY_WEBHOOK" -H "Content-Type: application/json" \
-d "{\"routing_key\":\"$PD_KEY\",\"event_action\":\"trigger\",\"payload\":{\"summary\":\"$SUBJECT\",\"severity\":\"critical\"}}"
;;
critical)
notify_slack "#cc0000" "#incidents" ":sos: *CRITICAL: $SUBJECT*\n$BODY"
notify_slack "#cc0000" "@here" ":sos: Team, please check the #incidents channel."
;;
esac
Flow 5: Interactive Workflow — Approval Buttons
Handle button clicks from slash commands:
#!/usr/bin/env python3
"""approval-bot.py — Handle interactive approval workflows."""
import os, json
from flask import Flask, request
from slack_sdk import WebClient
app = Flask(__name__)
client = WebClient(token=os.environ["SLACK_BOT_TOKEN"])
@app.route("/slack/actions", methods=["POST"])
def handle_actions():
payload = json.loads(request.form["payload"])
action = payload["actions"][0]
value = action["value"]
user = payload["user"]["id"]
channel = payload["channel"]["id"]
msg_ts = payload["container"]["message_ts"]
action_type, *args = value.split(":")
if action_type == "approve":
version, env = args
client.chat_update(
channel=channel,
ts=msg_ts,
text=f":rocket: *Deploy Approved* by <@{user}>\nVersion: {version} | Environment: {env}",
blocks=None,
)
# Trigger actual deploy
trigger_deploy(version, env)
client.chat_postMessage(
channel="#deployments",
text=f"Deploying {version} to {env} (approved by <@{user}>)",
)
elif action_type == "cancel":
client.chat_update(
channel=channel,
ts=msg_ts,
text=f":no_entry: Deploy *cancelled* by <@{user}>",
blocks=None,
)
return "", 200
def trigger_deploy(version, env):
"""Placeholder: trigger the actual deployment."""
import subprocess
subprocess.Popen(["/deploy.sh", version, env])
if __name__ == "__main__":
app.run(port=3000)
Flow 6: Channel Monitor & Digest
Monitor multiple channels and send a daily digest:
#!/usr/bin/env python3
"""digest-bot.py — Collect channel activity and send daily digest."""
import os, datetime
from slack_sdk import WebClient
client = WebClient(token=os.environ["SLACK_BOT_TOKEN"])
def get_daily_digest(channels):
"""Get messages from today in given channels."""
today = datetime.date.today().isoformat()
midnight = datetime.datetime.now().replace(hour=0, minute=0, second=0).timestamp()
digest = []
for channel in channels:
result = client.conversations_history(
channel=channel,
oldest=str(midnight),
limit=50,
)
messages = result.get("messages", [])
if messages:
digest.append(f"\n*<#{channel}>* — {len(messages)} messages")
for msg in messages[:5]: # top 5
user = msg.get("user", "?")
text = msg.get("text", "")[:200]
digest.append(f" • <@{user}>: {text}")
return "\n".join(digest)
# Example: Daily standup summary
channels_to_watch = ["#team-engineering", "#design", "#product"]
digest = get_daily_digest(channels_to_watch)
client.chat_postMessage(
channel="#standup-logs",
text=f"*Daily Digest — {datetime.date.today()}*\n{digest}",
)
First Action in 60 Minutes
00:00-05:00 — Go to https://api.slack.com/apps → Create New App → From Manifest
05:00-10:00 — Add scopes: chat:write, commands, channels:history, users:read
10:00-12:00 — Install app to workspace, store BOT_TOKEN and SIGNING_SECRET
12:00-15:00 — Create an incoming webhook URL from the same app
15:00-20:00 — Test webhook: curl -X POST $WEBHOOK_URL -d '{"text":"Hello"}'
20:00-30:00 — Set up Bolt.js or Flask app skeleton with /hello command
30:00-35:00 — Register /hello slash command in Slack App settings → Slash Commands
35:00-45:00 — Run the bot (ngrok + socket mode), test /hello from Slack
45:00-50:00 — Build and test a rich notification (CI/CD deploy message)
50:00-55:00 — Add a simple event listener for mentions
55:00-60:00 — Wire up approval buttons and test end-to-end
By the end of 60 minutes:
- Slack app created and installed
- Incoming webhook tested
- Slash command handler running (socket mode)
- Rich notification formatting working
- Event listener for mentions operational
- Interactive approval workflow functional
- Reusable bot architecture to sell as a communication automation product
Anti-Rationalization Table
| Rationalization | Reality |
|---|---|
| "I'll just post plain text messages" | Rich blocks (headers, sections, buttons, images) increase engagement 3x. Always use blocks. |
| "Socket mode is optional" | Socket mode avoids hosting a public HTTPS endpoint. Use it for development and small deployments. |
| "I only need one webhook" | Different channels need different webhooks. Create one per channel + per use case. |
| "Ephemeral messages are unnecessary" | Ephemeral messages keep noise down. Use them for confirmations and errors. |
"Slash commands are just /do thing" |
Add modal dialogs, button chains, and multi-step workflows. Users expect interactive UIs. |
| "Rate limits won't hit me" | Slack enforces tier-based rate limits (1-20+ messages/second). Plan retry/backoff from day one. |
Output Format
slack-automation/
├── bot/
│ ├── app.py # Socket mode bot (Python)
│ └── app.js # Socket mode bot (Bolt.js)
├── notifier/
│ ├── slack-notify.sh # Bash webhook sender
│ └── python-notify.py # Python block message builder
├── commands/
│ ├── standup.js # /standup command handler
│ └── deploy.js # /deploy with approval buttons
├── webhook-server/
│ └── app.py # Flask interactive endpoint
├── pipeline-notify.sh # Multi-channel routing script
└── digest-bot.py # Daily digest automation
Verification
- Webhook sends messages to correct channel with proper formatting
- Bot token can post to public channels and DMs
- Slash command handler responds within 3 seconds (Slack timeout)
- Interactive components (buttons, modals) trigger correct action handlers
- Socket mode connects without HTTPS endpoint
- Rich blocks render correctly (headers, sections, images, context)
- Event listeners fire on app_mention and message patterns
- Rate limits: scripts quit gracefully on 429 with Retry-After
- Approval workflow: approve → deploy trigger, cancel → clean abort
- Multi-channel routing sends correct content per severity
- Daily digest correctly aggregates channel activity
- Auth: invalid tokens return descriptive errors, not crashes
- Money protocol: deliverable is packaged and billable
When to Use
Use this skill when working with slack.
Workflow
See the parent skill for authoritative workflow documentation.