Skip to content

Commit 3b224e7

Browse files
Merge pull request #189 from ContextLab/feature/scheduling-bot
Add term meeting scheduling to CDL Bot
2 parents 1fa4630 + e9fbd81 commit 3b224e7

44 files changed

Lines changed: 4479 additions & 295 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,15 @@ html_test/
2929
# Playwright MCP screenshots
3030
.playwright-mcp/
3131

32-
# CDL Onboarding Bot
33-
scripts/onboarding/.env
34-
scripts/onboarding/output/
35-
scripts/onboarding/*.json
36-
scripts/onboarding/secrets/
37-
scripts/onboarding/data/
32+
# CDL Bot
33+
cdl_bot/.env
34+
cdl_bot/output/
35+
cdl_bot/*.json
36+
cdl_bot/secrets/
37+
cdl_bot/data/
38+
!cdl_bot/data/projects.json
39+
.cdl-bot.pid
40+
.cdl-bot.log
3841
*.credentials.json
3942
service-account*.json
4043
google-credentials.json
@@ -72,3 +75,5 @@ env/
7275

7376
# Claude session notes
7477
notes/
78+
.omc/
79+
cdl_bot/CDL_scheduler.ipynb

CLAUDE.md

Lines changed: 16 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
44

55
## Repository Overview
66

7-
This is the lab manual for the Contextual Dynamics Laboratory (CDL) at Dartmouth College. It's a LaTeX document using the Tufte-book class that describes lab policies, member responsibilities, and research approach. The repo also contains a **Slack onboarding bot** (`scripts/onboarding/`) that automates member on/offboarding.
7+
This is the lab manual for the Contextual Dynamics Laboratory (CDL) at Dartmouth College. It's a LaTeX document using the Tufte-book class that describes lab policies, member responsibilities, and research approach. The repo also contains **CDL Bot** (`cdl_bot/`), a Slack bot that automates onboarding, offboarding, and term meeting scheduling.
88

99
## Build Commands
1010

@@ -14,28 +14,23 @@ This is the lab manual for the Contextual Dynamics Laboratory (CDL) at Dartmouth
1414
```
1515
Runs `latex` 5x (for cross-references/index), then `pdflatex`, and cleans up intermediate files. Requires a LaTeX distribution (`brew install --cask mactex` on macOS).
1616

17-
**Run onboarding bot tests:**
17+
**Run bot tests:**
1818
```bash
19-
# No API keys needed
20-
pytest tests/test_onboarding/test_models.py -v
21-
pytest tests/test_onboarding/test_image_service.py -v
22-
23-
# Requires GITHUB_TOKEN
24-
pytest tests/test_onboarding/test_github_service.py -v
25-
26-
# Requires ANTHROPIC_API_KEY
27-
pytest tests/test_onboarding/test_bio_service.py -v
28-
29-
# All tests
30-
pytest tests/test_onboarding/ -v
19+
pytest tests/test_onboarding/ -v # All tests
20+
pytest tests/test_onboarding/test_scheduling.py -v # Scheduling only (no API keys needed)
3121
```
3222
Tests use real API calls (no mocks). Tests skip automatically when credentials are missing.
3323

34-
**Run the onboarding bot:**
24+
**Run CDL Bot:**
3525
```bash
36-
python -m scripts.onboarding.bot
26+
pip install -e . # First time only
27+
cdl-bot start # Start (idempotent)
28+
cdl-bot stop # Stop (idempotent)
29+
cdl-bot restart # Stop + start
30+
cdl-bot status # Show running state
31+
cdl-bot logs # Tail log file
3732
```
38-
Requires `.env` in `scripts/onboarding/` with Slack tokens, GitHub PAT, and optionally Google/Anthropic credentials.
33+
Requires `.env` in `cdl_bot/` with Slack tokens, GitHub PAT, and optionally Google/Anthropic credentials.
3934

4035
## Project Structure
4136

@@ -45,28 +40,9 @@ Requires `.env` in `scripts/onboarding/` with Slack tokens, GitHub PAT, and opti
4540
- `tufte.cfg` — TeX4ht configuration for HTML generation
4641
- `tufte-book.cls`, `tufte-common.def` — Custom Tufte template files (do not modify casually)
4742
- `toc.js`, `checklist.js`, `lab-manual.css` — HTML version enhancements (TOC nav, interactive checklist, custom styling)
48-
- `scripts/onboarding/`Slack onboarding bot (see architecture below)
43+
- `cdl_bot/`CDL Bot (Slack automation, see `cdl_bot/README.md`)
4944
- `tests/test_onboarding/` — Bot tests (real API calls, no mocks)
50-
51-
### Onboarding Bot Architecture
52-
53-
```
54-
scripts/onboarding/
55-
├── bot.py # Entry point, Slack app setup
56-
├── config.py # Environment/config management
57-
├── handlers/
58-
│ ├── onboard.py # /cdl-onboard slash command
59-
│ ├── approval.py # Admin approval workflow (interactive messages)
60-
│ ├── offboard.py # /cdl-offboard slash command
61-
│ └── workflow_step.py # Slack Workflow Builder custom steps
62-
├── models/
63-
│ └── onboarding_request.py # Data models
64-
└── services/
65-
├── github_service.py # GitHub org invitations
66-
├── calendar_service.py # Google Calendar sharing
67-
├── image_service.py # Photo border processing (Pillow)
68-
└── bio_service.py # Bio editing via Claude API
69-
```
45+
- `pyproject.toml` — Package config, installs `cdl-bot` CLI
7046

7147
## CI/CD
7248

@@ -95,5 +71,5 @@ The HTML version is auto-generated by CI — no manual build needed.
9571

9672
- `lab_manual.tex` is gitignored (the `.tex` line in `.gitignore`) — this is intentional to avoid accidental commits of intermediate build state. The file IS tracked by git despite the gitignore entry.
9773
- The CI will **close PRs** that fail LaTeX compilation — always test locally with `./compile.sh` first.
98-
- Onboarding bot credentials go in `scripts/onboarding/.env` (gitignored). Never commit tokens or service account JSON files.
99-
- Bot tests require running from the repo root so `scripts.onboarding` is importable as a package.
74+
- Onboarding bot credentials go in `cdl_bot/.env` (gitignored). Never commit tokens or service account JSON files.
75+
- Bot tests require running from the repo root so `cdl_bot` is importable as a package.

cdl_bot/README.md

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
# CDL Bot
2+
3+
Slack bot for the Contextual Dynamics Laboratory. Automates onboarding, offboarding, and term meeting scheduling.
4+
5+
## Quick Start
6+
7+
```bash
8+
# First time: create venv and install
9+
python -m venv venv
10+
source venv/bin/activate
11+
pip install -e .
12+
13+
# Configure credentials
14+
cp cdl_bot/.env.example cdl_bot/.env
15+
nano cdl_bot/.env
16+
17+
# Start the bot
18+
cdl-bot start
19+
```
20+
21+
The `cdl-bot` CLI manages the bot process:
22+
23+
```bash
24+
cdl-bot start # Start (no-op if already running)
25+
cdl-bot stop # Stop (no-op if not running)
26+
cdl-bot restart # Stop + start
27+
cdl-bot status # Show PID or "not running"
28+
cdl-bot logs # Tail the log file
29+
```
30+
31+
## Features
32+
33+
### Onboarding (`/cdl-onboard` or Workflow Builder)
34+
35+
Two entry points for new members:
36+
37+
1. **Workflow Builder** (recommended): New member runs "Join the lab!" workflow. Bot validates GitHub username, sends admin approval, then invites to GitHub org, shares calendars, processes profile photo.
38+
39+
2. **Admin-initiated**: `/cdl-onboard @user` opens a form for the new member. Collects GitHub username, bio, photo, website. Bio edited to CDL style via Claude. Photo gets hand-drawn green border.
40+
41+
### Offboarding (`/cdl-offboard` or Workflow Builder)
42+
43+
Admin selects access to revoke (GitHub, calendars). Generates a checklist — does NOT auto-remove anyone.
44+
45+
### Term Scheduling (`/cdl-schedule`)
46+
47+
1. Director runs `/cdl-schedule` — config modal auto-populates projects from database
48+
2. Creates When2Meet survey (Mon-Fri weekly) and posts to #general with project list and emoji reactions
49+
3. "Collect Responses" scrapes respondent names, checks for :zoom: individual meeting requests
50+
4. Assignment modal: director assigns respondents to projects, marks senior/external
51+
5. Algorithm maximizes attendance with PI-required, senior 3x weighting, day concentration
52+
6. Director reviews proposed schedule, approves to post announcement
53+
54+
**Project database** (`data/projects.json`): Stores emoji, Slack channels, description, and default duration per project. Auto-populated from previous terms. New projects added during scheduling are saved for future use.
55+
56+
Project format in the config modal (one per line):
57+
```
58+
Project Name | duration_blocks | :emoji:
59+
Lab Meeting | 4 | :raising_hand:
60+
Kraken | 4 | :octopus:
61+
```
62+
63+
Duration is in 15-minute blocks (4 = 60min). Append `.5` for biweekly (2.5 = biweekly 30min).
64+
65+
## Setup
66+
67+
### Slack App
68+
69+
1. Go to [api.slack.com/apps](https://api.slack.com/apps)
70+
2. Create new app from manifest (`cdl_bot/manifest.json`) or manually:
71+
- Enable Socket Mode, create app-level token with `connections:write`
72+
- Bot scopes: `chat:write`, `commands`, `users:read`, `users:read.email`, `im:write`, `im:history`, `files:read`, `files:write`, `workflow.steps:execute`, `reactions:read`
73+
- Events: `file_shared`, `function_executed`
74+
- Slash commands: `/cdl-onboard`, `/cdl-offboard`, `/cdl-schedule`, `/cdl-ping`, `/cdl-help`
75+
- Enable Interactivity
76+
77+
### Credentials (`.env`)
78+
79+
Required:
80+
- `SLACK_BOT_TOKEN` — Bot OAuth token (xoxb-...)
81+
- `SLACK_APP_TOKEN` — App-level token (xapp-...)
82+
- `SLACK_ADMIN_USER_ID` — Director's Slack user ID
83+
- `GITHUB_TOKEN` — PAT with `admin:org` scope
84+
85+
Optional:
86+
- `GOOGLE_CREDENTIALS_FILE` — Service account JSON for calendar sharing
87+
- `GOOGLE_CALENDAR_*` — Calendar IDs
88+
- `ANTHROPIC_API_KEY` — For Claude bio editing
89+
90+
## Testing
91+
92+
```bash
93+
pytest tests/test_onboarding/ -v # All tests
94+
pytest tests/test_onboarding/test_scheduling.py -v # Scheduling only (no API keys needed)
95+
```
96+
97+
Tests use real API calls (no mocks). Tests skip automatically when credentials are missing.
98+
99+
## Architecture
100+
101+
```
102+
cdl_bot/
103+
├── bot.py # Entry point, Slack app setup
104+
├── cli.py # cdl-bot CLI (start/stop/restart/status/logs)
105+
├── config.py # Environment/config management
106+
├── project_store.py # Project database CRUD
107+
├── scheduling_storage.py # Scheduling session persistence
108+
├── manifest.json # Slack app manifest
109+
├── data/
110+
│ └── projects.json # Project database (emojis, channels, descriptions)
111+
├── handlers/
112+
│ ├── onboard.py # /cdl-onboard
113+
│ ├── approval.py # Admin approval workflow
114+
│ ├── offboard.py # /cdl-offboard
115+
│ ├── schedule.py # /cdl-schedule term scheduling flow
116+
│ └── workflow_step.py # Workflow Builder custom steps
117+
├── models/
118+
│ ├── onboarding_request.py
119+
│ └── scheduling_session.py
120+
└── services/
121+
├── github_service.py # GitHub org invitations
122+
├── calendar_service.py # Google Calendar sharing
123+
├── image_service.py # Photo border processing (Pillow)
124+
├── bio_service.py # Bio editing via Claude API
125+
├── when2meet_service.py # When2Meet create + scrape
126+
└── scheduling_service.py # Meeting scheduling algorithm
127+
```
Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
- Bio editing via Claude API
1616
1717
Usage:
18-
python -m scripts.onboarding.bot
18+
python -m cdl_bot.bot
1919
2020
Environment Variables Required:
2121
SLACK_BOT_TOKEN - Slack bot OAuth token (xoxb-...)
@@ -43,6 +43,7 @@
4343
from .handlers.workflow_step import register_workflow_step_handlers
4444
from .handlers.workflow_listener import register_workflow_listener_handlers
4545
from .handlers.website_approval import register_website_approval_handlers
46+
from .handlers.schedule import register_schedule_handlers
4647
from .startup_queue import process_startup_queue, StartupQueueProcessor, register_startup_queue_handlers
4748

4849
# Configure logging
@@ -75,6 +76,7 @@ def create_app(config: Config) -> App:
7576
register_workflow_step_handlers(app, config)
7677
register_workflow_listener_handlers(app, config)
7778
register_website_approval_handlers(app, config)
79+
register_schedule_handlers(app, config)
7880
register_startup_queue_handlers(app, config)
7981

8082
# Add a health check command
@@ -107,6 +109,8 @@ def handle_help(ack, respond, command):
107109
• Admin selects which access to revoke
108110
• Generates a checklist for manual steps
109111
112+
`/cdl-schedule` - Start term meeting scheduling (director only)
113+
110114
`/cdl-ping` - Check if the bot is running
111115
112116
`/cdl-help` - Show this help message

0 commit comments

Comments
 (0)