Is there a really simple chat server written in Roc yet? I need one for my project.
I'm writing a multi-player game that is currently serverless (and thus single-player unless you want to play all turns yourself, which actually kinda works in my game, but that's a strange detail).
I want the game to support chat in both the obvious sense and the apps-talking-to-each-other are really just-chatting-opaque-messages sense.
I don't even remotely need it to run at any kind of scale yet. I don't even need user registration yet.
For those of you who didn't see #introductions > hello from Steve Howell I am obviously aware of things like Zulip. :slight_smile: I want something a zillion times lighter for now.
Steve Howell said:
Is there a really simple chat server written in Roc yet? I need one for my project.
Not that I'm aware of, claude may be able to build one using the examples here: https://github.com/roc-lang/basic-webserver/tree/0.13.1/examples
I definitely want the chat server to support HTTP for basic endpoints like start_chat and find_chatters, so the above link is helpful. The only slightly non-trivial thing I want is some kind of websockets support. (Zulip actually uses long polling for events, and I'm not opposed to anything that just works, as long as it gets me up and running, but I need the code to be super lightweight, which precludes Zulip. )
(and of course I want it in Roc, which also precludes a lot of other ideas haha)
I have zero hands-on experience with either Roc itself or claude. But I do have some pretty good conceptual understanding of Roc (coming from Elm) and AI (not deep, but I get the basic ideas). So if I can have something to hack on, I think I can contribute back.
Also, the reason I am posting to #ideas (here) instead of #beginners (I am clearly a beginner!) is that I think it would be a good idea for Roc to have a canonical chat server. It's a little more common for front-end-biased frameworks and languages to use "chat" as its entry app, but I think it makes sense for back-end languages as well. (This will probably be my first project here, and I'm just fishing for code to start with, so bear with me. :slight_smile: )
My understanding is that the old compiler / platform api made it difficult to do async or green threads well, and this is why basic-webserver is thread-per-request and doesn't support websockets. The rewrite has an easier-to-use platform api, but most of the platforms have yet to be rewritten, including basic-webserver.
So I think you could do a long-polling version with the published basic-webserver (and old compiler), and another option is to get your hands dirty with platform stuff with the rewrite interpreter.
Luke's templates would be the place to start for Option B:
https://github.com/lukewilliamboswell/roc-platform-template-zig
https://github.com/lukewilliamboswell/roc-platform-template-rust
Semi-related, I have long been a fan (from the outside, fogging the glass) of ChatOps, pioneered by Etsy. This is where there is a sysadmin room, and a bot within the room. All sysadmin tasks are issued to the bot, who makes the change and reports the result back to the chat. In this way, all members stay updated, and all changes are logged and controlled. No rogue ssh sessions.
I would be very interested to develop RocOps bot, mostly as an exercise. I would welcome any collaboration or support. I haven't developed a bot before, but I've dabbled with the idea here and there.
The Zulip API is pretty easy to use. The most "sanctioned" bindings are the Python bindings, but it's really just an HTTP API, and that's documented too. The Zulip API lets your bot long-poll to get new messages, and when your bot gets a message, it's super straightforward to send a message back to Zulip (to whoever ping'ed the bot, of course). And you can do whatever you want in the bot itself.
https://zulip.com/api/real-time-events is the basic idea.
https://zulip.com/api/send-message is how a bot would talk back to Zulip.
As talking to Zulip is clearly I/O, it seems we'd need a zulip-platform. I'm wondering what would be in scope for such a platform. I would be tempted to implement in Zig, but not sure about using Python or HTTP in this context. I would imagine a direct Python impl is kind of off the table -- we need an object file / linkable machine code, right? If there is some C library for Zulip, Zig could build it. I'm not sure about trying to drive an HTTP API from Zig.
You can totally implement a Zulip API in Zig.
If you open the network tab in this very app, you can see the kind of typical messages that go from a client to the Zulip server. Most of the messages that go across the wire from the official Zulip client are part of the public interface, and the only minor difference between these requests and the requests that a non-authenticated API client uses are that the latter sends an API key. It's all HTTP. Regular HTTP for all your typical stuff and long-polling HTTP to receive events.
is there a good example of Zig driving an HTTP API? anything well known and simple? or just a good working example?
This is me performing a request while watching the network tab heh!
haha :slight_smile:
I just googled "zig http example" and it looks like the zig std.http.Client example is on par with every other language I've ever used, apart from some defer/allocate stuff that is zig-specific.
ok, nice -- I know go excels with http stuff and has reasonable string handling. I'm expecting Zig to be closer to Go than C in this respect.
Probably true! (I did most of my C programming before HTTP became a mainstream thing, haha.)
I'm not volunteering (yet) to write a Zig client for Zulip, but I can certainly offer a few pointers. The main Zulip docs are here: https://zulip.com/api/rest
Setting up your API key through the UI is straightforward enough: https://zulip.com/api/api-keys
A good POST endpoint to try is to send a message to this site: https://zulip.com/api/send-message
(Just make sure to use "type": "private" in your initial testing so it sends you a DM instead of hitting a channel.)
Thanks Steve. I can't promise not to bait you with tasty morsels. I'm at work now, but this is probably my next platform project.
Looking forward to it! No pressure, haha.
The trickiest part about writing a new Zulip client in a new language from the ground up is getting the authentication-via-API-key piece working. After that, it's mostly vanilla as heck.
The Zulip docs provide CURL examples. It's sometimes easier to just think of going up the stack from CURL vs. reverse-engineering the standard Python/JS mechanisms. So be sure to check out the "curl" tab in https://zulip.com/api/send-message:
your user_id is 780900 (this is public, I found it from your profile), and this can be useful when you use the API
For Roc, I would imagine a cross-platform package that takes http effectful functions and provides a higher level API for interacting with Zulip
in other words, just use basic-cli or equivalent platform, and do everything in Roc, e.g. with basic-cli.Http? that makes more sense.
Yeah, that's the idea.
I can imagine we have some common interfaces that emerge like Http which most platforms align on, and so this will be easy to wire up to any package
Even if a platform doesn't match the API 1-1 you should be able to wrap it, like if your platform only provide TCP/UDP primitives instead.
see also #off topic > vibe coded a zulip clone heh
If anybody is still interested in getting Roc to talk to Zulip, here's a pretty small JS example that you can try to port. Just replace the two lines at the top. You can get your API key by going to gear menu and Personal Settings/Account&privacy has it toward the bottom of the panel:
const api_key = "EFCFREDhJKFREDI2g5FRlDllFREDDQOO"
const my_email = "fred@example.com";
const site = "https://roc.zulipchat.com";
function get_headers() {
const auth = btoa(`${my_email}:${api_key}`);
const auth_header = `Basic ${auth}`;
return { Authorization: auth_header };
}
function get_user_info() {
query = `users/${my_email}`;
const url = `${site}/api/v1/${query}`;
const method = "GET";
const options = { method, headers: get_headers() };
const promise = fetch(url, options);
promise.then((response) => {
const json_promise = response.json();
json_promise.then((data) => {
console.log(data);
});
});
}
(The email there is whatever email you used to set up your Zulip account. If you didn't use email to set up your account, Zulip assigns you a fake email that you use in the authentication.)
Thanks Steve! This is still very much on my radar, but my focus has shifted for the moment to an Elixir project (poker-trainer-with-LLM-assistance)
Last updated: Jun 16 2026 at 16:19 UTC