jam bot is a discord bot that gamifies your community. it tracks messages, awards xp, manages referrals, and hands out jam-themed roles as members level up.
it also handles onboarding. new members have to introduce themselves and share a project before they get verified. no lurkers allowed (well, fewer lurkers).
this branch also adds /showcase-project, which opens a modal and sends a project submission to a separate showcase API that you host elsewhere.
message sent → xp awarded → level up → jam role assigned → announced to the server
every message earns 10 xp (with a 60-second cooldown so you can't spam your way to the top). longer messages (50+ chars) earn a 5 xp bonus. refer a friend and get 50 xp on top of that.
| level | role | xp needed |
|---|---|---|
| 1 | strawberry jam | 100 |
| 2 | blueberry jam | 500 |
| 3 | golden jam | 1,500 |
| 4 | diamond jam | 8,000 |
| 5 | platinum jam | 15,000 |
| 6 | infinity jam | 25,000 |
| command | what it does |
|---|---|
/rank |
check your xp, level, referrals, and message count |
/mylink |
get your personal referral invite link |
/myreferrals |
see everyone you've referred |
/leaderboard |
top 10 members by xp |
/ref-leaderboard |
top 10 members by referrals |
/joined |
check when a member joined the server |
/serverinfo |
display server stats (members, channels, boosts, and more) |
/countdown |
start a countdown embed to an upcoming event |
/bread |
receive a random bread blessing |
/am-i-jam |
deep philosophical question |
/link-github |
link your github account to be tagged in PR merges |
/showcase-project |
submit a project to the external showcase API |
| command | what it does |
|---|---|
/setxp |
manually set a user's xp |
/setreferrals |
manually set a user's referral count |
/setup-welcome |
post welcome embeds to a channel |
/test-welcome |
dm yourself the welcome message |
jam bot gives every member a personal invite link they can share. when someone joins through that link, the referrer gets credit and 50 xp.
member runs /mylink → gets personal invite link → shares it → new member joins
→ bot detects which invite was used → credits the referrer → awards 50 xp
→ announces it to the server
- invite creation — when a member runs
/mylink, the bot creates a permanent discord invite tied to their account and stores the link in the database. if they already have one, it reuses it. - join detection — the bot caches all invite use counts. when a new member joins, it compares the cached counts to the current counts to figure out which invite was used.
- referrer lookup — the bot checks the
invite_ownerstable to find who owns the invite. if the invite wasn't created through/mylink, it falls back to discord's built-in invite creator field. - reward & announce — the referrer's referral count goes up by 1, they get 50 xp, and the bot posts a message in the configured channel (defaults to #commands). if the xp pushes them to a new level, that gets announced too.
- duplicate prevention — each referred member can only count once. if someone leaves and rejoins through the same link, it won't double-count.
| command | what it does |
|---|---|
/mylink |
get your personal referral invite link + see your referral stats |
/myreferrals |
see the list of people you've referred (up to 20 most recent) |
/ref-leaderboard |
top 10 members ranked by referral count |
/setreferrals |
(admin) manually set a user's referral count |
referrals are tracked across three postgres tables:
users— stores each member's total referral count alongside their xp and levelreferral_log— records every referral (who referred whom and when), with a unique constraint on the referred member to prevent duplicatesinvite_owners— maps invite codes to the members who created them
not everything has to be productive. these do nothing useful and that's the point.
receive a random bread blessing. there are 15 possible outcomes, including:
- a warm loaf of sourdough is given to you
- a tiny baguette rolls across the floor and stops at your feet
- a mysterious bread fairy delivers a pretzel to you
- the universe grants you a single, perfect slice of milk bread
ask the bot a deep philosophical question about whether you are jam. it will respond with one of two possible answers. neither of them actually answers the question.
a magic 8-ball with 20 possible responses — some positive, some uncertain, some negative. a few are on-brand: "bread says yes", "jam is confused, ask later", "bread says no". takes a question as input and returns its wisdom in a purple embed.
- xp & leveling — message-based xp with cooldowns, bonus xp for longer messages, automatic role assignment
- referral tracking — personal invite links, referral credit with xp rewards, persistent tracking via database
- onboarding gate — new members must post in #intros and #projects to get verified
- thread management — auto-archives threads in specified channels to keep things tidy
- welcome system — dms new members with onboarding info and their personal referral link
- server info — rich embed showing member counts, channel breakdown, boost level, roles, and creation date
- event countdowns — post a live countdown embed for any upcoming event using discord's dynamic timestamps
- github webhooks — automatically announce merged PRs to a channel and ping the author
- showcase submissions — collect project submissions in Discord and forward them to a separate showcase backend
/showcase-project opens a modal with:
- project name
- short description
- github url
- live/demo url
- tags
when the user submits, the bot:
- builds a structured payload with guild, channel, member, and project metadata
- sends that payload to your separate showcase API as JSON
- returns an ephemeral confirmation to the member
The intended product flow is Discord-first: community members share their project from inside the server with /showcase-project, and the public showcase site lists it. The showcase site can also accept direct manual submissions through its public API, but the bot path is the main one.
the bot sends a POST request to SHOWCASE_SUBMISSION_API_URL with:
{
"version": 1,
"source": "jam-discord-bot",
"request_id": "abc123",
"guild": {
"id": "123",
"name": "Jam"
},
"channel": {
"id": "456",
"name": "projects"
},
"member": {
"id": "789",
"username": "paul",
"display_name": "Paul"
},
"project": {
"name": "Jam AI Copilot",
"description": "A short summary people will see in the showcase.",
"github_url": "https://github.com/you/repo",
"live_url": "https://your-project.com",
"tags": ["ai", "automation"]
}
}headers:
Content-Type: application/jsonX-Showcase-Request-Id: ...for request tracing
the separate showcase API can validate, sanitize, rate-limit, and insert that payload server-side, and can optionally return JSON like:
{
"id": "abc123",
"slug": "jam-ai-copilot",
"showcase_url": "https://your-showcase.example.com/#projects"
}- python 3.11+
- a postgresql database
- a discord bot token from the developer portal
git clone https://github.com/wespreadjam/jam-discord-bot.git
cd jam-discord-bot
pip install -r requirements.txtDISCORD_BOT_TOKEN=your_bot_token_here
DATABASE_URL=your_postgres_connection_string
GITHUB_WEBHOOK_SECRET=your_secure_random_string
PR_ANNOUNCEMENT_CHANNEL_NAME=testing-announcements
SHOWCASE_SUBMISSION_API_URL=https://your-showcase-api.example.com/api/submissions
SHOWCASE_PUBLIC_URL=https://your-showcase.example.com
SHOWCASE_SOURCE=jam-discord-bot
SHOWCASE_REQUEST_TIMEOUT_SECONDS=10
SHOWCASE_BOT_SHARED_SECRET=your_shared_bot_secretFor the current public showcase deployment, the bot only needs SHOWCASE_SUBMISSION_API_URL to submit projects. The rest are optional quality-of-life settings:
SHOWCASE_PUBLIC_URLlets the bot include the public site link in its confirmation messageSHOWCASE_SOURCEtags the payload sourceSHOWCASE_REQUEST_TIMEOUT_SECONDScontrols how long the bot waits for the APISHOWCASE_BOT_SHARED_SECRETlets the showcase API verify that the request came from the bot and skip the public curl rate limit
No encrypted payload flow is required. If you want the bot to bypass the public rate limit, configure the same SHOWCASE_BOT_SHARED_SECRET in both the bot and the showcase site.
For /showcase-project to work end-to-end, the separate showcase site needs:
NEXT_PUBLIC_SUPABASE_URLNEXT_PUBLIC_SUPABASE_ANON_KEYSUPABASE_SERVICE_ROLE_KEYSHOWCASE_BOT_SHARED_SECRET
and these Supabase migrations applied:
202603120001_projects.sql202603120002_submission_rate_limits.sql
create these roles in your discord server:
strawberry jam · blueberry jam · golden jam · diamond jam · platinum jam · infinity jam · verified
create these channels:
#intros · #projects · #commands
python bot.pythen run /setup-welcome in any channel to post the welcome embeds.
the bot runs a built-in web server to listen for GitHub webhooks, so it includes a Procfile for easy deployment to railway or heroku. Note that it runs as a web process to expose the port correctly:
web: python bot.py
on railway, the DATABASE_URL is set automatically when you add the postgres plugin.
| language | python |
| framework | discord.py |
| database | postgresql |
| hosting | railway / heroku |
credits to hassan2bit bread on discord for naming infinity jam
-jia