# How to Access Application Settings in FluidVoice: Complete Guide to SettingsStore

> Learn how to access application settings in FluidVoice using the SettingsStore. This guide explains how SwiftUI views subscribe to changes and persist data effortlessly.

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

---

**FluidVoice stores all user-configurable data in a thread-safe singleton called `SettingsStore` that conforms to `ObservableObject`, allowing SwiftUI views to subscribe to changes via `@ObservedObject` while automatically persisting values to `UserDefaults`.**

The FluidVoice repository organizes application preferences through a centralized architecture defined in [`Sources/Fluid/Persistence/SettingsStore.swift`](https://github.com/altic-dev/FluidVoice/blob/main/Sources/Fluid/Persistence/SettingsStore.swift). This approach ensures that whether you are building a preference pane, reacting to hotkey changes, or configuring dictation prompts, you access application settings in FluidVoice through a single, consistent API backed by `UserDefaults` and `KeychainService` for sensitive data.

## What is SettingsStore?

**`SettingsStore`** is the central nervous system for FluidVoice configuration. Implemented as a singleton accessible via `SettingsStore.shared`, this class conforms to `ObservableObject` and manages the persistence layer for all user preferences.

The store automatically handles serialization through `UserDefaults` (with `KeychainService` handling secrets), eliminates manual save calls, and broadcasts changes via `objectWillChange.send()` to trigger SwiftUI view updates. Located in [`Sources/Fluid/Persistence/SettingsStore.swift`](https://github.com/altic-dev/FluidVoice/blob/main/Sources/Fluid/Persistence/SettingsStore.swift), it exposes typed properties and helper methods that provide type-safe access to raw preference values.

## How to Access Application Settings in FluidVoice

### Reading Settings

Access any setting by querying the computed property on the shared instance. The store provides typed accessors that abstract away the underlying `UserDefaults` keys.

```swift
import Fluid

// Access the transcription preview character limit
let limit = SettingsStore.shared.transcriptionPreviewCharLimit

// Retrieve the active dictation prompt for a specific slot
let selection = SettingsStore.shared.dictationPromptSelection(for: .primary)

// Check if launch at startup is enabled
let autoLaunch = SettingsStore.shared.launchAtStartupEnabled

```

### Writing Settings

Assign values directly to properties; the store automatically persists changes and notifies observers. This pattern appears throughout [`Sources/Fluid/Views/CommandModeView.swift`](https://github.com/altic-dev/FluidVoice/blob/main/Sources/Fluid/Views/CommandModeView.swift) and other view files.

```swift
// Update the preview limit with bounds checking
let current = SettingsStore.shared.transcriptionPreviewCharLimit
let step = SettingsStore.transcriptionPreviewCharLimitStep
let max = SettingsStore.transcriptionPreviewCharLimitRange.upperBound
SettingsStore.shared.transcriptionPreviewCharLimit = min(current + step, max)

// Configure a hotkey for a specific prompt selection
var config = SettingsStore.shared.dictationPromptConfiguration(for: selection)
config.shortcut = newHotkey
SettingsStore.shared.setDictationPromptConfiguration(config, for: selection)

```

### Observing Changes

Inject the store into SwiftUI views using `@ObservedObject` to ensure the UI reacts to preference mutations. This pattern is demonstrated in [`Sources/Fluid/fluidApp.swift`](https://github.com/altic-dev/FluidVoice/blob/main/Sources/Fluid/fluidApp.swift) where the top-level view maintains a reference to `SettingsStore.shared`.

```swift
import SwiftUI

struct PreviewLimitView: View {
    @ObservedObject private var settings = SettingsStore.shared

    var body: some View {
        Text("Preview limit: \(settings.transcriptionPreviewCharLimit) characters")
            .padding()
    }
}

```

## Common Settings and Properties

The following settings represent the most frequently accessed configuration options within the FluidVoice codebase:

- **`transcriptionPreviewCharLimit`** – Controls the character limit for the transcription preview pane. Accessed in [`Sources/Fluid/Views/NotchContentViews.swift`](https://github.com/altic-dev/FluidVoice/blob/main/Sources/Fluid/Views/NotchContentViews.swift).

- **`dictationPromptSelection(for:)`** – Returns the active prompt selection (default, profile, Private AI, or off) for a given shortcut slot. Used extensively in [`Sources/Fluid/Views/CommandModeView.swift`](https://github.com/altic-dev/FluidVoice/blob/main/Sources/Fluid/Views/CommandModeView.swift).

- **`selectedDictationPromptProfile`** – Identifies the currently chosen dictation prompt profile, if any.

- **`defaultPromptOverride(for:)`** – Retrieves optional user-provided overrides for built-in system prompts (e.g., `.dictate` mode).

- **`launchAtStartupEnabled`** – Boolean indicating whether FluidVoice registers as a macOS login item.

- **`availableModelsByProvider`** – Dictionary of AI models organized by provider, accessed in [`Sources/Fluid/Views/RewriteModeView.swift`](https://github.com/altic-dev/FluidVoice/blob/main/Sources/Fluid/Views/RewriteModeView.swift) to populate model selection interfaces.

## Practical Code Examples

### Observing Settings from a Service

For non-SwiftUI contexts such as background services, subscribe to the `objectWillChange` publisher to react to configuration updates.

```swift
import Combine

class PromptService {
    private var cancellable: AnyCancellable?

    init() {
        cancellable = SettingsStore.shared.objectWillChange.sink { _ in
            self.reloadPrompt()
        }
    }

    private func reloadPrompt() {
        let prompt = SettingsStore.shared.effectiveSystemPrompt(for: .dictate)
        // Pass updated prompt to AI provider...
    }
}

```

### Determining Active Prompt Description

Handle the `DictationPromptSelection` enum to provide user-facing descriptions of the current configuration.

```swift
func activePromptDescription() -> String {
    let selection = SettingsStore.shared.dictationPromptSelection(for: .primary)
    switch selection {
    case .off:
        return "Dictation is turned off"
    case .default:
        return "Using the default system prompt"
    case .privateAI:
        return "Using Private AI prompt"
    case .profile(let id):
        return "Using custom profile \(id)"
    }
}

```

### Accessing Visualizer Settings

The [`NotchContentViews.swift`](https://github.com/altic-dev/FluidVoice/blob/main/NotchContentViews.swift) file demonstrates accessing audio visualization thresholds.

```swift
// From Sources/Fluid/Views/NotchContentViews.swift
let noiseThreshold = SettingsStore.shared.visualizerNoiseThreshold

```

## Summary

- **FluidVoice** centralizes all application settings in `SettingsStore`, a thread-safe singleton defined in [`Sources/Fluid/Persistence/SettingsStore.swift`](https://github.com/altic-dev/FluidVoice/blob/main/Sources/Fluid/Persistence/SettingsStore.swift).
- **Access** settings through `SettingsStore.shared` using typed properties that abstract `UserDefaults` persistence.
- **Observe** changes by injecting the store as an `@ObservedObject` in SwiftUI views or subscribing to `objectWillChange` in Combine-based services.
- **Modify** values by direct assignment; the store automatically triggers persistence and UI updates without manual save calls.
- **Secure** sensitive data through internal `KeychainService` integration while standard preferences use `UserDefaults`.

## Frequently Asked Questions

### Where are FluidVoice settings physically stored?

Settings are persisted to `UserDefaults` standard storage, with sensitive credentials managed by the internal `KeychainService` class. You never need to call `synchronize()` or perform manual writes; the `SettingsStore` handles persistence automatically when you modify any property.

### How do I observe settings changes in SwiftUI?

Inject `SettingsStore.shared` as an `@ObservedObject` in your view struct. Because the store conforms to `ObservableObject` and calls `objectWillChange.send()` on every mutation, any view containing `@ObservedObject var settings = SettingsStore.shared` will automatically redraw when settings change, as implemented in [`Sources/Fluid/fluidApp.swift`](https://github.com/altic-dev/FluidVoice/blob/main/Sources/Fluid/fluidApp.swift).

### Is SettingsStore thread-safe?

Yes. The singleton instance is designed to be accessed from any thread or queue safely. While SwiftUI mutations must occur on the main thread by architectural requirement, the underlying `UserDefaults` and `KeychainService` operations are thread-safe, allowing background services to read settings without race conditions.

### How do I access settings from a non-SwiftUI context?

Use the Combine framework to subscribe to `SettingsStore.shared.objectWillChange`. This publisher emits whenever any setting changes, allowing services, view models, or background tasks to react to configuration updates without maintaining a direct view reference, as shown in the `PromptService` example above.