No description
  • Rust 96.4%
  • Shell 2.8%
  • Dockerfile 0.4%
  • Nix 0.4%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Ivan c28dc2d47b
Some checks failed
Rust, Docker, Code Coverage / fmt (push) Failing after 16s
Rust, Docker, Code Coverage / clippy () (push) Failing after 1m30s
Rust, Docker, Code Coverage / clippy (--all-features) (push) Failing after 1m42s
Rust, Docker, Code Coverage / clippy (--features "opentelemetry ai-openrouter util-download") (push) Failing after 1m31s
Rust, Docker, Code Coverage / build () (push) Successful in 1m43s
Rust, Docker, Code Coverage / build (--all-features) (push) Successful in 2m25s
Rust, Docker, Code Coverage / build (--features "opentelemetry ai-openrouter util-download") (push) Successful in 2m18s
Rust, Docker, Code Coverage / docker (push) Failing after 2s
Rust, Docker, Code Coverage / test (push) Failing after 4m29s
feat(forgejo): add Forgejo Actions CI mirroring the GitHub workflow
origin is a Forgejo instance (git.hu-tao.dev), so CI now lives where the
code does. .forgejo/workflows/ci.yml mirrors .github/workflows/full.yml —
fmt, clippy and build across the empty/deploy/all feature matrix, tests
against Postgres + Redis service containers, and a Dockerfile build.

Three deviations, all forced by Forgejo running jobs inside a container
rather than on a VM: third-party actions are referenced by full github.com
URL (the runner's default registry is code.forgejo.org), services are
reached by service name instead of localhost with an explicit TCP wait loop
(the runner ignores `options:` health-checks), and the coverage report is
kept as a run artifact instead of pushed to Codecov.

Also syncs the GitHub matrix's deploy feature string with
scripts/deploy-features.sh, which gained util-download in 72b2a6e.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-09-12 13:57:19 +03:00
.cargo Add tracing and profiling 2026-01-12 00:29:21 +02:00
.forgejo/workflows feat(forgejo): add Forgejo Actions CI mirroring the GitHub workflow 2026-09-12 13:57:19 +03:00
.githooks ci: fan out pipeline into parallel jobs + cache deps (#29) 2026-06-14 19:32:50 +03:00
.github feat(forgejo): add Forgejo Actions CI mirroring the GitHub workflow 2026-09-12 13:57:19 +03:00
.sqlx chore(ai): remove /ai-review — superseded by automatic AI reviewers (#42) 2026-06-24 01:02:16 +03:00
assets chore(readme): add Grafana Tempo span details screenshot 2026-06-07 14:39:48 +03:00
database Added skill-icons 2024-06-11 23:44:10 +03:00
deploy/supervisor fix(commands,deploy): use node + ejs:github for YouTube n-challenge; set cookies env 2026-06-24 13:26:34 +03:00
docs feat(commands): add YT_DLP_COOKIES_PATH for YouTube auth bypass (#46) 2026-06-24 12:32:20 +03:00
grafana/provisioning/datasources fix(docker): use host networking for Tempo and Grafana 2026-06-07 18:40:01 +03:00
migrations chore(ai): remove /ai-review — superseded by automatic AI reviewers (#42) 2026-06-24 01:02:16 +03:00
scripts revert(deploy): remove nodejs install from bg-deploy.sh 2026-06-24 13:12:23 +03:00
serenity_discord_bot_derive Add documentation and additional testing for the Asset proc macro 2026-03-04 18:07:59 +02:00
src feat: expose AI_MAX_TOKENS as an env var 2026-09-08 21:50:51 +03:00
.dockerignore chore(docker): load env via env_file instead of COPY .env 2026-06-07 13:43:48 +03:00
.env.example feat(commands): add YT_DLP_COOKIES_PATH for YouTube auth bypass (#46) 2026-06-24 12:32:20 +03:00
.gitattributes feat(commands): add YT_DLP_COOKIES_PATH for YouTube auth bypass (#46) 2026-06-24 12:32:20 +03:00
.gitignore feat(commands): add YT_DLP_COOKIES_PATH for YouTube auth bypass (#46) 2026-06-24 12:32:20 +03:00
.gitlab-ci.yml ci: fan out pipeline into parallel jobs + cache deps (#29) 2026-06-14 19:32:50 +03:00
AGENTS.md chore(ai): remove /ai-review — superseded by automatic AI reviewers (#42) 2026-06-24 01:02:16 +03:00
build.rs Migrate the AI provider from Ollama to the llm crate 2026-06-07 01:37:19 +03:00
Cargo.lock chore(ai): remove /ai-review — superseded by automatic AI reviewers (#42) 2026-06-24 01:02:16 +03:00
Cargo.toml chore(ai): remove /ai-review — superseded by automatic AI reviewers (#42) 2026-06-24 01:02:16 +03:00
CHANGELOG.md chore(ai): remove /ai-review — superseded by automatic AI reviewers (#42) 2026-06-24 01:02:16 +03:00
CONTRIBUTORS.md docs: documentation overhaul (architecture, security, contributors, custom reactions) (#18) 2026-06-14 12:02:57 +03:00
docker-compose.infra.yml fix(docker): use host networking for Tempo and Grafana 2026-06-07 18:40:01 +03:00
docker-compose.yml fix(docker): consolidate to single tempo.yaml using /var/tempo 2026-06-07 16:31:02 +03:00
Dockerfile fix(docker): install git and the GitHub CLI in the runtime image 2026-06-11 23:36:28 +03:00
flake.lock feat: add flakes ❄️ 2026-09-08 22:22:32 +03:00
flake.nix feat: add flakes ❄️ 2026-09-08 22:22:32 +03:00
LICENSE Create LICENSE 2024-03-17 20:22:57 +00:00
README.md chore(ai): remove /ai-review — superseded by automatic AI reviewers (#42) 2026-06-24 01:02:16 +03:00
SECURITY.md chore(ai): remove /ai-review — superseded by automatic AI reviewers (#42) 2026-06-24 01:02:16 +03:00
tempo.yaml fix(docker): consolidate to single tempo.yaml using /var/tempo 2026-06-07 16:31:02 +03:00

Serenity Discord Bot

GH_Build IconBuild IconCoverage IconLicense Icon

Rust PostgreSQL Docker Redis Grafana

Bot profile

Try the bot out!

A Hu Tao-themed Discord bot built with Serenity and Poise. Responds to both slash and prefix commands (hu, ht), with persistent XP levelling backed by PostgreSQL and an optional AI persona that stays in character across a full channel conversation window.

The minimal build needs only a Discord token and PostgreSQL; AI, Redis, and telemetry are opt-in Cargo features. Run it with:

cargo run --release

For deeper detail, see the documentation: architecture, configuration, deployment, AI features, and observability.

Features

  • /help — lists every registered command
  • Embed interaction commands: tieup, pat, hug, kiss, slap, punch, bonk, nom, kill, kick, bury, selfbury, peek, avatar, drive, chair, boom, quote
  • XP levelling with a 60-second cooldown, stored in PostgreSQL — /level for a member's level, /toplevels for the server leaderboard
  • /reminder — schedule a DM for later (create/list/search/delete), with a saveable default timezone (/reminder timezone, per-server or global) and browsable, paginated history
  • /util — utility commands: /util avatar, /util uptime, /util age, and /util download (when util-download feature is enabled)
  • /age — your or another member's account creation date
  • /cookie — give someone a cookie
  • /uptime — bot uptime
  • /custom reaction add url:<url> pattern:<regex> [anywhere:<bool>] — register an image + Rust regex; whenever a guild message matches, the bot replies with the image in an embed. anywhere: false (default) anchors to the full message; anywhere: true matches anywhere. The confirmation shows the reaction's per-guild number (#1, #2, … within the server). Tenor/Giphy page links (tenor.com/view/…, giphy.com/gifs/…) are rejected — paste the direct media URL (media.tenor.com/....gif) instead. Requires Manage Channels. Per-guild cap: 25
  • /custom reaction list — list the server's reactions (ephemeral) with their per-guild numbers, patterns, and anywhere flags (Manage Channels)
  • /custom reaction remove name:<autocomplete> — soft-delete the reaction picked by its per-guild number from autocomplete (Manage Channels, cache-backed). Numbers are positional, so removing one renumbers the rest
  • Levenshtein-distance typo correction on unrecognised prefix commands

Optional features

Everything optional is a Cargo feature. ai is a meta-feature — enabling it also enables redis — and it requires picking exactly one ai-<backend>.

Feature What it adds Notes
(core) Commands, XP, reminders, custom reactions Needs only BOT_TOKEN + PostgreSQL.
redis Cross-instance AI context, locks, rate limits Standalone. Single instance works without it.
ai The AI persona chat Meta-feature: also enables redis. Needs a backend (below).
ai-<backend> The AI provider Exactly one of ai-deepseek, ai-ollama, ai-anthropic, ai-openai, ai-google, ai-groq, ai-openrouter. Mandatory when ai is on.
opentelemetry OTLP trace export Point at any OTLP collector; compose ships Tempo + Grafana.
util-download /util download — yt-dlp + ffmpeg 2-pass encode targeting 8 MB Needs yt-dlp and ffmpeg (with ffprobe) on PATH.
tokio_console Tokio Console runtime inspection Needs RUSTFLAGS="--cfg tokio_unstable".

Building with --features ai and no backend stops at a compile_error! by design. See docs/configuration.md for the environment variables each feature reads.

AI

An in-character Hu Tao persona powered by the llm crate, which supports every mainstream provider. The backend is chosen at compile time — enable exactly one of: ai-deepseek, ai-ollama, ai-anthropic, ai-openai, ai-google, ai-groq, ai-openrouter.

Set AI_MODEL and AI_API_KEY (hosted backends) in .env — see .env.example for all variables.

  • /ai — one-off prompt in any channel or DM
  • /aichannel — toggle a channel where the bot auto-replies to every message (requires Manage Channels)
  • /custom prompt add|show|remove — set a per-server instruction block appended to the AI's system prompt, applied to both /ai and auto-replies (requires Manage Channels)
  • Set REDIS_URL to keep conversation context in Redis and to share AI locks and rate limits across bot instances; without it the bot re-fetches recent messages from Discord on every reply and coordination is per-instance

AI channel demo

AI DM demo

Tokio Console

Task-level async runtime inspection via Tokio Console:

RUSTFLAGS="--cfg tokio_unstable" cargo run --features tokio_console

tokio-console task view

Telemetry

Distributed tracing via OpenTelemetry — backend-agnostic, so you can point it at any OTLP-compatible collector. The compose setup ships with Grafana Tempo and Grafana pre-wired as the UI. See docs/observability.md for the tracing layers and the category span field. To run Tempo manually (create /var/tempo once with your user as owner):

sudo mkdir -p /var/tempo && sudo chown $USER /var/tempo
tempo -config.file=./tempo.yaml

otel-tui trace view

Grafana Tempo trace view

Grafana Tempo flame graph

Grafana Tempo span details

Setting up

  1. Copy .env.example to .env and fill in the values.
  2. Have PostgreSQL running and reachable at DATABASE_URL — migrations run automatically at startup.
  3. Run:
cargo run --release
# or, to enable specific features:
cargo run --release --features='<your-features>'

To run the telemetry stack (Grafana Tempo + Grafana) in containers while running the bot natively:

docker-compose -f docker-compose.infra.yml up -d

Docker Compose

The compose file brings up PostgreSQL, Redis, Grafana Tempo, and Grafana alongside the bot:

docker-compose up -d

Important

Make sure you aren't running PostgreSQL or Grafana Tempo locally due to port conflicts!

Note

The Dockerfile builds with the features listed in its FEATURES arg (defaults to ai-deepseek opentelemetry tokio_console). Override via the compose build args to change provider or feature set.

Documentation

See SECURITY.md for the secrets inventory, and CONTRIBUTORS.md to set up a dev environment.