For AI agents:
February 4, 2026 ยท View on GitHub
Edit this file to document project structure and any features you have added. The Github issue list should be used to document all in-progress work. Do not add ANYTHING resembling instance locks, or overcomplicate infrastructure. Keep it simple, stupid. If you find yourself incapable of keeping track of the service, it's not because you didn't implement dumb useless features like picking arbitrary ports or global locks. Just use supervisorctl the way god intended.
ArugoBot
Discord bot with all you need to practice competitive programming and compete against friends on Discord. Based on https://github.com/eggag32/ArugoBot/ and https://github.com/phattd15/arugo.
Usage
The following commands are available to you:
Most command responses are public; handle-linking and admin diagnostics remain ephemeral.
Handle inputs (including list options like handles) accept Codeforces profile URLs or @handles and will extract the handle.
-
/challenge problem
lengthproblem[user1..user9][open][max_participants]Starts a challenge.
-
/challenge random
lengthrating|min_rating|max_rating|ranges[tags][user1..user9][open][max_participants]Starts a challenge by selecting a random unsolved problem in the rating range (defaults to 800-3500). Use
rangesfor multiple bands, e.g.800-1200, 1400+, 1600-1800. Usetagsto require tags and prefix-to exclude tags (e.g.dp, greedy, -math). Setopento allow anyone in the server to join before the host starts. Usemax_participantsto raise the lobby cap (2-10, default 5). -
/tournament
create|join|leave|start|status|advance|cancel|historyRuns tournaments in Swiss, elimination, or arena formats. Use
createto open a lobby, pick format, match length, rating ranges, tags, and (optionally) Swiss round count or arena problem count. Users join withjoin/leave, and the host or an admin canstartthe lobby. Useadvanceto start the next round after all matches finish.statusshows standings, recent rounds, and the current round (or arena problem list and time remaining), plus lobby details when pending.historylists recently completed or cancelled tournaments for the server (select a tournament for a recap and export CSV/markdown results). -
/tournamentrecaps
set|status|clear|cleanup|postConfigure automatic tournament recap posts. Use
setto choose a channel and optional role mention.postsends the latest completed tournament recap immediately. -
/dashboard
set|status|clearAdmin-only web dashboard visibility. Use
setto opt in/out of the public dashboard,statusto see the current setting, andclearto reset to private. -
/rating
[user]Shows your (or other user's) rating graph.
-
/history
[page][user]Shows a page of your completed challenge history (result + rating delta).
-
/leaderboard
[page][metric][days]Shows a page of the server leaderboard (metric can be
rating,solves,contests,streak, orlongest_streak). Usedays(1-365) to set the lookback window for the contest leaderboard (defaults to 90 days). -
/profile
[user][handle]Shows a linked handle, rating, challenge streak, Codeforces profile info, and recent completed challenges (or a handle's Codeforces profile + recent submissions). In DMs, provide a
handle. -
/compare
[user1..user4][handles]Compares Codeforces stats for multiple linked users and/or handles.
-
/recent
[user][handle][limit][result]Shows recent Codeforces submissions for a linked user or a handle. Use
resultto filter byall,accepted, orrejectedsubmissions. In DMs, provide ahandle. -
/register
handleLinks your CF account. Verification prompts include a cancel button if you need to stop the flow. You can paste a Codeforces profile URL; the handle will be extracted.
-
/relink
handleUpdates your linked CF handle (use if you changed your Codeforces handle). Verification prompts include a cancel button if you need to stop the flow. You can paste a Codeforces profile URL; the handle will be extracted.
-
/unlink
Unlinks your CF account and erases all progress.
-
/suggest
rating|min_rating|max_rating|ranges[tags][handles]Gives some problems in the rating range that none of the CF accounts have done (defaults to 800-3500). If
handlesis omitted, uses linked handles in the server. Userangesfor multiple bands, e.g.800-1200, 1400+, 1600-1800. Usetagsto require tags and prefix-to exclude tags (e.g.dp, greedy, -math). -
/practice
rating|min_rating|max_rating|ranges[tags][user][handle]Suggests a single unsolved practice problem for a linked user or a Codeforces handle. If
handleis omitted, uses the linked handle foruser(or yourself). Userangesfor multiple bands, e.g.800-1200, 1400+, 1600-1800. Usetagsto require tags and prefix-to exclude tags (e.g.dp, greedy, -math). -
/practiceprefs
set|status|clearrating|min_rating|max_rating|ranges[tags]Sets default rating ranges/tags used by
/practicewhen you omit filters, or shows/clears them. -
/practicehistory
suggestions[user][limit]|reminders[limit]Shows recent practice suggestions for a user or recent practice reminder posts for the server.
-
/problem
idShows details for a Codeforces problem by id or URL, plus which linked users have solved it.
-
/help
Prints the help message.
-
/challenges
list[limit]|cancel|mine|recent[limit]Lists active challenges for the server or lets the host/admin cancel one. Use
mineto see your active challenge. Userecentto see recently completed challenges for the server. -
/handles
[page]Lists linked Codeforces handles for the server.
-
/handleadmin
set|unlink|statususer[handle]Admin-only handle management (link/update, unlink, or inspect a user's handle).
-
/health
Admin-only diagnostics (uptime, memory, DB status, reminder channel issues, last error, command usage/latency).
-
/logs
[limit][level][command][correlation][message][user]Admin-only log viewer for recent bot activity in the server.
-
/metrics
[command][limit]Admin-only command usage metrics (summary list or per-command details).
-
/refresh
[scope]Admin-only refresh of cached Codeforces data (problems, contests, and handle canonicalization).
-
/ping
Quick liveness check.
-
/stats
Shows server challenge stats plus recent contest participation (linked users, challenges, ratings, contest counts).
-
/activity
[days][user]Shows challenge activity summaries for the server or a specific user over a lookback window.
-
/streak
[user]Shows the current and longest challenge streak for a user (UTC days with at least one solved challenge).
-
/contests
[limit][include][exclude][scope]Lists ongoing and upcoming Codeforces contests. Use
include/excludeto filter by keywords (comma-separated, matched against the contest name). Usescopeto showofficial,gym, orallcontests. If you set default filters with/contestfilters,/contestsuses them when you omit filters. -
/contestfilters
set|status|clearConfigure default filters for
/contests(admin only). Usesetto store default include/exclude keywords and scope for this server,statusto show the current defaults, andclearto reset. -
/contest
query[scope]Shows details for a contest by id, URL, name,
latest(most recent finished contest),next/upcoming(soonest upcoming contest), orongoing(current contest if any). Usescopeto searchofficial,gym, orallcontests. -
/contestresults
query[limit][user1..user4][handles][scope]Shows standings for linked users (or specified handles) in a contest. Use
latestto target the most recent finished contest. Useinclude_practiceto include practice submissions in the standings. -
/contestchanges
query[limit][user1..user4][handles][scope]Shows rating changes for linked users (or specified handles) in a finished contest. Use
latestto target the most recent finished contest. Rating changes are only available for official contests; gym contests show a warning. -
/contestsolves
query[limit][user1..user4][handles][scope]Shows which contest problems linked users have solved and highlights unsolved problems. Use
latestto target the most recent finished contest. Provide handles or users to limit the list (handles are required outside a server). Useforce_refreshto bypass the contest submissions cache. -
/contestupsolve
query[user][handle][limit][scope]Shows unsolved contest problems for a linked user or a Codeforces handle. Use
latestto target the most recent finished contest. Useforce_refreshto bypass the contest submissions cache. -
/contesthistory
[user][handle][limit]Shows recent Codeforces contest rating changes for a linked user or handle.
-
/contestactivity
[days][limit][scope]Shows recent contest participation for the server's linked handles, including top participants and recent contests.
-
/contestdeltas
[days][limit][scope]Shows recent contest rating deltas for the server's linked handles, including top gainers/losers. Use
scopeto showofficial,gym, orallcontests. -
/contestreminders
add|set|list|status|preset|remove|clear|cleanup|preview|postConfigure contest reminders for the server (admin only). Use
add(or legacyset) to create multiple subscriptions with distinct channel, lead time, role mention, and keyword filters (include/exclude, comma-separated) plus contestscope(official, gym, or all). Uselist/statusto see subscription ids (useonly_issues:trueto show missing channels or permissions),removeto delete one,clearto delete all, andcleanupto remove subscriptions pointing at deleted channels (useinclude_permissions:trueto also remove subscriptions where the bot lacks channel permissions).preview/postaccept an optional subscription id when multiple are configured.postcanforcea reminder even if one was already posted.presetadds a curated subscription (Div 1, Div 2, Div 3, Div 4, or Educational) with sensible keyword filters. Subscriptions are automatically removed if the target channel is deleted. -
/contestratingalerts
set|status|list|remove|clear|cleanup|preview|postConfigure rating change alerts for finished contests (admin only). Use
setto choose a channel and optional role mention,min_deltafilter, andhandlesfilter (comma-separated, linked handles only).list/statusacceptonly_issues:trueto show missing channels or permissions.cleanupremoves subscriptions pointing at deleted channels (addinclude_permissions:trueto also remove ones missing bot permissions).previewshows the next alert for linked handles, andpostsends the latest rating change summary immediately (optionallyforceto resend). -
/practicereminders
set|status|clear|cleanup|preview|postConfigure practice problem reminders (admin only). Use
setto choose a channel, time, optionalutc_offset(e.g.+02:00,-05:30,Z), optionaldays(e.g.mon,wed,fri,weekdays,weekends), rating ranges, optional tags, and an optional role mention. Ifutc_offsetis omitted the time is interpreted as UTC. Usecleanupto remove reminders pointing at deleted channels (addinclude_permissions:trueto also remove ones missing bot permissions). Usepostto send a practice problem immediately (optionallyforceto send even if one was posted today). Reminders are automatically cleared if the target channel is deleted. -
/digest
set|status|clear|cleanup|preview|postConfigure a weekly digest for the server (admin only). Use
setto choose a channel, day, time, optionalutc_offset, and optional role mention. Digests include challenge activity, top contests by participation, and rating delta highlights. Usecleanupto remove digests pointing at deleted channels (addinclude_permissions:trueto also remove ones missing bot permissions). Usepostto send a digest immediately (optionallyforceto send even if one was already posted this week).
Reminder and digest channels must grant the bot View Channel + Send Messages permissions; the set flows will warn if the bot cannot post.
Installation
To try the bot, join the Purdue CPU Discord: https://purduecpu.com/discord If you want to host it, install dependencies with pnpm (Node 18+), set the required env vars, and run the bot:
Required environment variables:
DISCORD_TOKENDATABASE_URL(e.g.sqlite:./bot_data.db)
Optional environment variables:
DISCORD_GUILD_ID(register slash commands for a single guild for faster updates)CODEFORCES_API_BASE_URL(defaulthttps://codeforces.com/api)CODEFORCES_REQUEST_DELAY_MS(default2000)CODEFORCES_TIMEOUT_MS(default10000)CODEFORCES_STATUS_TIMEOUT_MS(default20000, used forcontest.status/user.status)CODEFORCES_SOLVED_MAX_PAGES(default10, set0for unlimited)PROXY_FETCH_URL(optional proxy list URL; one proxy per line ashost:portorhost:port:user:pass)LOG_RETENTION_DAYS(default30, set0to disable log cleanup)DATABASE_BACKUP(directory for automated backups, disabled if unset)DATABASE_BACKUP_RETENTION_DAYS(default7, set0to keep all backups)CODEX_LOG_PATH(path to the Codex log file for token usage estimates, e.g.../codex.log)WEB_HOST(default0.0.0.0)WEB_PORT(default8787, set0to bind a random open port)WEB_PUBLIC_URL(optional, e.g.https://bot.example.com, used for/dashboardlinks)GITHUB_WEBHOOK_SECRET(optional GitHub webhook secret; enables signature verification for/github)GITHUB_CODEX_LABEL(defaultcodex)GITHUB_ACTIVE_LABEL(defaultactive)GITHUB_REPO(optionalowner/repo, enables startup scanning for open codex-labeled issues)CODEX_PROMPT_PATH(default/home/codex/prompt.txt)CODEX_WORKTREE_PATH(default/home/codex/arugobot-work)CODEX_MAX_ITERATIONS(default0for unlimited)CODEX_STATUS_COMMENT_MINUTES(default30)CODEX_ITERATION_COOLDOWN_SECONDS(default10)
pnpm install
pnpm approve-builds
pnpm run dev
Releases
Tagged releases (v*) publish a source archive on GitHub Releases. You can download the latest
release archive from the Releases page and follow the installation steps above.
The bot runs database migrations on startup.
Problem and contest caches are persisted in the database to keep basic functionality available during Codeforces outages.
Structured logs are appended to the database (log_entries) and cleaned up automatically based on
LOG_RETENTION_DAYS. If DATABASE_BACKUP is set, the bot copies the sqlite file into that directory
on a schedule and removes backups older than DATABASE_BACKUP_RETENTION_DAYS.
GitHub issue automation
The web server exposes POST /github for GitHub issue webhooks. When an issue is opened with (or
later given) the GITHUB_CODEX_LABEL, the bot queues a single Codex worker. The worker:
- creates/refreshes a git worktree at
CODEX_WORKTREE_PATHon a new branch off the repo default branch - runs
codex execin a loop until the issue is closed (orCODEX_MAX_ITERATIONSis hit) - posts periodic progress comments (every
CODEX_STATUS_COMMENT_MINUTES) - applies
GITHUB_ACTIVE_LABELwhile working and removes it afterwards
If GITHUB_REPO is set, the bot scans for open codex-labeled issues on startup and after each job.
Web dashboard
The bot serves a Hono-powered dashboard for global stats and per-guild leaderboards.
By default it listens on http://localhost:8787 (override with WEB_HOST/WEB_PORT).
If the configured port is busy, the bot will retry a couple of nearby ports and fall back to a random
open port, logging the chosen port on startup.
Only guilds that opt in via /dashboard set public:true appear on the public pages.
If WEB_PUBLIC_URL is set, /dashboard responses include direct links to your guild page.
The overview highlights core bot features alongside upcoming contest cards, plus global contest
participation snapshots sourced from cached rating changes (split by official vs gym activity),
contest rating alert coverage, and rating-change cache freshness. Per-guild pages include
CSV/Markdown exports for rating/solve leaderboards, and /status shows cache ages for key
Codeforces syncs including the gym contest list. Tournament summaries link to full recap pages
at /guilds/:guildId/tournaments/:tournamentId (with rounds, match results, and problem lists), and
/api/guilds/:guildId/tournaments/:tournamentId exposes the same data as JSON.
/status.json returns the same cache status in JSON for external monitoring.
/api/overview returns the global snapshot and public guild summaries as JSON, and
/api/guilds/:guildId returns the per-guild overview payload (respecting the public dashboard setting).
/healthz returns JSON with a quick DB + Codeforces check plus cache status (useful for uptime monitors).
Token usage estimates
If CODEX_LOG_PATH is set, the bot periodically scans the log for token totals and reports
approximate energy, water, and carbon estimates (GPT-5 medium assumptions) in /health and
the /status dashboard page.
@misc{jegham2025hungryaibenchmarkingenergy,
title={How Hungry is AI? Benchmarking Energy, Water, and Carbon Footprint of LLM Inference},
author={Nidhal Jegham and Marwan Abdelatti and Chan Young Koh and Lassad Elmoubarki and Abdeltawab Hendawi},
year={2025},
eprint={2505.09598},
archivePrefix={arXiv},
primaryClass={cs.CY},
url={https://arxiv.org/abs/2505.09598},
}
Deployment (Supervisor + Caddy)
Sample configs live in deploy/ and assume you are running on a Linux host with systemd.
Use supervisorctl for start/stop to avoid running multiple instances (which can cause the dashboard
port to be in use).
- Install dependencies and allow native build scripts:
pnpm install
pnpm approve-builds
- Configure Supervisor (update the Node + project paths):
sudo cp deploy/supervisor.conf /etc/supervisor/conf.d/arugobot.conf
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl status
To restart or inspect logs:
sudo supervisorctl stop arugobot
sudo supervisorctl start arugobot
sudo supervisorctl tail -f arugobot
- Configure Caddy (update the domain name):
sudo cp deploy/Caddyfile /etc/caddy/Caddyfile
sudo systemctl reload caddy
Sample Caddyfile (TLS via subdomain + reverse proxy):
arugobot.purduecpu.com {
reverse_proxy http://localhost:8787
}
- Confirm the web server responds:
curl -I http://127.0.0.1:8787
Quality gates:
pnpm run lint
pnpm run format
pnpm run test
pnpm run build
To typecheck and run the production bot (tsx runtime, no JS build output):
pnpm run build
pnpm start
Future TODOs
- Expand the weekly digest with richer contest analytics (per-contest highlights, streaks).