A production-ready bot that automates daily team standups in Zulip. Features automated scheduling, AI-powered summaries, multi-timezone support, and robust database persistence.
- β¨ Features
- π Quick Start
- π Commands Reference
- π How It Works
- π Holiday Detection & Smart Scheduling
- ποΈ Architecture
- π³ Deployment
- βοΈ Configuration Reference
- π§ Customization
- π Monitoring & Maintenance
- π Troubleshooting
- π€ Contributing
- π License
- π Acknowledgments
- π Support
- π Automated Scheduling: Daily prompts, reminders, and summaries with precise timing
- π Multi-timezone Support: Each team member can set their own timezone
- π Holiday Detection: Built-in support for Nigeria and US holidays with smart skipping
- ποΈ Flexible Scheduling: Configure custom days and automatic holiday handling
- π§ Smart Prompts: Context-aware questions that adapt to gaps and holidays
- β Customizable Questions: Tailor standup questions to your team's workflow (1-5 questions)
- π€ AI-Powered Summaries: Intelligent team summaries using OpenAI GPT or Groq
- πΎ PostgreSQL/SQLite Support: Reliable data storage with connection pooling
- π‘οΈ Production Ready: Comprehensive error handling, logging, and monitoring
- π³ Easy Deployment: Docker, Docker Compose, and CapRover support
- π Interactive Workflow: Flexible questionnaire with dynamic completion logic
- π Rich Analytics: Search history, view trends, and track participation
- Zulip Server: A running Zulip instance with admin access
- Bot Account: Create a bot account in your Zulip organization
- Python 3.8+ or Docker
- Go to your Zulip organization settings
- Navigate to "Bots" section
- Add a new bot:
- Name: Standup Bot
- Username: standup-bot
- Bot type: Generic bot
- Download the bot's configuration file (
.zuliprc)
# Clone repository
git clone https://github.com/protomated/zulip-standup-bot.git
cd zulip-standup-bot
# Copy environment configuration
cp .env.example .env
# Edit .env with your configuration
nano .env
# Run with Docker Compose
docker-compose up -d# Clone repository
git clone https://github.com/protomated/zulip-standup-bot.git
cd zulip-standup-bot
# Create virtual environment
python3 -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
# Install dependencies (includes holiday detection library)
pip install -r requirements.txt
# Install the bot
pip install -e .
# Set up environment variables
cp .env.example .env
# Edit .env with your configuration
# Run the bot
python run_standup_bot.pyEdit your .env file with the following required settings:
# Zulip Configuration (Required)
ZULIP_EMAIL=standup-bot@your-zulip.com
ZULIP_API_KEY=your_api_key_here
ZULIP_SITE=https://your-zulip.com
# AI Configuration (Optional - for smart summaries)
OPENAI_API_KEY=sk-your_openai_key # Or use Groq
GROQ_API_KEY=gsk_your_groq_key # Alternative to OpenAI
# Database (Optional - defaults to SQLite)
DATABASE_URL=postgresql://user:pass@localhost/standup
# Bot Behavior (Optional - has sensible defaults)
DEFAULT_TIMEZONE=America/New_York
DEFAULT_PROMPT_TIME=09:30
DEFAULT_REMINDER_TIME=11:45
DEFAULT_CUTOFF_TIME=12:45
LOG_LEVEL=INFO- Add the bot to your team channel
- Send the setup command:
@standup-bot /standup setup
The bot will automatically:
- Configure daily standups with default times
- Add all human channel members as participants
- Schedule the first standup for the next business day
| Command | Description |
|---|---|
/standup setup |
Activate standup with default times (9:30 AM prompt, 11:45 AM reminder, 12:45 PM summary) |
/standup setup HH:MM |
Set custom prompt time only |
/standup setup HH:MM HH:MM HH:MM |
Set prompt, reminder, and cutoff times |
/standup config prompt_time HH:MM |
Change when daily prompts are sent |
/standup config reminder_time HH:MM |
Change when reminders are sent |
/standup config cutoff_time HH:MM |
Change when summaries are posted |
/standup config times HH:MM HH:MM HH:MM |
Set all times at once |
/standup config days weekdays |
Set which days to run (weekdays/weekend/all/custom) |
/standup config holidays Nigeria |
Set holiday country (Nigeria/US) |
/standup config skip_holidays true |
Enable/disable holiday skipping |
/standup config questions Q1, Q2, Q3 |
Set custom standup questions (comma-separated) |
/standup config questions reset |
Reset questions to defaults |
/standup config timezone <tz> |
Set channel timezone (e.g., America/New_York) |
| Command | Description |
|---|---|
/standup timezone <tz> |
Set your personal timezone |
/standup timezone |
View your current timezone |
| Command | Description |
|---|---|
/standup status |
View configuration and next scheduled events |
/standup pause |
Temporarily pause standups for this channel |
/standup resume |
Resume paused standups |
/standup participants |
View and manage team participants |
/standup test-prompt |
Send a test prompt immediately |
| Command | Description |
|---|---|
/standup history [days] |
View recent standup history (default: 7 days) |
/standup search <term> |
Search past standup responses |
/standup stats |
View participation statistics |
| Command | Description |
|---|---|
/standup debug |
Show technical details and scheduler status |
/standup help |
Show command help |
-
Morning Prompt (e.g., 9:30 AM)
- Bot sends private messages to all participants
- Asks the first configured question (default: "What did you work on yesterday?")
-
Interactive Questionnaire
- Bot asks follow-up questions based on your team's configuration
- Default: 3 questions about yesterday's work, today's plans, and blockers
- Custom: 1-5 questions tailored to your team's needs
- Completion marked when all questions are answered
-
Reminder (e.g., 11:45 AM)
- Friendly reminder sent to non-responders
- Includes quick action buttons for easy participation
-
Summary (e.g., 12:45 PM)
- AI-generated summary posted to channel
- Adapts to your question structure automatically
- Includes participation stats and key highlights
- Falls back to manual summary if AI unavailable
- Timezone Intelligence: Each user's prompts arrive at their local time
- Weekend Detection: Automatically skips weekends and holidays
- Participant Management: Automatically excludes bots and inactive users
- Graceful Degradation: Works without AI, database, or network issues
The bot includes built-in holiday detection for Nigeria and the United States, automatically skipping standups on official holidays and adapting prompts accordingly.
Nigeria π³π¬
- New Year's Day (January 1)
- Independence Day (October 1)
- Christmas Day (December 25)
- Boxing Day (December 26)
- All other official Nigerian holidays
United States πΊπΈ
- New Year's Day (January 1)
- Independence Day (July 4)
- Thanksgiving (4th Thursday in November)
- Christmas Day (December 25)
- All federal holidays including Memorial Day, Labor Day, etc.
- Automatic Skipping: When a scheduled standup day falls on a holiday, the bot automatically skips prompts, reminders, and summaries
- Smart Prompts: After holidays, prompts ask about the last actual work day instead of "yesterday"
- Configurable: Each channel can enable/disable holiday detection and choose their country
# Nigerian holidays (default)
/standup setup
# US holidays
/standup setup
/standup config holidays US
# Disable holiday skipping
/standup config skip_holidays false# Set holiday country
/standup config holidays Nigeria # Nigerian holidays
/standup config holidays US # United States holidays
# Control holiday skipping
/standup config skip_holidays true # Skip holidays (default)
/standup config skip_holidays false # Run on holidays too
# Combine with custom days
/standup config days weekdays # Monday-Friday only
/standup config holidays US # + skip US holidaysThe bot automatically adapts prompts based on holidays and configured days:
Regular Tuesday:
"What did you work on yesterday?"
Tuesday after Nigerian Independence Day (October 1):
"What did you work on last Thursday?" (skipped Friday holiday, weekend)
Wednesday after US Thanksgiving:
"What did you work on last Tuesday?" (before the long weekend)
Monday after Christmas weekend:
"What did you work on last Friday?" (before the holiday period)
Use /standup status to see current holiday configuration:
π― Standup Status for #engineering
π Configuration:
β’ Status: β
Active
β’ Timezone: America/New_York
β’ Days: Weekdays (Mon-Fri)
β’ Holiday Country: United States
β’ Skip Holidays: β
Enabled
β’ Participants: 8 members
Use /standup debug to see if today is a holiday:
π Channels:
β’ engineering: Prompt at 09:30 UTC, Holidays: United States π
(The π emoji appears when today is a holiday)
- Default Behavior: New channels default to Nigerian holidays with skipping enabled
- No Dependencies: Holiday detection gracefully degrades if the
holidayslibrary isn't available - Database Migration: Existing deployments automatically get holiday support with sensible defaults
- Logging: Holiday detection is logged for debugging and monitoring
- Main Bot Handler (
standup.py): Core bot logic and command routing - Database Layer (
database.py): PostgreSQL/SQLite operations with pooling - Scheduler (
APScheduler): Timezone-aware job scheduling - AI Integration (
ai_summary.py): OpenAI/Groq integration for summaries - Configuration (
config.py): Environment and default settings
The bot uses a PostgreSQL or SQLite database with the following tables:
- users: User preferences and timezone settings
- channels: Channel configuration and scheduling
- channel_participants: Team membership tracking
- standup_responses: Daily response storage with JSONB
- standup_prompts: Prompt tracking and pending responses
- Primary: Database storage for persistence and reliability
- Fallback: In-memory storage for temporary operation
- Automatic: Switches based on database availability
version: '3.8'
services:
standup-bot:
build: .
environment:
- ZULIP_EMAIL=standup-bot@your-zulip.com
- ZULIP_API_KEY=your_api_key
- ZULIP_SITE=https://your-zulip.com
- DATABASE_URL=postgresql://user:pass@db:5432/standup
depends_on:
- db
restart: unless-stopped
volumes:
- ./data:/app/data
db:
image: postgres:15
environment:
- POSTGRES_DB=standup
- POSTGRES_USER=standup_user
- POSTGRES_PASSWORD=your_secure_password
volumes:
- postgres_data:/var/lib/postgresql/data
restart: unless-stopped
volumes:
postgres_data:- Fork this repository
- Create a new CapRover app
- Connect your Git repository
- Set environment variables in app settings
- Deploy using the included
captain-definition
# Install system dependencies
sudo apt-get update
sudo apt-get install python3 python3-pip postgresql
# Clone and setup
git clone https://github.com/protomated/zulip-standup-bot.git
cd zulip-standup-bot
pip3 install -r requirements.txt
# Configure systemd service
sudo cp standup-bot.service /etc/systemd/system/
sudo systemctl enable standup-bot
sudo systemctl start standup-bot| Variable | Description | Example |
|---|---|---|
ZULIP_EMAIL |
Bot's email address | standup-bot@company.zulipchat.com |
ZULIP_API_KEY |
Bot's API key from Zulip | abcd1234... |
ZULIP_SITE |
Zulip server URL | https://company.zulipchat.com |
| Variable | Default | Description |
|---|---|---|
OPENAI_API_KEY |
None | OpenAI API key for AI summaries |
GROQ_API_KEY |
None | Groq API key (alternative to OpenAI) |
DATABASE_URL |
SQLite file | PostgreSQL connection string |
DEFAULT_TIMEZONE |
Africa/Lagos |
Default timezone for new channels |
DEFAULT_PROMPT_TIME |
09:30 |
Default time to send prompts |
DEFAULT_REMINDER_TIME |
11:45 |
Default time to send reminders |
DEFAULT_CUTOFF_TIME |
12:45 |
Default time to post summaries |
DEFAULT_HOLIDAY_COUNTRY |
Nigeria |
Default holiday country (Nigeria/United States) |
DEFAULT_SKIP_HOLIDAYS |
true |
Default holiday skipping setting |
LOG_LEVEL |
INFO |
Logging level (DEBUG, INFO, WARNING, ERROR) |
# PostgreSQL (recommended for production)
DATABASE_URL=postgresql://user:password@localhost:5432/standup
# SQLite (good for development)
DATABASE_URL=sqlite:///./data/standup.db# OpenAI (more accurate, higher cost)
OPENAI_API_KEY=sk-your-key-here
OPENAI_MODEL=gpt-3.5-turbo
# Groq (faster, lower cost)
GROQ_API_KEY=gsk-your-key-here
GROQ_MODEL=llama-3.1-8b-instantTo add support for other AI providers, extend the ai_summary.py module:
class CustomAIProvider:
def generate_summary(self, responses):
# Your implementation here
return summary_textModify the questions in standup.py:
STANDUP_QUESTIONS = [
"What did you accomplish yesterday?",
"What are your goals for today?",
"What challenges are you facing?"
]The bot allows you to customize the questions asked during standups to better fit your team's workflow and needs.
By default, the bot asks these 3 questions:
- "What did you work on {last_day}?"
- "What are you planning to work on today?"
- "Any blockers or issues you're facing?"
# Set custom questions (comma-separated)
/standup config questions What are your top 3 priorities today?, What help do you need from teammates?, What did you learn yesterday?
# Single question workflow
/standup config questions What's your main focus for today?
# Reset to default questions
/standup config questions reset- Dynamic Day References: Use
{last_day}placeholder to automatically reference the last working day - Flexible Workflow: Support 1-5 custom questions per standup
- Team-Specific: Each channel can have different questions
- Smart Adaptation: Bot adjusts prompts and completion logic based on question count
Engineering Team:
/standup config questions What did you ship {last_day}?, What are you building today?, Any technical blockers?Product Team:
/standup config questions What customer insights did you gather {last_day}?, What features are you prioritizing today?, What feedback needs addressing?Sales Team:
/standup config questions How many prospects did you contact {last_day}?, What deals are you closing today?, What support do you need?Coaching Cohort:
/standup config questions What progress did you make on your goals {last_day}?, What are you committed to achieving today?, What support or accountability do you need?Single Question (Daily Focus):
/standup config questions What is your #1 priority today and how can the team help?Check your current question configuration with /standup status:
β Questions (Custom):
1. What are your top 3 priorities today?
2. What help do you need from teammates?
3. What did you learn yesterday?
The bot supports all standard timezone names. Common examples:
America/New_York(Eastern Time)America/Chicago(Central Time)America/Denver(Mountain Time)America/Los_Angeles(Pacific Time)Europe/London(GMT/BST)Europe/Berlin(CET/CEST)Asia/Tokyo(JST)
The bot includes built-in health monitoring:
# Check bot status
curl http://localhost:5002/health
# View metrics
curl http://localhost:5002/metricsLogs are structured and include:
- Timestamp and log level
- Component and operation context
- Performance metrics
- Error details and stack traces
The bot automatically:
- Cleans up old data (>90 days)
- Optimizes database performance
- Manages connection pooling
- Handles schema migrations
For production deployments:
# PostgreSQL backup
pg_dump standup > backup_$(date +%Y%m%d).sql
# SQLite backup
cp data/standup.db backup_$(date +%Y%m%d).db- Check Status: Use
/standup debugto see scheduler status - Verify Configuration: Ensure all environment variables are set
- Check Logs: Look for error messages in application logs
- Test Connection: Verify bot can connect to Zulip
- Verify Setup: Check
/standup statusshows active configuration - Check Timezone: Ensure timezone settings are correct
- Verify Participants: Confirm users are added to channel
- Test Manually: Use
/standup test-promptto test immediately
- Check API Key: Verify
OPENAI_API_KEYorGROQ_API_KEYis set - Check Credits: Ensure API account has sufficient credits
- Review Logs: Look for API error messages
- Fallback Mode: Bot continues with manual summaries
- Check URL: Verify
DATABASE_URLformat is correct - Check Permissions: Ensure database user has required permissions
- Test Connection: Use database client to verify connectivity
- Fallback Mode: Bot switches to in-memory storage automatically
# Show detailed status
/standup debug
# Test immediate prompt
/standup test-prompt
# Check configuration
/standup status
# View recent activity
/standup history 1For large teams (50+ members):
-
Database Optimization:
- Use PostgreSQL instead of SQLite
- Enable connection pooling
- Add database indexes
-
Scheduler Tuning:
- Increase APScheduler thread pool size
- Optimize job execution intervals
-
Monitoring:
- Enable detailed logging
- Set up metrics collection
- Monitor database performance
We welcome contributions! Please see our contributing guidelines:
# Fork and clone
git clone https://github.com/protomated/zulip-standup-bot.git
cd zulip-standup-bot
# Setup development environment
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
pip install -e .
# Run tests
python -m pytest
# Code formatting
python -m black .
python -m isort .- Black for code formatting
- isort for import sorting
- mypy for type checking
- pytest for testing
- Create a feature branch
- Write tests for new functionality
- Ensure all tests pass
- Update documentation
- Submit a pull request
This project is licensed under the MIT License - see the LICENSE file for details.
- Built on the Zulip Bot Framework
- Powered by APScheduler for reliable scheduling
- AI summaries by OpenAI and Groq
- Database support via PostgreSQL and SQLite
- Documentation: Full documentation
- Issues: GitHub Issues
- Discussions: GitHub Discussions
Made with β€οΈ for distributed teams everywhere by Protomated