╔══════════════════════════════════════════════════════════════════════╗ ║ ║ ║ ║ ║ ▄▄ ▄▄ ██ ▄▄ ▄▄ ▄▄ ▄▄ ║ ║ ████ ██ ▀▀ ▀██ ██▀ ██ ██ ║ ║ ████ ▄███▄██ ████▄██▄ ████ ██▄████▄ ██ ██ ██ ██ ║ ║ ██ ██ ██▀ ▀██ ██ ██ ██ ██ ██▀ ██ ██ ██ ██ ██ ║ ║ ██████ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ ██ ║ ║ ▄██ ██▄ ▀██▄▄███ ██ ██ ██ ▄▄▄██▄▄▄ ██ ██ ████ ▀██▄▄██▀ ║ ║ ▀▀ ▀▀ ▀▀▀ ▀▀ ▀▀ ▀▀ ▀▀ ▀▀▀▀▀▀▀▀ ▀▀ ▀▀ ▀▀▀▀ ▀▀▀▀ ║ ║ ║ ║ ║ ║ A D I S C O R D M O D B O T ║ ║ ║ ╚══════════════════════════════════════════════════════════════════════╝
A cross-server Discord moderation bot written in C, with an embedded HTTP dashboard, a ticket system, a fact-check module powered by a local Ollama LLM, a cross-guild propagation alert network, and much more.
- Overview
- Features
- Architecture
- Prerequisites
- Building
- Configuration
- Running
- Modules
- Dashboard (AdminV-UI)
- REST API Reference
- Assembly Routine
- Known Issues & TODO
AdminVU (working title) is a Discord bot written entirely in C11, targeting the Linux platform. It uses the Orca C Discord library for gateway connectivity, stores all state in an SQLite3 database, and ships with a self-hosted HTTP dashboard (AdminV-UI) accessible at http://127.0.0.1:8080.
The bot is modular — each feature lives in its own .c file under src/modules/ — and is designed to be fast, low-dependency, and operator-controlled.
| Category | What it does |
|---|---|
| 🛡️ Moderation | /warn, /kick, /ban, /timeout, /warnings — all actions persisted to SQLite |
| 🎫 Tickets | Full DM-relay ticket system with anonymous staff messaging, note-taking, and a per-server config |
| 📡 Propagation | Cross-server alert network: flag bad actors, manage trust levels, appeals, and auto-escalation |
| 🧐 Fact-Check | Mention the bot + "is this true?" in a reply → local Ollama LLM writes a (satirical) counter-argument |
| 🎉 Fun | /trivia, /joke, /roll, /8ball, /choose, /coinflip, /rps, /activity |
| 📊 Dashboard | Embedded HTTP server with a real-time web dashboard (no external hosting required) |
| ⚙️ ASM | x86-64 NASM helper functions intended to run with minimal compute overhead |
discord_bot/
├── asm/ ← x86-64 NASM routines (fast_hash, fatnum_limb)
├── src/
│ ├── main.c ← Entry point, event routing, startup
│ ├── database.c ← Core DB (users, warnings, mod_logs, timeouts)
│ ├── database_propagation.c ← Propagation-specific tables & queries
│ ├── api.c ← JSON REST handlers for the dashboard
│ ├── http_server.c ← Minimal HTTP/1.0 server (pthreads)
│ ├── env_parser.c ← .env file loader
│ └── modules/
│ ├── moderation.c
│ ├── ticket.c
│ ├── propagation.c
│ ├── components_v2.c
│ ├── messaging.c
│ ├── personaplex_bridge.c ← Not tested fully
│ ├── factcheck.c
│ ├── fun.c
│ ├── ping.c
│ └── fatnum/ ← 2048-bit Arithmetic library
├── src/web/ ← AdminV-UI dashboard (HTML + CSS + JS)
│ ├── index.html
│ ├── moderation.html
│ ├── messaging.html
│ ├── propagation.html
│ ├── tickets.html
│ ├── dashboard.html
│ ├── style.css
│ └── script.js
├── .env ← Secrets (not committed)
└── CMakeLists.txt
┌─────────────────────────────┐
│ Discord Gateway │
│ (Orca websocket client) │
└──────────────┬──────────────┘
│ events
┌──────────────▼──────────────┐
│ main.c │
│ routes interactions & │
│ message events to modules │
└────┬──────┬──────┬───────┬──┘
│ │ │ │
┌───────────▼─┐ ┌──▼──┐ ┌─▼──┐ ┌─▼───────────┐
│ moderation │ │ tkt │ │prop│ │ factcheck │
└─────┬───────┘ └──┬──┘ └──┬─┘ └──────┬──────┘
│ │ │ │
┌─────▼────────────▼───────▼───────────▼───────┐
│ SQLite3 (bot_data.db) │
└──────────────────────┬───────────────────────┘
│
┌──────────────────────▼───────────────────────┐
│ http_server.c → api.c → AdminV-UI │
│ 127.0.0.1:8080 │
└──────────────────────────────────────────────┘
| Dependency | Version | Notes |
|---|---|---|
| GCC / Clang | C11 | Any modern version |
| CMake | ≥ 3.16 | |
| NASM | Any | For the ASM subdir |
| libcurl | Any | HTTP requests (fact-check, fun) |
| SQLite3 | Any | Bundled on most distros |
| pthreads | POSIX | For HTTP server thread |
| Orca | Latest | Must be installed separately — see below |
| Ollama | Any | Only required for fact-check module |
git clone https://github.com/cee-studio/orca.git
cd orca
make
sudo make installcurl -fsSL https://ollama.com/install.sh | sh
ollama pull ministral-3:8b # or any model — see FACTCHECK_OLLAMA_MODEL# Clone the repo
git clone https://github.com/PolskaKrowa/AdminVU.git
cd AdminVU
# Create a build directory
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j$(nproc)Note: The build copies your
.envfile and thesrc/web/assets into the build directory automatically. No manual copying is needed.
| Flag | Default | Description |
|---|---|---|
FACTCHECK_OLLAMA_MODEL |
"ministral-3:8b" |
Ollama model to use |
FACTCHECK_OLLAMA_URL |
"http://localhost:11434/api/generate" |
Ollama endpoint |
Example:
cmake -B build \
-DCMAKE_BUILD_TYPE=Release \
-DFACTCHECK_OLLAMA_MODEL='"mistral"'Create a .env file at the project root:
# Required
DISCORD_BOT_TOKEN=your_bot_token_here
DISCORD_BOT_GUILD_ID=your_infra_guild_id
# Optional — comma-separated list of guilds for instant slash-command updates
DISCORD_DEV_GUILD_IDS=123456789,987654321Security note: The
.envfile is copied into the build directory at configure time. Never commit it. It is listed in.gitignoreby convention.
| Permission | Required by |
|---|---|
KICK_MEMBERS |
Moderation module |
BAN_MEMBERS |
Moderation module |
MODERATE_MEMBERS |
Timeout command |
MANAGE_CHANNELS |
Ticket channel creation |
MANAGE_MESSAGES |
Anonymous staff message relay |
SEND_MESSAGES |
All modules |
READ_MESSAGE_HISTORY |
Fact-check reply lookup |
Enable the Message Content and Server Members privileged intents in the Discord Developer Portal.
cd build
./discord_botThe bot will:
- Load
.env(from../relative to the binary, or the build dir) - Initialise the SQLite database (
bot_data.db) - Start the HTTP dashboard on
http://127.0.0.1:8080 - Connect to the Discord gateway
- Register slash commands (global + dev guilds) in a background thread
src/modules/moderation.c
All actions are persisted to mod_logs and, where applicable, warnings / timeouts.
| Command | Permission | Description |
|---|---|---|
/warn <user> [reason] |
Kick / Ban / Moderate | Issue a warning; reply includes cumulative count |
/warnings <user> |
Kick / Ban / Moderate | List all warnings for a user (paginated, up to 10 shown) |
/kick <user> [reason] |
Kick Members | Remove a user from the guild |
/ban <user> [reason] |
Ban Members | Ban a user; deletes 1 day of messages |
/timeout <user> [duration] [reason] |
Moderate Members | Applies communication_disabled_until via direct REST PATCH; default 10 min, max 40 320 min (28 days) |
Timeouts are also stored in the timeouts table so the bot can track and query them independently of Discord's internal state.
src/modules/ticket.c
A full anonymous DM-relay ticket system. Users never see staff usernames; staff never see the user in the channel.
User types /ticket open server:<id> subject:<text>
│
▼
Bot creates a private channel in the staff server's ticket category
│
▼
Bot opens a DM with the user and stores the mapping (user ↔ DM channel ↔ ticket channel)
│
┌──────┴──────┐
│ │
User DMs bot Staff types in ticket channel
│ │
▼ ▼
Forwarded to Deleted + re-posted as [Staff]: …
ticket channel then forwarded to user's DM
Slash Commands
| Command | Permission | Description |
|---|---|---|
/ticket open <server> <subject> |
Anyone | Opens a ticket for a specific community server |
/ticket claim |
Staff (in ticket channel) | Assigns ticket to self, sets status to In Progress |
/ticket close [outcome] [notes] |
Staff | Closes the ticket, notifies the user via DM |
/ticket priority <level> |
Staff | Updates priority (0 Low → 3 Urgent) |
/ticket status <value> |
Staff | Updates status (0 Open → 4 Closed) |
/ticket assign <staff> |
Staff | Reassigns ticket to another staff member |
/ticketconfig [mainserver] [staffserver] [category] [logchannel] |
Administrator | Configures the ticket system for a guild |
Mention safety: All forwarded messages are run through strip_mentions() which inserts a Unicode zero-width space (U+200B) after every @, preventing @everyone, @here, and user/role mentions from firing in either direction.
src/modules/propagation.c·src/database_propagation.c
A cross-server alert network. Opted-in guilds receive notifications when a moderator flags a user. Severity is calculated from a weighted confirmation score based on each guild's trust level.
| Level | Badge | Weight | Description |
|---|---|---|---|
| Unverified | ⚪ | 1 | Default for all guilds |
| Trusted | 🔵 | 2 | Manually set by central admins |
| Verified | ✅ | 3 | Verified community |
| Partner | ⭐ | 4 | Auto-assigned to staff servers and the central guild |
| Score | Level | Emoji |
|---|---|---|
| 0 | Unconfirmed | ⬜ |
| 1 – 3 | Low | 🟡 |
| 4 – 8 | Medium | 🟠 |
| 9 – 15 | High | 🔴 |
| 16+ | Critical | 🚨 |
| Command | Permission | Description |
|---|---|---|
/propagate <user> <reason> <evidence> <confirm> |
Mod | Issue a cross-server alert |
/propagate-config <channel_id> |
Admin | Set alert delivery channel |
/propagate-opt-out |
Admin | Stop receiving alerts |
/propagate-history <user> |
Mod | View alert history for a user |
/propagate-revoke <moderator> <reason> |
Admin | Permanently blacklist a moderator |
/propagate-report <alert_id> <reason> |
Mod | Flag an alert as suspicious (auto-escalates at threshold) |
/propagate-appeal <alert_id> <statement> |
Targeted user | Submit an appeal |
/propagate-appeal-review <appeal_id> <approve|deny> [notes] |
Admin | Decide an appeal; broadcasts result to all notified guilds |
/propagate-trust <guild_id> <level> [notes] |
Central admin | Set a guild's trust level |
/propagate-central <guild_id> <channel_id> |
Bot team only | Designate the central oversight server |
/propagate-pair <main_guild_id> <staff_guild_id> |
Bot team only | Pair a community's main and staff servers |
Misuse protection: The
/propagatecommand requires typingI UNDERSTAND THE CONSEQUENCESverbatim in theconfirmfield. Blacklisted moderators are silently blocked from issuing further alerts.
src/modules/factcheck.c
Trigger: Reply to any message, then mention the bot and include "is this true?" in your message.
The bot forwards the referenced message's content to a local Ollama instance, instructing it to act as a persuasive but dishonest AI that argues against the statement. The response is sent as a reply.
User replies to a message and mentions @Bot with "is this true?"
│
┌───────▼──────┐
│ Fetch the │
│ referenced │
│ message │
└───────┬──────┘
│
┌───────▼──────┐
│ POST to │
│ Ollama API │
│ (60s limit) │
└───────┬──────┘
│
┌───────▼──────┐
│ Reply with │
│ AI response │
└──────────────┘
Configure the model and endpoint at compile time via -DFACTCHECK_OLLAMA_MODEL and -DFACTCHECK_OLLAMA_URL.
src/modules/fun.c
All fun commands return ephemeral responses (only visible to the invoker).
| Command | Description |
|---|---|
/joke |
Fetches a random dad joke from icanhazdadjoke.com |
/roll [max] |
Rolls 1 – N (default: 6) |
/8ball <question> |
Classic magic 8-ball |
/choose <options> |
Picks randomly from a comma-separated list |
/coinflip |
Heads or tails |
/rps <rock|paper|scissors> |
Rock-paper-scissors against the bot |
/trivia |
Fetches a multiple-choice question from Open Trivia DB; interactive buttons with a 60-second timeout |
/activity |
Shows the top 3 most active text channels tracked in the current session |
src/modules/ping.c
/ping [target]
Responds with Pong! 🏓 (Target: <name>, Hash: 0x<hex>).
The hash is computed by the x86-64 NASM routine fast_hash (see Assembly Routine). If a target user option is provided, the bot fetches their guild member record via REST and uses their nickname (or username as fallback).
The bot runs a minimal HTTP/1.0 server on http://127.0.0.1:8080 (loopback only — not externally accessible).
| Page | URL | Description |
|---|---|---|
| Dashboard | / |
Live stats: guild count, warnings, open tickets, propagation events, uptime |
| Moderation | /moderation.html |
Paginated mod log with guild and action filters; user warning lookup |
| Propagation | /propagation.html |
Opted-in server list, alert history, block/unblock controls |
| Tickets | /tickets.html |
Full ticket list with status/guild filters; click any row to view detail + notes |
The dashboard polls
/api/statusevery 15 seconds. All snowflake IDs are serialised as strings to preserve JavaScript precision.
All endpoints return application/json. POST bodies are application/x-www-form-urlencoded.
GET endpoints
| Endpoint | Query params | Description |
|---|---|---|
GET /api/status |
— | Warning count, open tickets, guild count, propagation events |
GET /api/guilds |
— | All known guilds with warning + ticket counts |
GET /api/mod-logs |
guild_id, action (0–3 or all), limit, offset |
Paginated mod log |
GET /api/warnings |
guild_id, user_id |
Warning records |
GET /api/propagation/guilds |
— | All guilds with propagation config + block status |
GET /api/propagation/events |
user_id, source_guild_id, limit, offset |
Alert events with notified counts |
GET /api/propagation/blocked |
— | All dashboard-blocked guilds |
GET /api/tickets |
guild_id, status |
Ticket list |
GET /api/tickets/<id> |
— | Single ticket with notes |
GET /api/tickets/events |
since (unix ts) |
SSE-style event poll |
POST endpoints
| Endpoint | Body params | Description |
|---|---|---|
POST /api/propagation/block |
guild_id, reason |
Block a guild from receiving alerts |
POST /api/propagation/unblock |
guild_id |
Remove a guild block |
asm/
The /ping command uses an x86-64 NASM hash function (fast_hash) wired via extern uint64_t fast_hash(const char *str, size_t len). It is compiled as a separate CMake subdirectory and linked into the main binary.
This serves both as a demonstration of C ↔ ASM interop and as a moderately fast string hash for display purposes.
Warning
Shutdown handler waits for webserver updates and command re-registration before each appropriate thread is joined.
When the bot is shutting down, its webserver thread waits for any sort of update (refresh, changing pages, etc.) before the thread gets joined. Making the bot appear as if it's "hanging" during the shutdown procedure. The command registry thread gets joined after every command is registered, slowing down the shutdown process significantly, especially when the bot is only online for a short period of time.
Warning
Ticket messages don't scan for messages that were meant to be sent while the bot is offline.
When the bot is offline, and there's an active ticket in progress, The bot should scan for any message that wasn't sent between the ticket opener and staff once the bot is restarted.
Note
Persistent webserver handling for managing larger audiences.
Currently the bot's webserver is designed for localhost management, but ideally the webserver should be designed for handling cases where the bot is in many servers, with different managers for each server. So a secure login system, data transport encryption, modern HTTPS handling and potentially cloudflare support would be ideal. This should only really be done once I am able to run the bot within a persistent, and powerful server which can run 24/7.
[ AdminVU ] · built in C · running on 127.0.0.1:8080
Made with way too much printf debugging.