Draft Persistence (Crash-Safe)
Draft Persistence means an unsent message does not vanish. Text typed into a team-chat composer is written to the browser's local storage a fraction of a second after you stop typing — and again, immediately, when the window is closing — so switching workspace, reloading or crashing still leaves the text waiting. It stays on that one device and is deleted when you sign out.
What it is
Draft Persistence protects the message you are composing before you send it. In a fleet app you constantly switch between sessions, and losing a half-written reply to a switch or a reload is a real cost. This feature keeps that text safe so you can leave a composer mid-thought and come back to it intact.
It is deliberately a local guarantee. Drafts live only in this device's storage — the same choice Slack makes for local drafts — and never travel to the cloud, so a draft is not synced to your other machines and is not part of team history.
Where to find it
There is nothing to turn on: draft persistence runs in the team-chat composer. Type a message, switch workspace, or close the app, and when you return the text is still there. It is a background guarantee rather than a control. Gmail compose is a separate surface with its own behaviour — it auto-saves the draft to the Gmail API, shows a Saving/Saved indicator in the dialog header, and offers a Resume banner in the inbox once the dialog is closed.
How it behaves
Writes are debounced, not continuous: a typing burst produces one write about 400 ms after you pause, and the latest snapshot for that workspace wins. Two composers for different workspaces inside the same window no longer clobber each other, because pending saves are tracked per workspace.
Debouncing alone would lose the last few keystrokes, so closing or reloading the page triggers a synchronous, un-debounced flush first — every pending workspace is written immediately, including one whose debounce had not yet fired. That flush is best-effort, not a guarantee.
Drafts are stored per workspace under a dated envelope, and anything older than 30 days is pruned the first time drafts load. Storage trouble never escalates: a quota error or an unreadable blob is treated as "no drafts" and logged, never allowed to break the composer.
One deliberate safeguard: drafts are identity-scoped. Signing out clears every workspace's stored draft, so text written under one user can never surface to the next person to sign in. If that bulk clear fails part-way it retries each key individually and leaves a flag that forces a full sweep on the next app start.
For agents
- Draft persistence for team chat is
src/renderer/src/features/team-chat/data/draft-persistence.ts; the Gmail compose surface is anchored bysrc/renderer/src/features/gmail/gmail-compose-draft-persistence.ui-anchors.ts. - Durability is one layer, not three:
localStorage, keyedteam-chat-drafts:<orgId>, with no Firestore and no database copy.SAVE_DEBOUNCE_MS = 400;DRAFT_TTL_MS = 30 days;flushDraftsNow()is the teardown path (pagehide/beforeunload);clearAllDrafts()is the logout cascade, withteam-chat-drafts-clear-failedas the startup-retry flag (F013). - The stored value is a
Record<string, string>— text only. Attachments and pasted images are uploaded separately and are not part of the persisted draft.
Related
- crash-recovery.md — recovering after the app crashes.
- crash-recovery-part-2.md — more on crash recovery.
- safe-mode.md — the reduced mode the app can start in after trouble.
Last verified 2026-10-06