A chat interface is one of those products that looks straightforward until the connection drops. A user presses Send. The message appears. Then their laptop sleeps, their connection returns, and they discover the same message twice—or a reply that arrived before the message it answered.

That is where communication software stops being a collection of screens and starts becoming a distributed system.

At Recline, we're building a community-chat client with real-time channels, direct messages, calls and desktop support. We publish the client code so developers can see what is implemented and, just as importantly, where its current limitations are.

This article walks through the building blocks of our client, what each one is responsible for, and the engineering questions we're still working through. It is an architecture explanation, not a claim that every feature or security property has been independently audited.

One product, several distinct kinds of traffic

Not everything should travel through the same connection. In the Recline client, different tasks have different jobs:

  • HTTP requests load account state, conversation history and other resources where a request-and-response model makes sense.
  • Socket.IO supports live updates, including the event-driven behavior needed for messaging and presence.
  • WebRTC handles live media and connection establishment for voice and video.
  • Client-side cryptography transforms supported message text before it is sent and after it is received.
  • Tauri packages the current web interface as a desktop application, with platform integrations around it.

The frontend is built with React, TypeScript, Vite and Tailwind CSS. These choices make it possible to share interface and application logic across the browser and the current desktop build. They do not remove the need for a careful protocol between the client and server.

You can inspect the public Recline client repository rather than relying on this description alone.

The difference between loading messages and receiving them

Opening a conversation and receiving the next message are related, but separate operations.

An HTTP request is a natural fit for fetching a page of history. The response has a defined start and end, and the client can handle loading, failure and retry states.

A realtime connection is a better fit for learning that something has changed while the user is already looking at a conversation. But that introduces questions the UI must answer:

  1. What happens if the user sends a message while the socket is reconnecting?
  2. What constitutes a successful send: local display, server acknowledgement, or delivery to another device?
  3. If the same event arrives twice, how do we avoid displaying two messages?
  4. After reconnection, how do we detect events missed while offline?
  5. Can the UI distinguish a failed send from one that is merely taking longer than expected?

These are general protocol-design questions, not promises that every edge case is already solved in Recline. They are also the questions we'd put into automated tests before trusting a rewritten native client with a user's messages.

A useful design rule is to treat server-assigned message identity and authoritative history as more reliable than an optimistic bubble drawn on one device. The interface can respond immediately, but it must be able to reconcile that immediate display with the server's eventual answer.

Where encryption sits in the architecture

The fact that a client uses encryption says little on its own. You also need to understand where keys are derived, which data is encrypted, and what the server can still observe.

Recline's current client code includes AES-256-GCM for supported encrypted message text. For Space text, it derives a key using PBKDF2-SHA256 with 300,000 iterations in the archived implementation. For DMs, it uses P-256 ECDH key agreement and HKDF-SHA256 to derive message-encryption keys.

Those primitives have different roles: PBKDF2 derives key material from a passphrase, ECDH establishes shared secret material between parties, HKDF derives usable keys from that material, and AES-GCM encrypts and authenticates data. Choosing known primitives is preferable to inventing an encryption scheme, but the total security of a system depends on much more than algorithm names.

There is an important current limitation: the existing Space access protocol sends the Space passphrase to the backend during verification. Although supported Space text is encrypted client-side, this is not a server-blind design. Attachments are also handled separately from encrypted text. A database containing ciphertext is only one piece of the threat model.

DM encryption has a different key lifecycle. In the current web client, key handling also involves browser storage and encrypted key backups. A second client must reproduce the exact message formats and key-recovery behavior; simply implementing the same cryptographic algorithms is not sufficient.

Developers can review the relevant client files in the repository, including src/lib/crypto.ts and src/hooks/useDmKeys.ts. The implementation and its tests are a better starting point for evaluating these boundaries than an unqualified encryption slogan.

Voice calling is a different protocol problem

A message can wait in a queue while a network connection recovers. A live voice call cannot hide a five-second interruption in the same way.

Recline's client uses WebRTC for live calls. WebRTC negotiates a media connection, searches for viable network paths and may use a TURN relay when direct connectivity isn't possible. Calls also have to manage permissions, device changes, audio processing and reconnection.

This distinction is useful when debugging. A working Socket.IO connection does not prove that microphone access works. A working camera preview does not prove that the remote peer can receive media. And successful peer-to-peer media on one home network doesn't establish that a call will work behind an enterprise firewall.

We document the path-selection side in How Voice Calls Work: WebRTC, STUN & TURN. The implementation is visible in src/lib/webrtc.ts.

Why the desktop shell doesn't make the UI native

The distributed Windows desktop beta uses Tauri 2. Tauri gives us a desktop shell around the React interface and access to native capabilities through its Rust integration. On Windows, that interface is rendered through WebView2. On macOS, Tauri uses WebKit.

That is a useful reuse strategy: improvements to the main web interface can often benefit the desktop experience too. But it also means that media APIs, browser storage, permission prompts and authentication flows need platform-specific testing.

A future WinUI 3 client with no WebView would take a different path. It could use Windows controls directly, but it would also need its own implementation of application state, realtime communication, key handling, and media integration. The backend does not need to be replaced merely because the frontend technology changes—but compatibility becomes a first-class engineering requirement.

We compare those approaches in WebView vs Native Desktop Apps.

Five checks for any open-source chat client

If you're evaluating a chat application, including ours, these are more useful questions than a features list:

  1. How are message sends acknowledged and retried? Ask what happens after a disconnect, not just on a good network.
  2. Which data is encrypted, and where are the keys? Separate message text, uploads, credentials and metadata.
  3. Can a new device recover old conversations safely? Inspect backup and migration behavior before changing cryptographic storage.
  4. How does calling behave on difficult networks? Test different NATs, denied permissions and relay-only connections.
  5. Does the public code match the shipped product? Look for reproducible builds, release provenance and clear limitations.

Open source makes inspection possible; it doesn't replace a security audit or reliability testing. We believe those are good reasons to publish our client code and explain the trade-offs as we make them.

What we're building toward

The long-term goal is not to preserve React or Tauri forever. It's to make Recline's communication behavior stable enough that multiple trustworthy clients can implement it: web, current desktop, and potentially future native Windows and Mac applications.

That means treating message formats, key formats, acknowledgements and recovery as compatibility contracts—not incidental details hidden in a component.

If you'd like to inspect the implementation or offer technical feedback, start with the Recline client source on GitHub. If you're evaluating the product itself, see Recline's current beta status and the main website. We also post development updates on X.