How FluidVoice Handles and Stores User Data: A Local-First Architecture Guide
FluidVoice stores all user data locally on macOS using UserDefaults for settings and transcription history, Keychain for API keys, and the Application Support directory for audio files, ensuring voice data never leaves the device unless explicitly sent to an optional cloud AI provider.
FluidVoice is a local-first dictation application that prioritizes user privacy by keeping sensitive voice data and transcriptions on-device. Understanding how FluidVoice handles and stores user data reveals a privacy-centric architecture built on standard macOS security frameworks. This analysis examines the specific storage mechanisms, file paths, and data flows implemented in the altic-dev/FluidVoice repository.
Local-First Privacy Architecture
FluidVoice operates on a strict local-first principle: user-generated content remains on the Mac unless the user explicitly opts into a cloud AI provider. The application leverages macOS-native storage solutions—including UserDefaults, Keychain, and sandboxed file directories—to ensure data persistence without compromising security boundaries.
Application Settings and Preferences Storage
All UI-tweakable values, hot-key bindings, and overlay configurations are managed through a centralized persistence layer.
UserDefaults Implementation in SettingsStore
The SettingsStore.swift file implements a singleton pattern that wraps UserDefaults.standard to persist configuration data. As implemented in Sources/Fluid/Persistence/SettingsStore.swift (lines 14-19), the store initializes with a private reference to standard defaults:
private let defaults = UserDefaults.standard
This singleton handles all preference mutations, writing simple key-value pairs that immediately synchronize across the app's UI through NotificationCenter observers listening for UserDefaults.didChangeNotification.
Legacy Key Migration
The store includes migration logic to normalize legacy preference keys and values during startup, ensuring seamless updates without data loss when users upgrade to newer versions of FluidVoice.
Secure API Key Management with Keychain
When users enable optional cloud AI providers, authentication credentials receive hardware-backed protection. The SettingsStore references KeychainService.shared (line 19 in SettingsStore.swift) to read and write API keys exclusively through the macOS Keychain.
Unlike settings stored in UserDefaults, API keys are never written to plaintext disk storage or exposed in source code. The KeychainService.swift file (located at Sources/Fluid/Services/KeychainService.swift) provides the cryptographic wrapper ensuring these credentials remain inaccessible to other applications or system processes.
Transcription History Persistence
FluidVoice maintains a complete record of dictation sessions, including raw text, processed output, timestamps, and application context.
JSON-Encoded UserDefaults Storage
The TranscriptionHistoryStore.swift file persists transcription entries as a JSON-encoded array under the key "TranscriptionHistoryEntries" (lines 51-55):
// From Sources/Fluid/Persistence/TranscriptionHistoryStore.swift
private let historyKey = "TranscriptionHistoryEntries"
func saveEntries(_ entries: [TranscriptionHistoryEntry]) {
if let encoded = try? JSONEncoder().encode(entries) {
UserDefaults.standard.set(encoded, forKey: historyKey)
}
}
Each TranscriptionHistoryEntry object contains the raw and processed transcription text, originating application/window information, and optional AI-processing metadata including model names and error messages.
Optional Audio File Storage
For users who enable audio history, raw recordings are stored outside of UserDefaults to prevent memory bloat. Each entry may carry a DictationAudioMetadata reference (lines 27-28 in TranscriptionHistoryStore.swift) pointing to files saved in the app's sandboxed support directory:
~/Library/Application Support/FluidVoice/
This separation ensures that lightweight text metadata resides in fast-access UserDefaults while bulky audio files remain in the filesystem, both protected by macOS sandboxing restrictions.
On-Device AI Model Storage
The optional "Fluid Intelligence" on-device AI model downloads entirely to the user's local machine. Model files reside in ~/Library/Application Support/FluidVoice, operating completely offline without external server communication unless the user explicitly enables a cloud provider for processing.
Analytics and Privacy Controls
FluidVoice implements opt-in analytics that respect strict user consent boundaries. According to the README documentation (lines 63-78), the system collects only high-level, non-identifying information such as app version, macOS version, feature-usage flags, and usage ranges.
The AnalyticsService.swift file (Sources/Fluid/Analytics/AnalyticsService.swift) manages these anonymous counters stored locally in UserDefaults. When users consent via Settings → Share Anonymous Analytics, the service transmits aggregated statistics—but never voice data, raw audio, or transcribed text—to telemetry endpoints.
Data Flow Lifecycle
Understanding how FluidVoice handles and stores user data requires examining the runtime data flow:
- Startup:
SettingsStore.sharedloads preferences from UserDefaults and executes legacy key migrations. - Runtime Changes: User modifications trigger immediate UserDefaults writes, broadcasting change notifications to update the UI.
- Dictation Sessions: Speech processing generates
TranscriptionHistoryEntryobjects; if AI post-processing occurs, model metadata attaches to the entry before JSON serialization to UserDefaults. - Audio Persistence: Enabled audio history writes raw files to Application Support while storing lightweight metadata references in the transcription entry.
- Analytics Transmission: Periodic aggregation of local counters occurs only when explicit user consent exists in settings.
Summary
- FluidVoice employs a local-first architecture where user data remains on-device by default according to the altic-dev/FluidVoice source code.
- UserDefaults stores settings and JSON-encoded transcription history in
SettingsStore.swiftandTranscriptionHistoryStore.swift. - Keychain protects cloud provider API keys via
KeychainService, never persisting credentials to plaintext disk storage. - Audio files reside in the sandboxed
~/Library/Application Support/FluidVoicedirectory when history is enabled. - Analytics operate on an opt-in basis, transmitting only anonymous aggregated counters without voice or text content.
- All storage mechanisms leverage native macOS security boundaries and application sandboxing.
Frequently Asked Questions
Does FluidVoice send my voice recordings to the cloud?
No. FluidVoice processes audio locally using on-device models stored in your Application Support directory. Voice data only leaves your Mac if you explicitly enable a third-party cloud AI provider and initiate processing. Raw audio files remain in ~/Library/Application Support/FluidVoice unless you delete them or disable audio history in settings.
Where does FluidVoice store my transcription history?
Transcription history is stored as JSON-encoded data in UserDefaults under the key "TranscriptionHistoryEntries", managed by TranscriptionHistoryStore.swift. The actual text content, timestamps, and application context persist on your device only, with optional audio files stored separately in the sandboxed Application Support folder.
How secure are my API keys in FluidVoice?
API keys for optional cloud providers are stored exclusively in the macOS Keychain through KeychainService.swift. They are never written to UserDefaults, plaintext files, or exposed in source code, leveraging Apple's hardware-backed encryption for credential protection against other applications or system processes.
Can I completely disable data collection in FluidVoice?
Yes. FluidVoice requires explicit opt-in for analytics collection via Settings → Share Anonymous Analytics. You can disable this at any time, and the application does not collect telemetry by default. No voice data, raw audio, or transcribed text is ever transmitted for analytics purposes regardless of your settings.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →