GitHub - IanSeyler/BareMetal-Discord-Bot: A simple Discord bot that repeats messages directed to it in pig latin · GitHub
/" data-turbo-transient="true" />
Skip to content
Type / to search
Sign in<br>Sign upAppearance settings
You signed in with another tab or window. Reload to refresh your session.<br>You signed out in another tab or window. Reload to refresh your session.<br>You switched accounts on another tab or window. Reload to refresh your session.
Dismiss alert
{{ message }}
IanSeyler
BareMetal-Discord-Bot
Public
Notifications<br>You must be signed in to change notification settings
Fork
Star
main
BranchesTags
Go to file
CodeOpen more actions menu
Folders and files<br>NameNameLast commit message<br>Last commit date<br>Latest commit
History<br>6 Commits<br>6 Commits
images
images
.gitignore
.gitignore
LICENSE
LICENSE
README.md
README.md
discord_bot.c
discord_bot.c
View all files
Repository files navigation
BareMetal-Discord-Bot
Image generated by ChatGPT - it dropped the ball at the end of the speech bubble.
A simple Discord bot that watches one channel and replies with a Pig Latin translation of any human message that directly @mentions it.
Runs as an ordinary *nix program, and on BareMetal - an exokernel, written in x86-64 Assembly, built to run a single, statically-linked program directly on hardware (or a microVM) with no OS overhead in between.
Why this exists
Most Discord bots likely assume a full OS, a language runtime, a garbage collector, and hundreds of megabytes of headroom for good measure. This one doesn't. Every buffer in discord_bot.c is static and of fixed-size - nothing is malloc'd - specifically so it can run in a RAM-constrained environment.
In a world where "small" usually still means a few hundred MiB, this bot has been tested running successfully end-to-end, polling Discord and posting replies, inside a 4MiB Firecracker microVM on BareMetal Cloud:
And here it is replying in the wild, in the Return Infinity Discord #test channel:
How it works
Polling, not the Gateway. A "real" Discord bot normally holds a<br>persistent WebSocket open to Discord's Gateway and gets pushed<br>MESSAGE_CREATE events. That's not available here - the BareMetal-App<br>curl port this is built against has WebSockets compiled out (HTTP/HTTPS<br>only). So instead this polls GET /channels/{id}/messages every<br>POLL_INTERVAL_SECS, using after to only ask for messages newer than the<br>last one it already handled, and replies via POST /channels/{id}/messages
both ordinary HTTPS requests through libcurl.
@mention gating. On startup the bot looks up its own user id via<br>GET /users/@me, then only replies to a message whose raw content contains<br>a literal or for that id. Everything else (@everyone,<br>role mentions, plain messages) is ignored.
Hand-rolled JSON. There's no JSON library here - json_extract_string()<br>/ json_extract_object() / split_json_objects() do just enough parsing<br>for this shape of Discord response, tracking string/escape state and<br>brace/bracket depth so nested objects (like a reply's<br>referenced_message, or a mentioned user's own "id") can't be mistaken<br>for the outer message's fields.
Pig Latin rules. A leading vowel run gets "way" appended; otherwise<br>the leading consonant cluster (a trailing "qu" counts as part of it, so<br>"queen" -> "eenquay", not "ueenqay") moves to the end plus "ay"; a word<br>with no vowels just gets "ay". Only the first letter's case survives<br>(ALL-CAPS input comes back Titlecase). Discord mentions/channels/emoji<br>(, , ) and http(s):// URLs are passed through<br>untouched so translating them can't break a real ping or a working link.
Build instructions
BareMetal
git clone https://github.com/ReturnInfinity/BareMetal-App<br>cp discord_bot.c BareMetal-App/<br>cd BareMetal-App<br>./setup.sh<br>./1-build.sh discord_bot.c<br>./2-run.sh<br>./3-upload.sh # optional - upload to BareMetal Cloud
*nix (Linux/BSD/macOS)
discord_bot.c is also a valid standalone C program - just link it against libcurl:
gcc -O2 -o discord_bot discord_bot.c -lcurl<br>./discord_bot
Discord setup
Create an application + bot at the Discord Developer Portal.
Copy the bot token into DISCORD_BOT_TOKEN in discord_bot.c.
On the Bot tab, enable the Message Content Intent toggle - without it, Discord redacts the content field (returns "") on every message this bot didn't send itself, for both the Gateway and this REST endpoint.
Invite the bot to a server with the bot scope and the Read Messages/View Channel + Send Messages permissions.
With Developer Mode enabled in Discord, right-click the target channel -> Copy Channel ID -> set DISCORD_CHANNEL_ID in discord_bot.c.
main() refuses to run with either value left empty. Both are per-bot secrets, so don't commit real values into a shared/example file.
Notes
TLS verification is off. CURLOPT_SSL_VERIFYPEER/VERIFYHOST are<br>both disabled since no CA store is vendored on the BareMetal-App curl<br>port. TLS still buys confidentiality on the wire, just not server-identity<br>assurance - acceptable for...