Channels, direct messages, and files
Channels and DMs have replies, reactions, and attachments. Roles and invites control who gets in and what they're allowed to do.
- Direct messages
- Attachments
- Roles + invites
A self-hostable chat and voice app for small communities, built on an open-source base.
I work on the web client, the native iOS app, and the Electron desktop app, plus the unglamorous stuff around them: call-state bugs, desktop packaging, and an admin dashboard for keeping an eye on the server.
Mutinycommunity chat
Counted from the repos in November 2026. Both commit totals include the upstream project's history, so most of those commits aren't mine. 1.2.8 is the version number in the desktop source.
Mutiny has text channels, direct messages, file sharing, voice rooms, and screen sharing. The web app is Solid.js. The desktop app wraps that same web client in Electron, and iOS gets its own native SwiftUI app.
I didn't start from zero. Mutiny sits on an existing open-source codebase, and most of my time goes into adapting it, wiring the clients to the server, and chasing bugs where what the screen shows drifts from what's actually happening underneath.
Chat goes through the API, with a WebSocket pushing events back. Attachments go to a separate file service. To join voice, the client asks the API for room access, then connects to LiveKit directly. The admin dashboard reads straight from MongoDB.
scroll to see the full diagram →
You see the same community in every client, but each platform has its own quirks to get right.
Channels and DMs have replies, reactions, and attachments. Roles and invites control who gets in and what they're allowed to do.
LiveKit carries the audio and video. On the web you click to join voice, and the floating call card has mute, deafen, and a preview of what you're sharing.
The Electron app adds what you'd expect from a desktop app: a tray icon, native notifications, and auto-updates. Packaging is its own job on each platform, since macOS and Windows sign and ship apps differently.
The iOS app has native message views, attachment previews, a notification extension, and LiveKit voice. It's still in development, and the release checklist has manual steps I haven't finished.
I write release requirements and known failure cases into the repo so they get checked again whenever the code changes.
The web client watches LiveKit for track changes and reads the real microphone, camera, and screen-share state from it. Leaving a call clears all of that. Tests cover each of those paths, plus the join button.
A build that runs on my own Mac can still fail on someone else's. The desktop signing guide spells out what a real release needs: a Developer ID signature, notarization, a ticket check, and a Gatekeeper check. Faked signing in tests can't stand in for that.
I built a separate admin dashboard that shows how many accounts, messages, communities, and files there are. It reads from MongoDB and has a sample-data mode so I can work on it locally. Web releases also have to ship with public patch notes, and that's written down as a rule.
The work I like most is chasing one bug from the button someone clicked, through the app's state, all the way to the build they installed.
Electron gets the web interface for free. SwiftUI has to be built separately, so I keep a clear list of what each client supports and don't assume they match.
Clicking share screen only means someone wants to share. LiveKit is what knows whether a track actually went out. The difference shows up the moment someone cancels the screen picker or drops out of a room.
Signing taught me to keep code tests and packaged-app checks apart. A green test run tells me nothing about whether Apple accepted the build I'm about to hand out.
The metrics view only reads data. The admin routes beside it can edit accounts and communities, so giving someone the dashboard gives them that power too.
I'm looking at hands-on systems and product engineering roles. I'm happy to walk through the client code, the call-state handling, or the desktop release process live.