Paul HittandClaude Opus 5 4dd628d571 Reactions during a call
Tap a reaction while somebody is talking and it shows on their screen
for a moment. Agreement without interrupting, on a voice call as well as
video.

The signal rides the ratchet like every other call signal, is accepted
only for the call in progress and only once it is up, and is recorded
nowhere: when the call ends there is no trace of it. An older build
ignores an action it does not know, and the emoji key is absent on every
other kind, so nothing else on the wire changes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-11 21:33:23 -04:00
2026-09-09 09:27:20 -04:00
2026-09-11 21:33:23 -04:00
2026-09-11 21:33:23 -04:00
2026-09-11 07:46:33 -04:00
2026-09-11 12:51:29 -04:00
2026-09-09 16:58:52 -04:00

Flamenet Messenger

An end-to-end encrypted messenger: the apps, the server they talk to, and a specification complete enough that someone else could build a compatible client from it.

The site is at https://flamenetmessenger.com, which is served by the relay in this family and explains what the apps do, what the server keeps, and where the limits are.

This repository holds all of it, and is the source of truth for every part. A protocol and the thing that speaks it drifting apart in separate repositories is how "compatible" quietly stops being true, so the interop harness here compiles the iOS engine and runs it against the JavaScript one on every change, which only works while they sit in the same checkout.

Sources/    the app (SwiftUI), including its Swift E2E engine
Tests/      unit tests — run on any Mac, no device
UITests/    the driven-simulator suites
Resources/  assets, entitlements, the shared sticker manifest
docs/       design notes, the roadmap, the padding design

The rest of the product lives in its own repositories, each with its own pipeline:

Repo What it is
flamenet-e2e The protocol: JS engine, specification, published vectors, the interop driver
flamenet-relay The server
flamenet-messenger-android The Android app

those three lived here as subtrees, and the public repos were rsync extracts of them, refreshed by hand. The extracts drifted for days at a time. They are standalone now, split out with their history, work on each product happens in its own repository, and a patch to a subtree here has nowhere to go because the subtrees are gone.

What still spans repos, and how it is wired rather than wished for:

  • flamenet-e2e's interop driver compiles this app's Sources/E2E/*.swift, it finds this repo as a sibling checkout, or via FNMSG_APP_DIR.
  • The Android engine fetches the published vectors from flamenet-e2e at HEAD in CI rather than carrying a copy that would drift.
  • The relay's conformance job clones flamenet-e2e for the §8 harness.

The three engines

The protocol is implemented three times rather than an accident. Two implementations that agree may agree because one was written while reading the other; a third, written against the specification and the published vectors, is what finds the places where the spec says less than the first two quietly assumed.

They are checked against each other rather than trusted:

Engine Where State
JavaScript flamenet-e2e/src/, 8 files Complete, the reference implementation, and the one the published vectors are generated from
Swift Sources/E2E/, 20 files Complete, and compiled directly into the interop harness rather than reimplemented for it
Kotlin flamenet-messenger-android/engine/, 18 files Complete: X3DH, the ratchet, sealed sender, the key-transparency log, safety numbers

Running the tests

Each repository tests itself; there is no longer a command that runs all of them, because they are no longer one checkout.

# this repo — the app's unit suite, the merge gate
xcodegen generate && xcodebuild -project FlamenetMessenger.xcodeproj \
  -scheme FlamenetMessenger -sdk iphonesimulator \
  -destination "platform=iOS Simulator,name=iPhone 17" \
  test -only-testing:FlamenetMessengerTests

The cross-repository suites live in flamenet-e2e and need it checked out as a sibling of this one (or FNMSG_APP_DIR pointing here):

cd ../flamenet-e2e
node test/conformance.mjs   # published vectors, both backends
node test/interop.mjs       # compiles THIS app's Sources/E2E and runs it against the JS engine — needs a Mac
node test/relay.mjs         # drives a compiled relay over real HTTP; needs FN_RELAY_DIR

relay.mjs drives a binary, so swift build in the relay checkout has to have run first, a stale binary passes tests for code you just changed.

UI tests (UITests/) are not in any gate: they need a local relay on port 18810 and, for the conversation suites, two booted simulators. Without the relay they skip rather than fail, so read the executed count and not the tick.

Running the relay

The server is its own repository now:

git clone https://gitlab.com/paulhitt/flamenet-relay.git
cd flamenet-relay
cp .env.example .env    # then fill in the secrets it asks for
docker compose up -d

Open http://localhost:8080. The relay serves this project's website itself, so a working install explains what it is rather than answering with a 404. For production, see that repository's docs/HOSTING.md.

Building the iOS app

xcodegen generate
open FlamenetMessenger.xcodeproj

Requires Xcode and XcodeGen (brew install xcodegen).

FlamenetMessenger.xcodeproj/project.pbxproj is generated and gitignored. Declare sources in project.yml and regenerate; never hand-edit it.

The app is pinned to relay.flamenet.io; the sign-in screen accepts another address for a relay you run yourself.

The app has not been released. SCOPING-v1.md tracks what stands between it and a first TestFlight build.

What is published

All four repositories are public under the MIT licence, this one included. That was not always true: the app was private while the engine and server were mirrored out of it by an allowlist, and those mirrors were the only public copies. They are standalone repositories now, so what you are reading is the source rather than an extract of it.

Being public is a constraint on what may be committed: no keystores, no passphrases, no secrets, ever, including in test fixtures and in the history.

  • The protocol: flamenet-e2e/docs/SPEC.md, also served at /spec
  • What an auditor would need: flamenet-e2e/docs/AUDIT-SCOPE.md, served at /audit
  • What the relay stores: served at /metadata
  • What is not done: served at /roadmap
  • How to contribute: CONTRIBUTING.md · security: SECURITY.md
S
Description
Flamenet Messenger for iOS — X3DH + Double Ratchet with hybrid post-quantum key agreement, on CryptoKit. MIT.
Readme MIT
53 MiB
Languages
Swift 98.1%
Shell 1.3%
Python 0.4%
JavaScript 0.2%