● Technical details

How this works under the hood.

Every privacy-bearing capability is anchored to a design record. The page below describes each capability + the architecture that enforces it; the records themselves are pending publication (see Read deeper).

01 The shape of the system

Mobile + web clients hold the keys. A Cloudflare Workers gateway routes ciphertext to an open-weight model (currently NVIDIA Nemotron 3.5 Lightning) served through Phala's confidential-inference API, on TDX + Confidential GPU. Phala's gateway enclave decrypts the request and forwards it over a verified channel to the enclave running the model. The Worker is a confidential gateway, not an enclave — Cloudflare sees only ciphertext for conversation content. Clients verify Phala's gateway enclave, not the Worker; the model's enclave behind it is checked by Phala.

02 Encryption and keys

Conversation bodies, transcripts, and recaps are ciphertext in our R2 storage; metadata-only rows live in D1. Per-conversation keys are derived from a libsignal-style on-device Ed25519 / X25519 identity keypair sealed in the OS keystore (iOS WhenUnlockedThisDeviceOnly; Android hardware-backed Keystore, encrypted at rest). On Android the key is not yet bound to device unlock — setUserAuthenticationRequired is not set, so a key extracted from an unlocked, compromised device is not additionally gated. That binding is planned, not shipped. The server never holds a user private key.

03 Attested confidential inference

Before sending plaintext, the client fetches the inference TEE's signed attestation receipt (dstack-v1 format) and verifies the measurement matches a published policy at /.well-known/attestation-policy.json (signed and published for dev, test and staging today; the production policy awaits its offline signing ceremony, so production serves a placeholder the client rejects). On mismatch the client refuses to send — there is no silent fallback to a non-attested LLM. Closed frontier models (GPT / Claude / Gemini-class) are explicitly excluded from the inference path because they cannot be deployed in a customer-verifiable TEE.

04 Voice calls (planned)

Planned, not live: the app refuses every call today, because React Native's WebRTC has no Insertable Streams. The design: LiveKit-mediated rooms with mandatory E2EE Insertable Streams and a load-bearing application-layer cipher layered on top. The client probes for Insertable Streams availability at room-join time and refuses to start the call if the platform API is unavailable. The SFU sees opaque RTP frames, never decoded audio.

Tested end to end. We boot the OSS LiveKit server, drive a real call through both the cipher and the SFU, and assert that none of the frames the SFU receives decode as audio. Two complementary checks run side-by-side: the cipher's own output sampled before it hits the network, and the bytes the SFU actually reads after transport-level decrypt. If either path lets an intelligible audio frame through, the test fails.

05 Audio understanding

Planned, not live: nothing transcribes or analyses audio today. The design sends every audio path to one place, a TEE-hosted audio-native multimodal model. Audio is encrypted on-device against the attested enclave's public key and decrypted only inside enclave memory; the model (Qwen2.5-Audio-7B-Instruct planned primary, Phi-4-multimodal fallback) returns transcript + structured analysis (speaker turns, sentiment, prosodic notes) encrypted to the client's session key. The company and the cloud provider would see ciphertext; the audio enclave would be the only thing that sees plaintext.

Offline behaviour, as designed: when the TEE path is unreachable (attestation failure, no network), the client buffers the audio locally (encrypted at rest on the device) and uploads it to the TEE once connectivity returns. The local buffer never transcribes — there is no on-device speech-to-text path that could produce a non-TEE transcript. Cloud STT vendors (Deepgram, AssemblyAI, OpenAI Whisper, etc.) are not in the design: they cannot run in a customer-attestable TEE.

06 Sharing

A per-resource wrap model: each shareable artefact carries a per-resource symmetric key wrapped to each recipient's identity key. Revoking a share revokes that wrapped copy on the server: the recipient's device stops being given the key, and the next read returns nothing. There is no "we promise to delete" handshake — revocation is enforced at the read path, not by asking the recipient nicely. What revocation cannot do is reach backwards: anything the recipient already opened and kept, they keep.

07 Recovery

Three options, user-selected at User creation (no skip path, no default-accept): passphrase, paired device, or both. The recovery blob is OPRF-hardened against offline brute force using an SVR2-style protocol; an attacker who steals the encrypted blob cannot mount an offline dictionary attack. Passphrases require zxcvbn ≥ 5. No magic-link recovery path that would leak the user's identity to whoever runs the SMTP relay.

08 Audit log

Every privacy-bearing action writes one INSERT-only row to a per-user hash-chained log. The chain head signs to the user's identity key at user-determined intervals, producing tamper-evident checkpoints. A server that rewrote history would produce a hash-chain break the client detects on next sync.

09 Encrypted export

An encrypted record of your account, not a copy of it: the titles and dates of your conversations and goals, your devices, your sharing, and the exporting device's audit trail. It holds no content and no content keys, so what you said, the replies and your recaps are not in it. One binary format (tt-backup/v1, extension .ttbk): server-authored JSON frames, encrypted on your device under a key only you hold (from a passphrase, or bound to that device) with XChaCha20-Poly1305 in chunks of about 1 MiB, signed by your identity key, and size-padded to a 1.05× bucket curve to bound the size-correlation signal. The file is kept with your account for 30 days. Not yet: saving a copy to your device, restoring from one, moving to a new device with one, or reading one with a public tool.

10 Device pairing

New devices pair via X3DH with a user-verified short authentication string (SAS). The Worker is the relay, not part of the trust chain — a malicious relay cannot substitute its own key without producing a visible SAS mismatch. Every pairing flow on the site goes through this primitive.

11 Cost cap

Inference is quota-gated at the gateway: per-User + per-Account Durable Objects enforce request and spend ceilings, with a global spend-cliff that halts all inference if hit. Quota-hit produces a clear user-facing message; the system fails closed rather than running up a surprise bill on the user or the company.

12 Push notifications

APNs / FCM never see Private Data. Every push payload is a generic envelope: a kind drawn from a small fixed catalogue, a static title and body belonging to that catalogue entry, and an opaque ciphertext field — never envelope content. Android uses FCM data-only messages, so the OS renders nothing on its own. Today the ciphertext field ships empty on the single notification kind we send, and the on-device decrypt handlers (an iOS notification service extension, an Android data-message handler) are not yet built. Encrypted notification bodies arrive with those handlers.

13 Identity vs. account

Two distinct authentication tiers: the Account session (Better Auth — email / Google OAuth / Apple Sign-In / phone OTP) authorises billing + account ops; the User identity key authorises Private Data access. The Account session alone is insufficient to read Private Data; operations that touch it perform an on-device signature or decryption with the keystore-sealed identity key. Every User is their own Account-Owner by default; Account-removal of a User starts a 180-day claim window rather than deleting Private Data.

→ Read deeper

Design recordspublishing pendingevery architectural choice + why
Threat modelpublishing pendingassets, adversaries, what we claim and what we don't
Foundations planpublishing pendingarchitecture overview + phased roadmap
Attestation policy.well-known ↗the inference policy the client verifies; signed for dev, test and staging, production pending its ceremony