# How to Access FluidVoice Settings: The Complete Developer Guide

> Access FluidVoice settings easily. Learn how FluidVoice stores, persists, and updates its settings for seamless developer integration in your macOS apps. Get the complete guide now.

- Repository: [ALTIC/FluidVoice](https://github.com/altic-dev/FluidVoice)
- Tags: how-to-guide
- Published: 2026-08-14

---

**FluidVoice settings are stored in the `SettingsStore` singleton and persisted via `UserDefaults` and the macOS keychain, with all UI views binding to `SettingsStore.shared` as an `ObservableObject` for automatic SwiftUI updates.**

The [FluidVoice](https://github.com/altic-dev/FluidVoice) macOS app centralizes every user preference—from microphone selection to AI prompt routing—inside a single observable persistence layer. Whether you're building extensions, debugging behavior, or scripting configuration changes, understanding how to access FluidVoice settings programmatically unlocks the full surface area of the app's customization system.

## Where FluidVoice Settings Are Stored

FluidVoice uses a dual-storage architecture that separates public preferences from sensitive credentials.

### UserDefaults for Standard Preferences

Every non-sensitive setting lives in `UserDefaults` under keys defined in [`Sources/Fluid/Persistence/SettingsStore.swift`](https://github.com/altic-dev/FluidVoice/blob/main/Sources/Fluid/Persistence/SettingsStore.swift). The `SettingsStore` class exposes these as type-safe properties that automatically sync with the underlying storage.

### Keychain for Secret Values

API keys and other secrets are protected by the macOS keychain via [`KeychainService.swift`](https://github.com/altic-dev/FluidVoice/blob/main/KeychainService.swift). This separation ensures that credentials never leak into unencrypted backups or logs.

## Accessing Settings Programmatically

The `SettingsStore` follows the singleton pattern. Import the `Fluid` module and reference `SettingsStore.shared` to read or modify any preference.

### Reading Current Settings

```swift
import Fluid

// Access the singleton
let store = SettingsStore.shared

// Read microphone configuration
let microphoneMode = store.microphoneSelectionMode
let preferredDevice = store.preferredInputDeviceUID

// Read prompt selections
let dictationPromptID = store.selectedDictationPromptID
let editPromptID = store.selectedEditPromptID

// Read launch behavior
let launchesAtStartup = store.launchAtStartupEnabled

```

All read operations return the cached in-memory value. There's no async overhead because `SettingsStore` maintains local state and writes to persistence on a background queue.

### Modifying Settings

Write operations trigger `objectWillChange.send()`, causing any bound SwiftUI view to refresh automatically.

```swift
// Switch to manual microphone selection
SettingsStore.shared.microphoneSelectionMode = .manual
SettingsStore.shared.preferredInputDeviceUID = "studio-mic-uuid"

// Enable launch at startup
SettingsStore.shared.launchAtStartupEnabled = true

// Set a custom dictation prompt profile
let customProfileID = "my-custom-profile-uuid"
SettingsStore.shared.setDictationPromptSelection(.profile(customProfileID))

// Revert to default prompt
SettingsStore.shared.setDictationPromptSelection(.default)

```

## Key Settings and Their Properties

| Setting | Property / Method | Description |
|--------|-------------------|-------------|
| **Microphone selection** | `microphoneSelectionMode`, `preferredInputDeviceUID` | `system` uses the OS default; `manual` uses a specific device |
| **Dictation prompt** | `selectedDictationPromptID`, `dictationPromptSelection(for:)` | Default, custom profile, or disabled per context |
| **Edit prompt** | `selectedEditPromptID` | Prompt profile used for text rewriting |
| **Launch at startup** | `launchAtStartupEnabled` | Controls login item registration |
| **Private AI token limit** | `privateAIContextTokenLimit` | Context window size for on-device inference |

## Prompt Routing and Context-Aware Selection

FluidVoice supports context-dependent prompt selection through `SettingsStore+PromptRouting.swift`. The method `dictationPromptDisplayName(for:appBundleID:)` resolves which prompt actually applies given the current app and mode:

```swift
import Fluid

let store = SettingsStore.shared

// Query the effective prompt for primary dictation mode
let displayName = store.dictationPromptDisplayName(
    for: .primary,
    appBundleID: "com.apple.Safari"
)
print("Active prompt:", displayName)

```

This routing system allows per-app prompt bindings while falling back to global defaults—useful for tailoring AI behavior to specific workflows.

## Settings Extension Files

The codebase splits `SettingsStore` functionality across focused extensions:

- **[`SettingsStore.swift`](https://github.com/altic-dev/FluidVoice/blob/main/SettingsStore.swift)** — Core singleton, `UserDefaults` keys, and base persistence logic
- **`SettingsStore+CommandMode.swift`** — Secondary dictation shortcuts and command-mode keybindings
- **`SettingsStore+LaunchAtStartup.swift`** — Login item management via `SMLoginItemSetEnabled`
- **`SettingsStore+PromptRouting.swift`** — Context-aware prompt resolution
- **`SettingsStore+NemotronLanguage.swift`** — Private AI backend selection (MLX vs. llama.cpp)

Each extension adds computed properties and methods to the base singleton without cluttering the main implementation.

## UI Binding Architecture

All settings screens bind directly to `SettingsStore.shared`. For example, [`RewriteModeView.swift`](https://github.com/altic-dev/FluidVoice/blob/main/RewriteModeView.swift) and [`CommandModeView.swift`](https://github.com/altic-dev/FluidVoice/blob/main/CommandModeView.swift) use `@ObservedObject var settings = SettingsStore.shared`, ensuring immediate UI feedback when any property changes.

This design means you can modify settings from any source—UI, background service, or external script—and all observers stay synchronized.

## Complete Configuration Script Example

```swift
import Fluid

func configureVoiceProfile() {
    let store = SettingsStore.shared
    
    // Microphone: use specific studio hardware
    store.microphoneSelectionMode = .manual
    store.preferredInputDeviceUID = "StudioMicUID123"
    
    // Dictation: custom profile for technical writing
    store.setDictationPromptSelection(.profile("tech-writing-v2"))
    
    // Edit mode: default prompt for general rewriting
    store.selectedEditPromptID = "default"
    
    // Startup: enable automatic launch
    store.launchAtStartupEnabled = true
    
    // Private AI: limit context to 4096 tokens
    store.privateAIContextTokenLimit = 4096
    
    print("FluidVoice configured: microphone=\(store.preferredInputDeviceUID ?? "nil"), prompt=\(store.selectedDictationPromptID ?? "nil")")
}

configureVoiceProfile()

```

## Summary

- **FluidVoice settings** live in the `SettingsStore` singleton at [`Sources/Fluid/Persistence/SettingsStore.swift`](https://github.com/altic-dev/FluidVoice/blob/main/Sources/Fluid/Persistence/SettingsStore.swift)
- **Persistence layer**: `UserDefaults` for preferences, `KeychainService` for secrets
- **UI synchronization**: SwiftUI `ObservableObject` pattern with automatic `objectWillChange` propagation
- **Programmatic access**: Import `Fluid`, use `SettingsStore.shared` for reads and writes
- **Extension architecture**: Functionality split across `SettingsStore+*.swift` files for maintainability

## Frequently Asked Questions

### How do I access FluidVoice settings from a command line script?

Import the `Fluid` framework in a Swift script or REPL, then reference `SettingsStore.shared`. The singleton is globally accessible without launching the full app UI, though some features (like microphone enumeration) require the audio subsystem to be running.

### Where are FluidVoice preferences stored on disk?

Standard preferences serialize to `~/Library/Preferences/com.altic.FluidVoice.plist` via `UserDefaults`. Secrets including API keys reside in the macOS keychain. The `SettingsStore` abstracts both locations so you interact with properties, not file paths.

### Why don't my programmatic setting changes appear in the UI immediately?

They should—`SettingsStore` emits `objectWillChange.send()` on every write. If updates lag, verify you're modifying `SettingsStore.shared` (not a copy) and that your view observes the object correctly with `@ObservedObject` or `@StateObject`.

### How do I reset all FluidVoice settings to defaults?

There's no single reset method in the current API. Iterate through relevant properties and assign their default values, or delete the app's `UserDefaults` domain and keychain entries programmatically. The `setDictationPromptSelection(.default)` pattern shows per-category reset behavior.