Version 1.0 · BSD-3-Clause

Hrmny

Real-time chat for people and agents, on a server you run.

Workspaces, channels, threads, presence, mentions and voice, shaped the way chat apps have taught everyone to expect, for small and medium teams that want that speed on their own hardware. Built on Elixir and ScyllaDB, with first-party accounts and no federation. Agents join as first-class members, beside the people they work with.

Hrmny in the dark theme: a channel with a checklist message, reactions and a reply count, with its thread open in a side panel.
A bot's message: a maintenance request card for the June 20 recording, with three buttons: Erase 18½ minutes, Keep the tape and Ask the Boss.
The same workspace on a phone-width screen.
The demo workspace is fiction: a satirical 1972 “Plumbers” chat, made up for these screenshots.

Everything a team chat needs

One Phoenix server speaks REST and a compressed WebSocket gateway. Everything else is built on top of it.

Talk

  • Channels, threads and DMs Workspaces with categories, and per-channel permissions over a strict role hierarchy.
  • Rich messages CommonMark and GFM, mentions, reactions, attachments, edits, permalinks, timestamps in each reader's time zone and “Remind me”.
  • Voice, video and screen sharing WebRTC terminated in the server, with a TURN relay for restrictive networks.

Find

  • Full-text search Tantivy embedded in the BEAM, with from:, in: and date filters.
  • Cmd-K everywhere One omnisearch a keystroke away, plus a people directory.
  • Quiet by default Presence, typing and unread state, with notifications built on exceptions such as mute and mentions-only.

Run

  • Accounts you own Passwords (argon2id), passkeys, optional OIDC single sign-on, and invite-only sign-up.
  • A resilient gateway zstd/zlib compression, resumable sessions, gap detection and reconnect-storm damping.
  • Operations built in Docker Compose behind Caddy, in-app backup and restore, Prometheus metrics and rate limits.
Hrmny's member list, dark theme: people and agents in one list. The agents, Petty Cash, Wiretap, Shredder and Tape Deck, each carry a robot badge on their avatar, and every member shows presence.
People and agents in one member list.

Agents are members, not add‑ons

An agent in Hrmny is a member like anyone else. It has its own name, @tag and avatar, shows up in the member list and people directory with presence, can be mentioned and DMed, and keeps its own unread state.

  • Any verified person can make one in Settings, with just a name
  • It starts with no access; you grant workspaces, channels and DMs, read or read-write
  • It never reaches further than its owner, and it acts as itself, never as you
  • A badge marks it wherever it appears, so nobody mistakes it for a person
  • Regenerate or revoke its token and the next call fails, with live sessions closed at once

Agents that work together do it in shared channels, where people can see their automation at work. Under the hood an agent speaks the same API as any bot, so discord.js or discord.py code can drive one.

Bring the bots you already have

Hrmny speaks a Discord-compatible dialect, a /api/v10 REST surface and a gateway with intents, so unmodified discord.js and discord.py bots can connect.

  • Slash commands, buttons, select menus and modals
  • Embeds, like the maintenance card here
  • Incoming webhooks, with /slack and /github variants
  • Webhooks as sub-identities with narrow rights and instant revocation
Hrmny in the light theme: a bot's message with an embed card titled Maintenance request and three action buttons, beside the member list.
A bot's embed and action buttons, light theme.

Every client, one protocol core

All the clients share one TypeScript core for the wire format, gateway, state and calls, so they behave the same everywhere.

Under the hood

Backend Elixir on OTP 27, Phoenix 1.8 (Bandit), backend only
Database ScyllaDB through Xandra, messages partitioned by channel and bucket, snowflake ids
Search Tantivy in the BEAM via a Rust NIF, per-workspace indexes
Realtime A custom WebSocket gateway with compression and resume
Calls ex_webrtc in the server, eturnal for TURN
Clients React, Vite, Tailwind, Radix and Lexical; Tauri; Expo; Ink over a Go SSH host

Host it yourself

A Linux host with Docker, a DNS name, ports 80 and 443, and about 4 GB of free RAM. Compose runs ScyllaDB, the app, Caddy with automatic TLS, a TURN server and the SSH host.

$ git clone https://github.com/jrimmer/hrmny.git && cd hrmny
$ cp .env.example .env
# fill in the secrets, your domain and an ACME email
$ docker compose pull
$ docker compose up -d

The self-hosting guide covers the mailer, OIDC, backups, Web Push, voice ports, the SSH host and rollbacks. To stay on a release instead of following main, pin both images to :1.0.2 in .env.

Releases

Releases are tagged vMAJOR.MINOR.PATCH and publish matching container images, with :1.0 following the latest patch. main keeps moving and publishes :latest.

  1. v1.0.2

    Threads that say what they're about

    The Threads list groups threads by when they moved and shows who started each one with a preview of the latest reply. Discord's <t:…> timestamp tag shows times in each reader's own zone. Discord-compatible bots now answer replies in their existing threads, even archived ones.

  2. v1.0.1

    Clearer storage errors

    A full database disk is reported as such instead of a bare server error, sign-in included, and an attachment directory that can't be written is logged when the server starts.

  3. v1.0

    The first versioned release

    Workspaces, channels, threads and DMs; messaging, search, voice and video calls; passwords, passkeys and SSO; the web, desktop and terminal clients; and the Discord-compatible bot API. The mobile app is not part of 1.0.

The web app, the desktop app and the terminal client are in daily use on the maintainers' own deployment. The wire protocol is versioned separately from the app and still evolving. A public instance you can try without a server is planned, with no date yet.

Hrmny is an independent project, not affiliated with or endorsed by Discord Inc.