Skip to content

monashcoding/karma-bot

Repository files navigation

Karma Bot

A Discord bot for giving and tracking karma points across server members and teams.

How It Works

Giving Karma

Mention a user followed by ++ (two or more plus signs) to give them karma:

@alice +++        # gives Alice 3 karma
@bob +++++        # gives Bob 5 karma

Removing Karma

Use -- (two or more minus signs) or em dashes to remove karma:

@alice ---        # removes 3 karma
@alice —          # removes 2 karma (em dash counts as 2)
@alice ———        # removes 6 karma

Team Karma

Mention a team role to give karma to all members of that team:

@Frontend +++     # gives +3 karma to every member with the Frontend role

Team role karma allows self-karma (if you're on the team) and bypasses the global rate limit, but per-user limits still apply.

Rate Limits

  • Global limit — max total karma you can give/take in a rolling interval (LIMIT_MAX_KARMA_SEND / LIMIT_MIN_KARMA_SEND)
  • Per-user limit — max karma you can give/take to the same person per interval (LIMIT_MAX_KARMA_USER_SEND / LIMIT_MIN_KARMA_USER_SEND)
  • The bot tells you exactly why karma was capped (per-user limit, global budget, or rate limited with reset time)

Karma Windows

Karma accumulates in configurable time-based windows (semiannual by default). When a window ends, the leaderboard is automatically posted and a new window begins. Historical windows are preserved.

Commands

Karma

Command Description
/leaderboard View the karma leaderboard (with period selector dropdown)
/team-leaderboard View the team karma leaderboard
/ping Check bot latency

Configuration (requires Manage Server)

Command Description
/config set-leaderboard-channel #channel Set where leaderboards are posted on window rollover
/config add-karma-role @role Add a role that can give and receive karma
/config remove-karma-role @role Remove a karma role
/config view-karma-roles List all karma roles
/config add-team-role @role Add a role as a team for the team leaderboard
/config remove-team-role @role Remove a team role
/config view-team-roles List all team roles

When no karma roles are configured, everyone can use the bot.

Project Structure

src/
  bot.py                              # Entry point, error handler, persistent views
  core/
    config.py                         # Rate limits, karma window rrule
    checks.py                         # @has_karma_role() decorator + member check
    emojis.py                         # Custom Discord emoji constants
    functions/karma.py                # Leaderboard embed builders
    message_utils/paginator.py        # Persistent paginated embeds
  backend/
    db.py                             # Database singleton (async SQLModel + asyncpg)
    cache.py                          # Stale-while-revalidate cache manager
    models.py                         # User, KarmaWindow, KarmaTransaction, GuildConfig, UserTeamRole
    tables/
      base.py                         # BaseDB[T] — generic CRUD
      db_user.py                      # UserDB — increment_karma
      db_karma_window.py              # KarmaWindowDB — leaderboard + window queries
      db_karma_transaction.py         # KarmaTransactionDB — rate limit queries
      db_guild_config.py              # GuildConfigDB — per-guild settings (cached)
      db_user_team_role.py            # UserTeamRoleDB — team role cache + aggregation
  cogs/
    commands/
      general.py                      # /ping
      karma.py                        # Karma listener, /leaderboard, /team-leaderboard
      config.py                       # /config command group
    workers/
      karma_history.py                # Auto-post leaderboard on window rollover
tests/                                # 61 tests (in-memory SQLite, no Docker needed)

Setup

Prerequisites

  • Python 3.12+
  • Docker & Docker Compose (for the database)

Development

cp .env.example .env
# Edit .env with your DISCORD_TOKEN

# Start the bot + Postgres
docker compose up --build

# Or run locally (with Postgres already running)
pip install -r requirements.txt
python -m src.bot

Environment Variables

Variable Description
DISCORD_TOKEN Your Discord bot token
DATABASE_URL PostgreSQL connection string (dev override sets this automatically)

Discord Developer Portal

Enable these Privileged Gateway Intents for your bot:

  • Message Content Intent — needed to read the ++/-- karma pattern
  • Server Members Intent — needed for guild.get_member() in leaderboards

Testing

Tests use in-memory SQLite — no database setup required.

pip install -r requirements.txt
python -m pytest tests/ -v

Configuration

Edit src/core/config.py to adjust rate limits:

Setting Default Description
LIMIT_MAX_KARMA_SEND 100 Max total karma a user can give per interval
LIMIT_MIN_KARMA_SEND -100 Max total karma a user can remove per interval
LIMIT_KARMA_SEND_INTERVAL 6 hours Rolling window for the global rate limit
LIMIT_MAX_KARMA_USER_SEND 5 Max karma a user can give to one person per interval
LIMIT_MIN_KARMA_USER_SEND -5 Max karma a user can remove from one person per interval
LIMIT_KARMA_USER_SEND_INTERVAL 6 hours Rolling window for the per-user rate limit
KARMA_WINDOW_RULE Semiannual (Jan/Jul) dateutil.rrule defining karma reset periods

Changing the Karma Window Period

The KARMA_WINDOW_RULE accepts any dateutil.rrule:

from dateutil.rrule import MONTHLY, WEEKLY, MO, rrule

# Semiannual (default)
KARMA_WINDOW_RULE = rrule(MONTHLY, interval=6, bymonth=(1, 7), dtstart=...)

# Fortnightly starting Monday
KARMA_WINDOW_RULE = rrule(WEEKLY, interval=2, byweekday=MO, dtstart=...)

# Monthly on the 1st
KARMA_WINDOW_RULE = rrule(MONTHLY, dtstart=...)

Architecture

  • SQLModel — typed models that double as Pydantic + SQLAlchemy
  • asyncpg — async PostgreSQL driver
  • BaseDB[T] — generic CRUD base class; per-table classes add domain methods
  • cached() — stale-while-revalidate wrapper for any table (used on guild_config)
  • Singleton patternfrom src.backend.tables import user, karma_window and use directly
  • Persistent paginator — embed buttons survive bot restarts via PersistentPaginatorView

About

A Discord bot that lets server members give each other karma points via mentions.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors