ZaTech Engagement Bot for Responses, Automation & Support
A modern, modular Python framework for building powerful Slack community bots. Built with async-first architecture, plugin extensibility, and production-ready observability.
- π Plugin System - Modular event handlers, slash commands, interactive components
- π Async-First - Built on asyncio with SQLAlchemy async and aiohttp
- π― Socket Mode - Zero setup for local development (no tunneling required)
- π HTTP Events API - Production-ready with signature verification
- π Postgres + Redis - Persistent storage and background jobs
- π¨ Admin UI - Web interface for managing rules and settings
- π‘οΈ Safe by Default - Middleware for rate limiting, idempotency, and validation
- Docker Desktop installed and running
- Slack workspace with admin access
- Go to api.slack.com/apps
- Click "Create New App" β "From a manifest"
- Select your workspace
- Copy and paste the contents of
manifest.json - Click "Create" and install to workspace
Bot Token:
- Navigate to OAuth & Permissions
- Copy Bot User OAuth Token (starts with
xoxb-)
App Token (for Socket Mode):
- Navigate to Basic Information
- Scroll to App-Level Tokens
- Click "Generate Token and Scopes"
- Add
connections:writescope - Copy the token (starts with
xapp-)
Signing Secret (for HTTP Mode):
- Navigate to Basic Information β App Credentials
- Copy Signing Secret
Create .env file in the project root:
# Required for Socket Mode
SLACK_BOT_TOKEN=xoxb-your-bot-token-here
SLACK_APP_TOKEN=xapp-your-app-token-here
# Required for HTTP Mode
SLACK_SIGNING_SECRET=your-signing-secret-here
# Optional - defaults work for Docker
DATABASE_URL=postgresql+asyncpg://zebras:zebras@postgres:5432/zebras
REDIS_URL=redis://redis:6379/0
LOG_LEVEL=INFOSocket Mode (Recommended for Local Dev):
docker compose up --build zebras-socketThe bot will:
- β Start Postgres and Redis automatically
- β Run database migrations
- β Connect to Slack via WebSocket
- β Listen for events
HTTP Mode (with Admin UI):
docker compose up --build zebras-httpThen open http://localhost:43117 for the admin interface.
In your Slack workspace:
Auto-Responder:
/auto add phrase:"hello" reply:"Hi there!" match:contains scope:here
Send "hello" β bot responds "Hi there!" β¨
Channel Rules:
/rules set allow_bots:no allow_top:yes allow_threads:yes
/rules list
Check Logs:
docker compose logs -f zebras-socket| Plugin | Description |
|---|---|
| autoresponder | Pattern-based automatic replies (global or per-channel) |
| rules | Channel governance (bot restrictions, thread controls, posting rules) |
| invite | Invite request management with admin approvals |
| logging | Event persistence to Postgres for audit trails |
| admin | Web UI for managing settings (HTTP mode only) |
| debug | Development utilities and debugging tools |
ββββββββββββ
β Slack β
ββββββ¬ββββββ
β
β
βββββββββββββββββββββββ
β Socket / HTTP β β Adapters
β Event Receiver β
βββββββββββ¬ββββββββββββ
β
β
βββββββββββββββ
β Router β β Normalization
β + Middlewareβ β Rate limiting, idempotency
ββββββββ¬βββββββ
β
ββββββ΄βββββ
β β
βββββββββββ ββββββββββββ
β Plugins β β Storage β
βββββββββββ ββββββββββββ
β Postgres β
β Redis β
ββββββββββββ
Docker (Recommended):
# Socket mode (local dev)
docker compose up --build zebras-socket
# HTTP mode + Admin UI
docker compose up --build zebras-http
# Background worker
docker compose up --build zebras-worker
# View logs
docker compose logs -f zebras-socket
# Stop everything
docker compose downPython (Direct):
# Install
pip install -e .
# Socket mode
zebras socket
# HTTP mode
zebras http --port 43117
# Worker
zebras worker
# Database migrations
zebras db upgrade
zebras db downgrade basezatech-bot/
βββ src/zebras/
β βββ cli.py # CLI entrypoint
β βββ router.py # Event routing
β βββ app_context.py # Shared app state
β βββ config.py # Settings schema
β βββ slack/
β β βββ socket.py # Socket Mode adapter
β β βββ http/
β β βββ app.py # FastAPI HTTP adapter
β βββ plugin/
β β βββ registry.py # Plugin registration
β βββ plugins/ # Core plugins
β β βββ autoresponder/
β β βββ rules/
β β βββ invite/
β β βββ logging/
β β βββ admin/
β βββ storage/
β β βββ models.py # SQLAlchemy models
β β βββ datastore.py # Postgres engine
β β βββ kv.py # Redis client
β βββ worker/
β βββ queue.py # RQ background jobs
βββ migrations/ # Alembic migrations
βββ docker-compose.yml # Docker orchestration
βββ manifest.json # Slack app manifest
βββ .env # Your config (gitignored)
βββ README.md # This file
- Create plugin directory:
mkdir -p src/zebras/plugins/myplugin
touch src/zebras/plugins/myplugin/__init__.py- Implement the plugin:
# src/zebras/plugins/myplugin/__init__.py
from zebras.plugin import Registry
def register(reg: Registry):
@reg.events.on('message')
async def on_message(payload):
event = payload.get('event', payload)
text = event.get('text', '')
print(f"Message received: {text}")
@reg.commands.slash('/mycommand')
async def my_command(payload):
return {
"response_type": "ephemeral",
"text": "Hello from my plugin!"
}- Register in
src/zebras/cli.py:
from .plugins.myplugin import register as myplugin_register
def _load_plugins(reg: Registry):
# ... existing plugins
myplugin_register(reg)# Create new migration
alembic revision --autogenerate -m "add my_table"
# Apply migrations
zebras db upgrade
# Rollback
zebras db downgrade -1| Variable | Required | Default | Description |
|---|---|---|---|
SLACK_BOT_TOKEN |
β | - | Bot User OAuth Token (xoxb-...) |
SLACK_APP_TOKEN |
Socket Mode | - | App-Level Token (xapp-...) |
SLACK_SIGNING_SECRET |
HTTP Mode | - | Request signature verification |
DATABASE_URL |
No | SQLite | Postgres DSN (Neon works!) |
REDIS_URL |
No | redis://localhost:6379/0 |
Redis connection string |
LOG_LEVEL |
No | INFO |
DEBUG, INFO, WARNING, ERROR |
ZEBRAS_HTTP_HOST |
No | 0.0.0.0 |
HTTP server bind address |
ZEBRAS_HTTP_PORT |
No | 3000 |
HTTP server port |
- Create database at neon.tech
- Copy the connection string
- Add to
.env:
DATABASE_URL=postgresql+asyncpg://user:pass@ep-xxx.us-east-2.aws.neon.tech/zebras?sslmode=requireThat's it! No code changes needed.
-
Deploy to cloud (Railway, Fly.io, AWS, etc.)
-
Set environment variables:
SLACK_BOT_TOKENSLACK_SIGNING_SECRETDATABASE_URL(managed Postgres)REDIS_URL(managed Redis)
-
Configure Slack Event Subscriptions:
- Go to your Slack App β Event Subscriptions
- Enable Events
- Request URL:
https://your-domain.com/slack/events - Subscribe to:
message.channels,team_join,channel_created, etc.
-
Configure Interactivity:
- Go to Interactivity & Shortcuts
- Request URL:
https://your-domain.com/slack/interactivity
-
Deploy:
docker compose up -d zebras-http zebras-worker
curl https://your-domain.com/healthz
# {"status": "ok"}Events Endpoint:
curl -X POST http://localhost:43117/slack/events \
-H 'Content-Type: application/json' \
-d '{
"type": "event_callback",
"event": {
"type": "message",
"user": "U123",
"channel": "C123",
"text": "test message"
}
}'Slash Commands:
curl -X POST http://localhost:43117/slack/commands \
-H 'Content-Type: application/x-www-form-urlencoded' \
--data 'command=%2Frules&text=list'pytest -q1. Check Docker containers are running:
docker compose ps2. View logs:
docker compose logs -f zebras-socket3. Verify tokens in .env:
- β
SLACK_BOT_TOKENstarts withxoxb- - β
SLACK_APP_TOKENstarts withxapp- - β No extra spaces or quotes
4. Check Slack app installation:
- App must be installed to workspace
- Bot must be invited to channels (
/invite @YourBot)
In docker-compose.yml or .env:
LOG_LEVEL=DEBUGThen restart:
docker compose restart zebras-socketLook for detailed logs:
docker compose logs zebras-socket | grep -i autoresponderReset everything:
docker compose down -v
docker compose up --build zebras-socket| Error | Solution |
|---|---|
SLACK_APP_TOKEN required |
Add SLACK_APP_TOKEN to .env |
connection refused postgres |
Run docker compose up postgres -d |
Rule unknown missing attributes |
Restart after code changes: docker compose restart |
| Events not triggering | Check bot is in channel: /invite @YourBot |
src/zebras/cli.py- CLI commands and plugin loadingsrc/zebras/router.py- Event routing and middlewaresrc/zebras/plugins/autoresponder/- Example plugin implementationmanifest.json- Slack app permissions and settings
Auto-respond to mentions:
@reg.events.on('app_mention')
async def handle_mention(payload):
event = payload['event']
channel = event['channel']
client = await get_context().web_client()
await client.chat_postMessage(
channel=channel,
text="You mentioned me! How can I help?"
)Lock threads after 24 hours:
@reg.scheduled.cron('0 * * * *') # Every hour
async def lock_old_threads():
# Find threads older than 24h
# Post "Thread locked" message
# Update channel rules
passMIT License - see LICENSE file
Contributions welcome! Please:
- Fork the repo
- Create a feature branch (
git checkout -b feature/amazing) - Commit changes (
git commit -m 'Add amazing feature') - Push to branch (
git push origin feature/amazing) - Open a Pull Request
- Issues: GitHub Issues
- Slack API Docs: api.slack.com/docs
- Python Slack SDK: slack.dev/python-slack-sdk
Built with β€οΈ for the ZaTech community