↑Skip to content
AshokBhatiHire me
← All work

Case study 02 · EdTech / Leadership coaching

LeadWell Coach

Slack bot that keeps leadership training alive

I built a Slack bot that sends leadership and management coaching content on a schedule each user picks. It personalises content from the participant's own workbook slides, and falls back to the approved guidebook for everyone else. Follow-up content now reaches every participant with no manual messages.

▶ Try the live demo
LeadWell Coach cover
Client
A leadership coaching and training company
PythonFastAPISlack SDKOpenAI GPT-4oPineconeLangChainPostgreSQLDocker

Live demo

Try LeadWell Coach yourself

An interactive recreation that runs in your browser.

Open the demo
01

Problem

Problem statement

Participants forgot most of the workshop within weeks. Coaches had no simple way to keep sending each person relevant leadership material.

Context

The client runs leadership and management workshops for companies. Participants already work in Slack. The approved course content lives in one master guidebook PDF. Each participant also gets a workbook PPT, where they write their own strategies, people, philosophy and priorities.

Why it matters

Reinforcement after training is what turns a workshop into a habit. It is also what client companies pay for when they renew.

Constraints

  • Content had to come from approved course material only.
  • Many participants never fill in or upload their workbook, so the bot must still be useful without it.
  • Each user picks their own delivery frequency.
  • The bot installs into each client company's own Slack workspace.
  • A fixed phase budget of about 70 hours.

Success criteria

Every participant gets on-topic content at their chosen interval. Those who upload a workbook get content about their own situation. Coaches update the master content without a developer.

02

Solution

What it does

An admin uploads the master guidebook PDF. The service parses it, embeds it with OpenAI and stores it as the shared knowledge base. The admin registers each participant by name and work email. When a client company installs the bot in Slack, the service reads the workspace members and links each registered participant by email. The participant gets a welcome DM, also sent the first time they open the bot's Home tab.

The welcome DM invites them to share their filled workbook, either as a file in the DM or as a link with /refresh <link>. The bot then sends short leadership and management content by DM on the user's schedule:

No workbook

generic content from the master guidebook, such as quotes, tips and short lessons built on program tools like the Eisenhower Matrix and the 10-10-10 rule.

Workbook uploaded

personalised content that weaves the user's own strategies and values into the guidebook material.

Each message is numbered by week and builds on the last one, so the series reads as a program, not random tips. Users change their schedule with /frequency weekly, bi_weekly or monthly, and send /refresh again any time to update their workbook.

Key features

  1. 01

    Admin uploads the master guidebook once. It is parsed and embedded with OpenAI as the shared knowledge base.

  2. 02

    One-click Slack install per client workspace, with participants matched by email and greeted by DM.

  3. 03

    Workbook upload as a Slack file or a link, filtered to the slides that matter.

  4. 04

    Two content modes: generic from the guidebook, or personalised from the workbook plus the guidebook.

  5. 05

    Scheduled DMs, weekly, bi-weekly or monthly, with each message following on from the last.

Key design decisions

Embed the guidebook and workbooks in a vector index, split shared vs per user

Reason
Retrieval pulls only approved text, and one user never sees another's workbook
Rejected option
Pasting the whole guidebook into every prompt

Generic fallback when no workbook exists

Reason
Most users never upload one. The bot still delivers value from day one.
Rejected option
Blocking content until a workbook is uploaded

Keep only the strategy slides from the workbook

Reason
Cuts noise from title and instruction slides and keeps the prompt small
Rejected option
Embedding every slide

Pass the last message and week number to the model

Reason
Gives a steady program arc and avoids repeats
Rejected option
Independent one-off messages

Match Slack users by registered email

Reason
Only enrolled participants get content, with no manual linking
Rejected option
Messaging every workspace member

Event work in background tasks

Reason
Slack needs a reply within 3 seconds, and parsing takes longer
Rejected option
Processing inside the request

Alternatives considered

I looked at fine-tuning a model on the guidebook. It cost more, was slower to update and could not stay strictly on the approved text. Retrieval over embeddings was cheaper and updates as soon as a new PDF is uploaded.

03

How it works

  1. 01

    The admin uploads the guidebook PDF. LlamaParse extracts the text, OpenAI embeds it, and the chunks go into the shared set in Pinecone.

  2. 02

    The admin registers participants by name and email.

  3. 03

    A client company installs the bot through Slack OAuth. The service saves the workspace token, lists members and links registered participants by email. Each gets a welcome DM.

  4. 04

    A participant shares a workbook in the DM or with /refresh <link>. The service downloads it, keeps only the strategy slides, and embeds them in that user's own set. Any older workbook is replaced.

  5. 05

    The scheduler runs on Mondays. It finds users due for content and groups them by workspace.

  6. 06

    For each user it searches their own chunks first. If none exist, it falls back to the shared guidebook chunks.

  7. 07

    GPT-4o writes the next week's message, using the user's name, the chunks and the previous message.

  8. 08

    The bot sends the DM, saves the message and sets the next delivery date from the user's frequency.

Infra and deployment

The service runs in Docker, with Docker Compose for local work. Poetry manages dependencies. Alembic migrations run on startup. The scheduler runs in its own thread inside the app. pytest covers the content delivery flow.

Security

Slack OAuth with a state check that expires in 5 minutes. Tokens and API keys come from environment config, never code. Workbook vectors are tagged per user, so retrieval never mixes users.

04

Challenges

Users without a workbook

Problem
Most participants never upload one
Approach
Built a generic mode that falls back to the shared guidebook chunks
Outcome
Every user gets content from day one

Duplicate Slack events

Problem
Slack retries and sends file events twice
Approach
Tracked in-flight file and user IDs and skipped repeats
Outcome
One reply and one parse per upload

Reading workbook slides

Problem
Answers sit in text boxes across many slides
Approach
Parsed with LlamaParse and kept only slides with the strategy headings
Outcome
Clean input for personalised content

Repetitive messages

Problem
Each message read like the last
Approach
Numbered weeks and passed the previous message to the model
Outcome
A steady weekly arc

Tight budget

Problem
About 70 hours for the whole phase
Approach
Kept a layered template and fixed frequency options
Outcome
Phase shipped in about 5 weeks
05

Results

Manual follow-up messages per week

0

from 100

Time to update course content

5 min upload

from 1 day of dev work

Post-workshop interactions

About 3x more

from Low

Before and after results chart

Business impact

Coaches stopped sending follow-ups by hand. The client can sell ongoing reinforcement with its workshops, with a personal tier for participants who share their workbook.

Technical impact

One scheduler serves both content modes and many workspaces. A new command is a controller plus a service, with no changes elsewhere.

06

Skills and tech stack

Backend

PythonFastAPIPydanticSQLAlchemy (async)PostgreSQLAlembicPoetryAPScheduler

AI / ML

OpenAI GPT-4oOpenAI embeddingsPineconeLangChainLlamaParseprompt design

Cloud / DevOps

DockerDocker Compose

Integrations

Slack SDK (OAuth installeventsfile downloadsslash commandsDMs)

Testing

pytest
07

Reflection

What worked

The generic fallback meant the bot was useful to everyone, not only to users who filled in the workbook.

What I would do differently

Use a proper job queue for scheduled sends, so a restart never skips a delivery, and store OAuth state in the database instead of files.

What's next

An admin screen for participants and guidebooks, feedback on each message, and a nudge for users still on generic content.

Key learning

Design for the user who skips the setup step. They are usually the majority.

Next step

Need something similar?

Code walkthrough available on request.