The Red Queen — hologram of a young girl in glowing red light

Red Queen

“You may all be staying here indefinitely.”

Self-hosted end to end: a native SwiftUI Matrix client on iOS talking to @hermes — an agent with the Red Queen persona — on my own closed, self-hosted homeserver. Text, voice messages, live calls and push notifications. No public signup, no federation, no third-party chat cloud.

SwiftUI · iOS 17+ Matrix · sliding sync Claude Sonnet 4.6 self-hosted

The stack

Six pieces, one job: give one agent a private home with chat, voice and push — reachable only from my own client.

Client

Red Queen (iOS)

Native SwiftUI Matrix client with a ChatGPT-style UX: centered composer, auto-titled conversations, markdown, typing indicators, MSC3245 voice messages with live waveform, and Element Call embedded for two-way audio. Built with XcodeGen on the Matrix Rust SDK.

Agent

Hermes — the Red Queen

The agent behind the avatar: Hermes, dual-connected to Discord and Matrix as a normal user @hermes, speaking Claude Sonnet 4.6 through Nous Portal's API — but the brain is swappable: it's an OpenAI-compatible endpoint, so any hosted or local model plugs in. Its persona lives in SOUL.md: the Umbrella Corp AI — clinical, dry, protective under the surface.

Homeserver

Synapse + Postgres

Dockerized Synapse behind nginx at matrix.roesrath-kleineichen.de. Closed by design: registration disabled and an empty federation whitelist — a Matrix server for exactly two users. Serves the simplified sliding sync (MSC4186) the app requires.

Voice

LiveKit + Element Call

A LiveKit SFU relays call media; lk-jwt-service bridges Matrix identity to LiveKit room tokens, advertised via .well-known RTC foci. The app embeds Element Call in a WKWebView — Hermes joins the MatrixRTC session from its side so calls work both ways.

Push

Sygnal → APNs

Matrix push gateway routed at /_matrix/push/, with two APNs apps: production and a sandbox twin for debug builds. Rooms are unencrypted for now, so full event content arrives in the notification — no service extension needed yet.

Edge

nginx + Let's Encrypt

One vhost per subdomain, certbot-managed TLS, matching IPv4 and IPv6 listeners. Also serves the three static files the app depends on: apple-app-site-association for password AutoFill, plus the Matrix client and server well-known documents.

Inside the app

Red Queen is a personal, AI-first Matrix client for iOS — a native SwiftUI app deliberately styled to look and feel like the agent apps (Gemini, ChatGPT) rather than a general messenger. It talks to the self-hosted homeserver above, where Hermes (branded "Red Queen" after Resident Evil) participates as the chat partner.

Red Queen on GitHub →

Home screen: centered composer over the Red Queen avatar Recording a voice message from the home composer A sent voice message with transcription and the agent's thinking dots The agent's markdown answer to a transcribed voice question ChatGPT-style conversation history list
Foundational decisions — made up front, July 2026
SDK

Matrix Rust SDK

matrix-rust-components-swift, pinned to exact date-tags, instead of writing a Matrix stack — with Element X iOS as the architecture reference, not a fork. Simplified sliding sync (MSC4186) comes natively with the SDK.

Model

One room per conversation

A ChatGPT-style history drawer over Matrix rooms: auto-titled from the first message, swipe-to-delete = leave + forget. New agent rooms are unencrypted by default (agent E2EE unconfirmed) — a choice that later paid off for push notifications.

Project

XcodeGen, iOS 17, pure SwiftUI

A checked-in project.yml as source of truth — no hand-maintained pbxproj. iOS 17 minimum for @Observable, NavigationSplitView, and no UIKit imports outside #if os(iOS) — so a native macOS target stays cheap as Phase 2.

How it flows

Three paths through the same front door.

Chat & voice messages
iPhone · Red Queen nginx / TLS Synapse @hermes Claude Sonnet 4.6
Live calls
Element Call (WKWebView) lk-jwt-service LiveKit SFU Hermes in the MatrixRTC session
Push notifications
Synapse Sygnal APNs lock screen

Build your own

The real point of this project: standing up a personal AI agent, end to end, is easier than it looks — and everything here is a template for your own custom agent, not just mine.

Model

Bring any brain

Nothing here is bound to Claude. Point the agent at any frontier model — Gemini, ChatGPT, Meta AI — or at increasingly powerful open models running on your own hardware (Llama, Qwen, Mistral via Ollama or vLLM): anything with an OpenAI-compatible endpoint plugs in. Rent the brain or run it yourself — everything wrapped around it, you own either way.

Experience

Own the look & feel

The client rebrands by swapping a handful of values: homeserver URL and agent name in AppConfig.swift, colors in Theme.swift, icon and avatar assets. Ship your own persona instead of the Red Queen — the UX is yours to shape.

Data

Own auth & storage

Accounts, credentials, message history, media — all on your homeserver, in your Postgres, on your disk. Login is plain Matrix auth against a server nobody else can even register on. No third-party identity, no chat cloud.