How to Access FluidVoice Settings: The Complete Developer Guide

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 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. 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. 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

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.

// 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:

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 — 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 and 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

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
  • 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.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →