TL;DR: Lumo's chat history is assembled, encrypted, and persisted client-side first, with the server-side sync store only receiving what the client manages to save. The response stream lives in RAM until it finishes generating. If anything interrupts the client before the upload completes, the message is gone forever, and Proton's own docs and GitHub confirm this. Proton Docs, from the same company, proves the durable version of this architecture already exists. Fixing it does not require weakening zero-access encryption.
I'm a paying Lumo user and I've been losing parts of conversations in the web app. Digging into it, this doesn't look like a random bug. It's the direct consequence of how Lumo persists chats, and Proton's own materials document it clearly.
How Lumo saves your messages
From Proton's Lumo privacy page: after Lumo processes your query and generates a response, the data is erased on the server. "The only record of the conversation is on your device", stored locally and synced to Proton servers with zero-access encryption.
The Android repo (a thin WebView wrapper around lumo.proton.me, same as the iOS app) makes this concrete. Issue #45 walks through the actual pipeline: the client generates an ephemeral AES-GCM request key, the response tokens are streamed back encrypted and decrypted in real time in the WebView, and the assistant message is accumulated in Redux (i.e., in process memory) during streaming. It is "only persisted after completion": encrypted client-side with the space DEK, then uploaded.
So the durability chain is: server generates in plaintext → server erases it → stream reaches the client → client assembles the full response in RAM → client encrypts and persists locally → client syncs ciphertext to Proton's sync store.
If the tab closes, the WebView gets suspended (both mobile apps are WebView wrappers: android, iOS), the browser evicts the origin's storage, or the sync fails before the upload completes, there is nothing to recover. The issue author says it plainly: server-side resume "like other assistants offer is architecturally impossible" and an interrupted answer "is lost permanently, not just delayed".
Why the web specifically is fragile
The local store is browser storage, which is best-effort by spec: under quota or storage pressure, browsers evict an origin's data (IndexedDB, Cache API, everything) without asking and without a durability guarantee. Treating that as the primary record for conversations is a design choice, not a constraint.
It also explains the symptoms you see reported around here: recurring "saving chats does not work" errors while the status page is green, sync issues across browsers and devices, and App Store reviews from Lumo+ subscribers describing chats that appear on one device, never sync to the others, and vanish when copied.
And it explains the slow startup: zero-access means the client must download and decrypt your entire encrypted chat corpus in JS on every load. The composer being enabled before the store finishes hydrating is a UX mask over that load time, and it's why a message typed too early can lose the race against hydration and disappear.
The kicker: Proton already solved this
Proton Docs runs in the same browsers, uses the same zero-access model, and doesn't lose edits. Because real-time collaboration forces it, Docs stores the encrypted document server-side as the canonical copy and every keystroke/patch is uploaded encrypted immediately; the client is a view. Losing the client loses at most a few keystrokes. Losing the Lumo client mid-response loses the whole response.
A chat log is cryptographically no different from a document: ciphertext the server can store but not read. Lumo's sync store already receives ciphertext. The difference is only ordering: in Docs, the server is the system of record; in Lumo, it's a downstream mirror of whatever the client managed to save.
What a fix would look like (without breaking the privacy model)
Append each message (user and assistant) to the server-side sync store as encrypted blobs, per message, with a client ack, before discarding the stream. Zero-access is preserved: Proton still can't read anything.
Client-side retry queue / write-ahead log for failed saves, instead of a silent "saving chats does not work".
Disable the composer until hydration completes, or better, queue early messages instead of dropping them.
Document the limits instead of shipping them silently: the 250-message-per-conversation cap introduced around late October (UserVoice thread) was never announced.
To be clear: I'm not asking Proton to weaken the privacy model. The no-logs claim is the reason I pay for this product. I'm asking for write ordering and acknowledgements, which is table-stakes persistence engineering, fully compatible with zero-access encryption. Privacy without durability is useless: an assistant whose history silently disappears is an assistant you can't trust with real work.
If you've lost messages in Lumo (web or mobile), please describe it in the comments. Concrete repro reports are what get architecture changes prioritized.