Persistent Discord panels for Calendar, Agenda, and Achievements — backed by Google Sheets and Google Calendar. Includes a division-based permission system with an approval flow for student edit requests.
| Role | Can do |
|---|---|
| Captain / Mentor / Lead Mentor | Edit anything, everywhere, no limits |
| Division Lead | Edit their own division's content directly |
| Division Student | Submit a request → division lead gets a DM to approve or deny |
- Calendar — Always-on embed, refreshes every hour from Google Calendar. Tag events with
[Division]to group them by division - Agenda — Checkbox task list grouped by division. Leads edit directly; students submit requests
- Achievements — Running list of wins grouped by division. Same permission flow as agenda
- Signups — Native Discord poll posted automatically every week. No backend needed
Create one spreadsheet and add these tabs with exact column headers:
Tab: Agenda
task | done | division
Tab: Achievements
achievement | division
Tab: Requests
id | division | action | payload | requester_id | requester_name | status | timestamp
No Signups tab needed — polls are handled entirely by Discord.
To tag a calendar event to a division, just put the division name in brackets at the start of the event title:
[Programming] Kickoff meeting
[Engineering] Build day
[Marketing] Sponsor outreach call
General all-hands meeting
The bot groups them by division in the calendar panel automatically. Events without a tag show under Team-Wide.
- Open
config.pyand copy one of the existing division blocks:
"outreach": {
"name": "Outreach",
"emoji": "🤝",
"lead_role_id": int(os.getenv("OUTREACH_LEAD_ROLE_ID", 0)),
"member_role_id": int(os.getenv("OUTREACH_MEMBER_ROLE_ID", 0)),
},- Add the two new role ID variables to your
.env:
OUTREACH_LEAD_ROLE_ID=
OUTREACH_MEMBER_ROLE_ID=
- Restart the bot. The new division shows up everywhere automatically.
- Go to https://discord.com/developers/applications → New Application
- Go to Bot tab → Add Bot
- Under Privileged Gateway Intents, enable Server Members Intent and Message Content Intent
- Copy the Token → paste into
.envasDISCORD_TOKEN - Go to OAuth2 > URL Generator. Scopes:
bot,applications.commands. Permissions:Send Messages,Read Messages/View Channels,Manage Messages,Embed Links,Mention Everyone - Open the URL to invite the bot to your server
- In Discord: User Settings > Advanced > enable Developer Mode
- Right-click any role in Server Settings > Roles → Copy Role ID
- Fill in all role IDs in your
.env
Right-click each channel → Copy Channel ID → fill into .env
- Go to https://console.cloud.google.com → New Project
- Enable Google Sheets API and Google Calendar API
- IAM & Admin > Service Accounts > Create Service Account
- Open the service account > Keys tab > Add Key > JSON → download it
- Rename the file to
credentials.jsonand put it in the bot folder - Copy the service account email (looks like
name@project.iam.gserviceaccount.com)
- Create a spreadsheet at https://sheets.google.com
- Share it with the service account email (give Editor access)
- Copy the ID from the URL:
docs.google.com/spreadsheets/d/THIS_ID/edit - Paste into
.envasGOOGLE_SHEETS_ID - Create the four tabs listed above with correct headers
- Open your team calendar settings at calendar.google.com
- Share it with the service account email (Read access is fine)
- Copy the Calendar ID from settings
- Paste into
.envasCALENDAR_ID
pip install -r requirements.txt
python main.pyRun these slash commands in Discord (you need Manage Messages permission):
/setup_agenda
/setup_achievements
/refresh_calendar
/post_signup
After that everything is automatic.
- Push to a private GitHub repo (do NOT commit
.envorcredentials.json) - Go to https://railway.app → New Project → Deploy from GitHub
- Add all
.envvalues under Variables - For
credentials.json: paste the entire JSON content as a Railway variable calledGOOGLE_CREDENTIALS_JSON, then add this tomain.pybeforeload_dotenv():
import json, os
creds_json = os.getenv("GOOGLE_CREDENTIALS_JSON")
if creds_json:
with open("credentials.json", "w") as f:
f.write(creds_json)| Command | Who | What |
|---|---|---|
/setup_agenda |
Captains+ | Post or re-post the agenda panel |
/setup_achievements |
Captains+ | Post or re-post the achievements panel |
/refresh_calendar |
Captains+ | Force-refresh the calendar embed |
/post_signup |
Captains+ | Manually post this week's poll |