Automate Slack Standup Reports with Python and AI
Daily standups are supposed to take five minutes, but in practice they eat into everyone's morning: people forget to post, updates arrive in six different formats, and whoever is supposed to summarize progress for leadership ends up scrolling through a wall of messages by hand. You can automate Slack standup reports with Python to collect updates from a channel, use AI to summarize progress and flag blockers, and post a clean, structured digest automatically — no manual copy-pasting required.
This tutorial builds a working script that pulls messages from a Slack standup channel, sends them to an AI model for summarization, and posts a formatted report back to the team, all on a schedule you control.
Why Manual Standup Summaries Break Down
Async standups work well when everyone actually participates, but the moment the team grows past five or six people, a few predictable problems show up. Updates get lost in fast-moving channels, people use inconsistent formats that make skimming difficult, and nobody has time to manually compile a summary for stakeholders who don't have time to read forty individual messages.
The usual fallback — asking a team lead to manually summarize standup threads every morning — is a low-value use of someone's time and it's exactly the kind of repetitive, pattern-based task that automation handles better than a human under time pressure. Automating this workflow doesn't replace the standup itself; it removes the tedious compilation step so the human time gets spent acting on blockers instead of formatting a summary.
Building the Slack Standup Bot
Step 1: Set Up Your Slack App and Permissions
Create a Slack app at api.slack.com/apps and add the channels:history, chat:write, and users:read OAuth scopes. Install the app to your workspace and grab the bot token. Invite the bot to your standup channel with /invite @YourBotName.
1import os2from slack_sdk import WebClient34slack_client = WebClient(token=os.environ["SLACK_BOT_TOKEN"])5STANDUP_CHANNEL_ID = "C0123456789"
Step 2: Pull the Last 24 Hours of Standup Messages
1import time23def fetch_standup_messages(channel_id):4 oldest = time.time() - 86400 # last 24 hours5 response = slack_client.conversations_history(6 channel=channel_id,7 oldest=str(oldest),8 limit=2009 )10 messages = []11 for msg in response["messages"]:12 if msg.get("subtype") is None: # skip joins/leaves/bot messages13 user_info = slack_client.users_info(user=msg["user"])14 username = user_info["user"]["real_name"]15 messages.append({"user": username, "text": msg["text"]})16 return messages
This grabs every human-posted message in the channel over the last day, tagging each one with the poster's real name so the summary can attribute updates correctly.
Step 3: Summarize Updates and Flag Blockers with AI
Raw message dumps aren't useful to leadership — the value comes from turning scattered updates into a structured summary that highlights what actually needs attention.
1from openai import OpenAI23ai_client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])45def summarize_standup(messages):6 combined_text = "\n".join(f"{m['user']}: {m['text']}" for m in messages)78 prompt = f"""9 Below are individual standup updates from a software team, each labeled10 with the person's name. Produce a summary with three sections:1112 1. Completed Yesterday - one bullet per person, condensed to one line13 2. Working On Today - one bullet per person, condensed to one line14 3. Blockers - list only real blockers that need someone else's help,15 and name who raised each one1617 If a person didn't post an update, list their name under a18 "Missing Updates" section instead of guessing.1920 Standup messages:21 {combined_text}22 """2324 response = ai_client.chat.completions.create(25 model="gpt-4o",26 messages=[{"role": "user", "content": prompt}],27 temperature=0.228 )29 return response.choices[0].message.content
Setting a low temperature keeps the summary factual and consistent rather than creatively rephrased, which matters when the output is being used to track real blockers.
Step 4: Post the Formatted Digest Back to Slack
1def post_standup_digest(channel_id, summary_text):2 slack_client.chat_postMessage(3 channel=channel_id,4 text=f"📋 *Daily Standup Digest*\n\n{summary_text}"5 )67if __name__ == "__main__":8 messages = fetch_standup_messages(STANDUP_CHANNEL_ID)9 if messages:10 summary = summarize_standup(messages)11 post_standup_digest(STANDUP_CHANNEL_ID, summary)12 else:13 post_standup_digest(STANDUP_CHANNEL_ID, "No standup updates were posted today.")
Scheduling the Script to Run Automatically
Set up a cron job to run the script every weekday morning once the standup window closes:
1# Run at 10:00 AM every weekday20 10 * * 1-5 /usr/bin/python3 /path/to/standup_digest.py
If your team is fully remote across time zones, adjust the oldest window and cron time to match when the last reasonable update would have been posted, so nobody's update gets cut off by a few minutes.
Real-World Example: A 12-Person Engineering Team
A remote engineering team of twelve people switched from a manually compiled Monday-morning summary — which regularly took their team lead twenty minutes to assemble from a scattered thread — to this automated digest. The blockers section alone changed how the team operated: instead of blockers sitting buried in a thread until someone happened to scroll past them, they appeared at the top of a digest posted to a channel the whole team and their manager actually read every morning.
Best Practices / Pro Tips
Keep the AI prompt strict about not inventing content. Explicitly instruct it to flag missing updates rather than guessing what someone might be working on, since a fabricated update is worse than an honest gap.
Post the digest to a separate channel from the raw standup thread. This keeps the digest as a clean, skimmable summary while preserving the original detailed updates for anyone who wants to dig into specifics.
Log every summary to a file or database in addition to posting it to Slack, so you have a historical record you can search later when investigating recurring blockers or patterns.
Rotate in a weekly rollup. Running the same summarization prompt against a full week of digests produces a useful trend report for retrospectives without any additional manual work.
Conclusion
You can automate Slack standup reports with Python using nothing more than the Slack API, a scheduled script, and an AI summarization call, turning a repetitive daily compilation chore into a five-second automated digest. The result is a more consistent, more readable standup summary that surfaces real blockers immediately instead of burying them in a scrolling thread, freeing up the time a team lead used to spend manually reading and reformatting updates every morning.
Frequently Asked Questions
Will this work with Slack threads instead of a single channel?
Yes, with a small change — fetch replies using conversations.replies for the specific standup thread timestamp instead of pulling the whole channel's history, then feed those replies into the same summarization function.
Can I use a different AI model instead of GPT-4o?
Absolutely. Any capable chat model works for this kind of structured summarization task; swap the client and model name in the summarize_standup function while keeping the same prompt structure.
What if someone posts their update as a thread reply instead of a top-level message?
The conversations_history call only returns top-level messages by default, so you'll need to also call conversations_replies for any message with a thread and merge those into your message list before summarizing.
How do I handle a team that spans multiple time zones?
Widen the lookback window on fetch_standup_messages to 30-36 hours and schedule the digest to run at a time that reasonably falls after your latest time zone's morning, so nobody's update is excluded.
Related articles: Build a Slack Bot to Automate Team Notifications with Python, Schedule Python Scripts to Run Automatically, Automate Weekly Email Reports with Python and smtplib
Sponsored Content
Interested in advertising? Reach automation professionals through our platform.
