Chat you can
host yourself.
Servers, channels, threads, DMs and calls in the shape you already know. The difference is who runs it: anyone can host an instance, and one client connects to all of them as one flat list.
general
Server channel · readable by Acme adminsFamiliar on the surface. Different underneath.
Lumia looks like the chat apps you use today. What changes is where your data lives, who can read it, and who gets to decide.
Instances are islands
Each instance is one deployment: a server, a Postgres database, and a blob store. Instances never talk to each other. Your client bridges them, so no operator sees the others.
One identity, many accounts
Your identity is a key hierarchy on your devices. Each instance you use holds an account bound to it. Joining a server on a new instance is a URL and a tap.
One flat list of servers
Work, friends, your own box, the flagship. They all sit side by side in one client. The instance is plumbing that only surfaces where trust or routing depends on it.
You always know who can read a conversation.
A conversation has exactly one of two natures and it never changes. The app tells you which one you are in.
Channels and server DMs
Belong to the server and follow its rules. Readable by the server, its admins and its bots, which is what makes moderation, search, retention and compliance possible.
- Public and private channels, threads, reactions
- Roles and permissions set by the server's admins
- Retention is a governance policy, never something a plan can override
End-to-end encrypted
Belong to the people in them and are encrypted with MLS. No server can read them, including the one Lumia runs. Not a setting, not a plan feature: the only way personal DMs work.
- Inside a server or across instances
- Device keys stay on your devices
- Stated guarantees with stated failure modes, not “works”
Two containers. That is the whole stack.
The Lumia image and Postgres. No Redis, no search engine, no message broker. Everything optional has a working default without it, and the docs say what that default does not do.
- No unconfigured outbound calls. The server makes no network request you did not explicitly enable.
- Optional push relay. Open source, content-free wakeups only, and the one Lumia-operated dependency. Leave it off and nothing else breaks.
- Scale when you need to. Nodes are stateless and homogeneous. Add more behind a load balancer; Postgres stays the single source of truth.
- Unlimited by default. A self-hosted instance ships with an unlimited plan. You set the hard limits.
services: lumia: image: ghcr.io/lumia/lumia:latest ports: ["443:4000"] environment: LUMIA_HOST: chat.example.com DATABASE_URL: postgres://lumia@db/lumia volumes: [blobs:/data] db: image: postgres:17 volumes: [pg:/var/lib/postgresql/data] # That's it. Push, TURN, SFU and S3 are opt-in. $ docker compose up -d
One edition. No enterprise tier. No license keys.
Every feature ships in the open source server. Hosted plans sell storage, call capacity, history and operations. They never sell code.
SSO, SCIM, audit log, compliance export, retention policies: all in the same image everyone runs. Hosted forks share their changes.
The Rust core and the Protobuf schemas are permissive so third-party clients and bots are unencumbered.
First-party clients use only the public API. If the official app can do it, your bot or client can do it too.
Every instance speaks the Model Context Protocol, so agents get the same API as people, with the same permissions.
One Rust core. A native shell on every platform.
Protocol, encryption, sync and the local store are shared. Each platform gets a UI built for it rather than a web view pretending to be one.
Run it yourself, or let us run it for you.
The flagship instance runs the exact same code as the one you would deploy, with no special cases. Pick whichever you trust more. You can change your mind later.