Skip to content

Repository files navigation

mom-bot

Discord bot consolidating two existing bots — siege-web's notifications sidecar and the reminder system from I:\games\raid\siege\clan\ — into a single bot with interactive slash commands.

What it does

  • Reminders — scheduled channel posts for Hydra and Chimera clashes, with a Hydra Tank Week variant that swaps in a heads-up and an end-of-clash message.
  • Per-member DM notifications — officers schedule recurring reminders to individual members via /member-notify-add, -list, -get, -update, -remove (weekly / biweekly / monthly cadence).
  • Day-role sync — receives siege-web webhooks and applies/removes Discord day roles.
  • Post-conditions/post-conditions, /post-conditions-get, /post-conditions-set proxy siege-web's preferences API so members can view and set post-condition priorities from Discord.
  • New-member onboarding — new joiners get an automatic welcome message asking for a profile screenshot; officers can subscribe to join alerts via /notify-new-members; members who post nothing within 24h receive a heads-up DM and are removed from the server.
  • /ping — health check (version + uptime).
  • Sidecar HTTP API — FastAPI service on port 8001 backing the siege-web integrations above.

See CHANGELOG.md for the full, dated history of every feature and fix, and the framework plan below for the original design rationale.

Documentation

Prerequisites

  • Python 3.12python --version must show 3.12.x
  • uv — fast Python package manager (pip install uv or see uv docs)
  • Docker — for container smoke tests (docker build .)

Local Development

# 1. Create a virtual environment
uv venv .venv

# 2. Install the package and dev dependencies
uv pip install -e ".[dev]"

# 3. Run the test suite
.venv/Scripts/python.exe -m pytest          # Windows
# .venv/bin/python -m pytest               # Linux / macOS

# 4. Lint and format checks
.venv/Scripts/python.exe -m ruff check src/ tests/
.venv/Scripts/python.exe -m black --check src/ tests/

# 5. Type checking
.venv/Scripts/python.exe -m mypy src/

# 6. Container smoke build
docker build .

Local Azure Access

Mom-bot reads secrets from Azure Key Vault (kv-mombot-eastus2) at runtime via DefaultAzureCredential. On a developer laptop this resolves to your az login session — no managed identity or service principal needed locally.

Prerequisites:

# 1. Log in to the mom-bot tenant (always pass --tenant to avoid cross-tenant confusion)
az login --tenant 48bca6c3-6d4f-4884-bc1a-648ae2362a32

# 2. Set the target subscription
az account set --subscription 213aa1f8-32d1-4ffe-8f4d-6e60f1cd9dc0

# 3. Verify
az account show --query '{tenant:tenantId, sub:id}' -o table

Role requirement: your user account needs Key Vault Secrets User on kv-mombot-eastus2. Request this from the repo admin (@cbeaulieu-gt), or grant it yourself if you have Owner/User Access Administrator on the subscription:

MY_OID=$(az ad signed-in-user show --query id -o tsv)
KV_ID=$(az keyvault show -g mom-bot -n kv-mombot-eastus2 --query id -o tsv)
az role assignment create \
  --role "Key Vault Secrets User" \
  --assignee-object-id "$MY_OID" \
  --assignee-principal-type User \
  --scope "$KV_ID"

Running locally with Key Vault secrets:

# MOM_BOT_ENV=dev causes config.load_secret() to read dev-* secrets from KV.
MOM_BOT_ENV=dev .venv/Scripts/python.exe -m mom_bot          # Windows (Git Bash)
# MOM_BOT_ENV=dev .venv/bin/python -m mom_bot                # Linux / macOS
# PowerShell equivalent:
$env:MOM_BOT_ENV = "dev"; .\.venv\Scripts\python.exe -m mom_bot

DefaultAzureCredential picks up your az login session automatically — no additional environment variables required. See docs/secrets-inventory.md for the full list of secrets and their purposes.

Once set up, launch with one command:

After the one-time az login and Key Vault role grant above, create a .env.dev file in the repo root with the same tenant and subscription GUIDs used in step 1 and step 2:

AZURE_TENANT_ID=48bca6c3-6d4f-4884-bc1a-648ae2362a32
AZURE_SUBSCRIPTION_ID=213aa1f8-32d1-4ffe-8f4d-6e60f1cd9dc0

.env.dev is git-ignored — these GUIDs aren't secrets, but per repo convention it still isn't a tracked file. Then launch mom-bot with:

./scripts/dev-launch.sh

This skips az login if you're already on the right tenant, always runs az account set --subscription to select the configured subscription, sets MOM_BOT_ENV=dev, and execs python -m mom_bot — activate your .venv first (or run it from a shell where .venv is on PATH), since the script uses whatever python resolves to rather than the venv interpreter explicitly. Use the manual steps below instead if you'd rather not use the wrapper, or for first-time setup (the wrapper still requires the Key Vault role grant to be done first).

Running the bot locally

After Local Azure Access is set up and dev-discord-token + dev-guild-id are seeded in kv-mombot-eastus2:

$env:MOM_BOT_ENV = "dev"
.\.venv\Scripts\python.exe -m mom_bot

The bot connects, logs connection details, and registers /ping to the dev guild. Test it from the dev guild's chat — the response is ephemeral (only visible to you). Seed dev-guild-id via:

az keyvault secret set \
  --vault-name kv-mombot-eastus2 \
  --name dev-guild-id \
  --value "<your-discord-server-id>"

Enable Discord Developer Mode (User Settings → Advanced → Developer Mode) to right-click the server icon and copy the guild ID.

Database / Migrations

Mom-bot uses Alembic for schema migrations backed by SQLAlchemy. The local dev default is SQLite (developer convenience — no Azure credentials needed for schema work); production uses a PostgreSQL Flexible Server (pg-mombot-* in resource group mom-bot). The active database is selected via the MOM_BOT_DATABASE_URL environment variable (see docs/secrets-inventory.md for the canonical secret names).

Apply all pending migrations:

alembic upgrade head

Generate a new migration after adding or changing models:

# 1. Generate the migration file (review it before applying)
alembic revision --autogenerate -m "describe change"

# 2. Review migrations/versions/<rev>_describe_change.py — remove any spurious ops

# 3. Apply the migration
alembic upgrade head

Set MOM_BOT_DATABASE_URL to override the default SQLite URL for prod/staging (e.g. postgresql+psycopg://user:pass@host/dbname — the project uses psycopg v3; psycopg2 is not installed).

Project Structure

mom-bot/
├── src/
│   └── mom_bot/                        # Main package (src-layout)
│       ├── __init__.py                 # Package version
│       ├── __main__.py                 # `python -m mom_bot` entrypoint
│       ├── main.py                     # Discord client, intents, slash commands
│       ├── config.py                   # MOM_BOT_ENV-aware config + KV secret load
│       ├── discord_authz.py            # Shared `require_manage_guild` authorization decorator
│       ├── telemetry.py                # OpenTelemetry / Azure Monitor wiring
│       ├── db/                         # SQLAlchemy DeclarativeBase
│       ├── health/                     # /health/* liveness/readiness probes
│       ├── migrations/                 # UAMI Container Apps Job entrypoint (acquire_token.py)
│       ├── post_conditions/            # `/post-conditions*` — siege-web preferences proxy
│       ├── reminders/                  # Channel reminders (Hydra/Chimera + Tank Week calendar logic)
│       ├── roles/                      # Day-role sync (`POST /api/internal/role-sync`)
│       ├── member_notifications/       # `/member-notify-*` per-member DM notification commands
│       ├── new_member_alerts/          # `/notify-new-members` officer join-alert subscriptions
│       ├── member_activity/            # 24h silent-joiner tracking + auto-kick
│       └── sidecar/                    # HTTP sidecar (FastAPI, port 8001)
├── migrations/                         # Alembic migration scripts (env.py, script.py.mako, versions/)
├── tests/                              # Pytest suite (unit + integration): per-package subdirectories plus top-level test modules
├── alembic.ini                         # Alembic config (local SQLite default)
├── docs/                               # Design docs, secrets inventory, framework plan
├── infra/                              # Bicep templates + AAD runbook
├── pyproject.toml                      # PEP 621 metadata, tool configs
├── Dockerfile                          # Container build (python:3.12-slim, non-root)
└── .dockerignore

CI Workflows

All workflows live in .github/workflows/:

Workflow Trigger Purpose
ci.yml PR, push to main Lint (ruff + uv lock --check), format check (black), type check (mypy), pytest, Docker build smoke test, shellcheck, pip-audit (non-blocking)
build-image.yml workflow_run after ci.yml succeeds on main Builds and pushes the :<sha> GHCR image — structurally guaranteed to run only after CI is green for that exact SHA
deploy.yml Manual (workflow_dispatch) Deploys a commit's image to the prod Container App: verifies the GHCR image exists, runs Alembic migrations via a Container Apps Job, then updates ca-mom-bot
infra-deploy.yml Manual (workflow_dispatch) Applies Bicep templates to the prod subscription (mutates live Azure infra); records the deployed commit as a GitHub Deployment on the prod-infra environment (#321)
infra-what-if.yml PR touching infra/** Posts an az deployment sub create --what-if diff as a PR comment; informational only, not a merge gate
release.yml Push of a v* tag Publishes a GitHub Release (notes from CHANGELOG.md) and an immutable :vX.Y.Z GHCR image; posts the Discord release announcement
notify-discord-release.yml Manual (workflow_dispatch) Re-posts the Discord release announcement for a given tag if the automatic post in release.yml failed
claude.yml Issue/PR comment created, PR review submitted, or issue opened/assigned Delegates to the shared glitchwerks/github-actions claude-tag-respond reusable workflow (authorized users only)
claude-ci-fix.yml workflow_run after ci.yml completes Delegates to the shared glitchwerks/github-actions ci-failure reusable workflow to attempt an automated fix when CI fails

prod-infra is a GitHub Deployments environment used only as a queryable ledger of what infra-deploy.yml last applied — it does not gate anything today. See infra/aad-runbook.md for first-time provisioning and RELEASING.md for the tag → release → deploy sequence.

Infrastructure runbook cross-reference

infra/aad-runbook.md is the authoritative operational doc for Azure infrastructure work — AAD app registration, OIDC federated credentials, the Bicep apply steps (Step 5 pre-merge, Step 9.5 post-merge), and secret seeding. It also documents the deploy-recency guardrail planned in #318 — including the webhook secret it needs and the infra/scripts/** coverage gap. This table only lists workflow entry points; consult the runbook for the operational procedure behind them.

Versioning

Mom-bot is its own product on its own version track, following semver from v1.0.0 onward (see RELEASING.md § Versioning policy), separate from siege-web. The runtime is coupled to siege-web by design (shared Discord token, sidecar HTTP contract, shared guild) — the separate-repo / separate-versioning is for code-organization clarity, not real separability.

License

TBD — to be set before first public release.

About

Discord bot for a Raid: Shadow Legends guild — reminders, role sync, and interactive slash commands, running on Azure Container Apps with Bicep IaC

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages