A serverless Discord moderation bot with 52 slash commands, running on
Val Town. No 24/7 server needed — Discord sends each /command to an HTTP
endpoint as a signed interaction, and this val responds.
Why slash commands and not a "gateway" bot? Val Town is serverless — it can't hold an always-on WebSocket connection. Discord's HTTP Interactions model is the supported way to build a bot here, and it covers every moderation action below.
Rendering mermaid diagram...
| File | Role |
|---|---|
main.ts | HTTP endpoint: verifies signature, routes interactions |
register.ts | Run once to register commands with Discord |
lib/verify.ts | Ed25519 signature verification (tweetnacl) |
lib/discord.ts | Discord REST API wrapper (ban/kick/timeout/…) |
lib/respond.ts | Interaction response & embed helpers |
lib/db.ts | SQLite storage for warnings, cases, notes |
commands/* | The 52 command handlers, grouped by area |
- Members:
banunbankicktimeoutuntimeoutmuteunmutesoftbanhardbanwarnwarningswarnpointsdelwarnclearwarnsmodlogscasereportnotenotesnickresetnickdehoistwhoisuseridavatarvoicekick - Channels:
purgecleanslowmodeslowmodeofflockunlocklockdownfreezesettopicrenamensfw - Roles:
addroleremoverolerolesroleinfo - Server / utility:
serverinfomembercountbanlistsayembedannouncepollpinginvitehelpabout
Every action command checks the invoker's Discord permissions (Ban/Kick/Moderate/Manage…) before running.
Go to https://discord.com/developers/applications → New Application. Under Bot, create a bot and copy its token. Under General Information, copy the Application ID and Public Key.
This val needs four env vars (the 4th is optional):
DISCORD_PUBLIC_KEY # General Information → Public Key
DISCORD_BOT_TOKEN # Bot → Token
DISCORD_APP_ID # General Information → Application ID
DISCORD_GUILD_ID # (optional) a test server ID for instant command updates
👉 Add DISCORD_PUBLIC_KEY here: https://www.val.town/x/dedewahyu/ReSecurity/environment-variables?key=DISCORD_PUBLIC_KEY 👉 Add DISCORD_BOT_TOKEN here: https://www.val.town/x/dedewahyu/ReSecurity/environment-variables?key=DISCORD_BOT_TOKEN 👉 Add DISCORD_APP_ID here: https://www.val.town/x/dedewahyu/ReSecurity/environment-variables?key=DISCORD_APP_ID 👉 Add DISCORD_GUILD_ID here: https://www.val.town/x/dedewahyu/ReSecurity/environment-variables?key=DISCORD_GUILD_ID
In General Information, set Interactions Endpoint URL to this val's
main.ts HTTP endpoint. Discord will send a PING to verify it — the bot
answers with a PONG automatically. (This only succeeds once
DISCORD_PUBLIC_KEY is set.)
Run register.ts (the Run button, or the val's run UI). With
DISCORD_GUILD_ID set, commands appear instantly in that server; without it
they register globally (can take up to ~1 hour to propagate).
In OAuth2 → URL Generator, select the bot and applications.commands
scopes plus the moderation permissions you want (Ban Members, Kick Members,
Moderate Members, Manage Channels, Manage Roles, Manage Messages), open the
generated URL, and add the bot to your server. Make sure the bot's role is
above the members it needs to moderate.
purgecan only bulk-delete messages younger than 14 days (Discord limit).timeout/mutemax duration is 28 days (Discord limit).- The bot's role must be higher than its targets, or actions return 403.