Show HN: A Discord bot running in a 4MiB microVM

ianseyler1 pts0 comments

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...

discord baremetal discord_bot messages message channel

Related Articles