What Are the Key Services in FluidVoice? A Complete Guide to the Architecture

FluidVoice is built around 15 core modular services located in Sources/Fluid/Services/ that handle speech recognition, speaker diarization, media control, AI integration, and system automation, all accessed through a centralized AppServices registry.

altic-dev/FluidVoice is a macOS voice dictation and meeting transcription application. Its clean service-oriented architecture separates concerns into isolated, testable components. This guide examines each key service, its responsibilities, and how they interact to power the app's speech-driven workflow.

ASRService: The Core Speech Recognition Engine

ASRService.swift implements the primary Automatic Speech Recognition pipeline. It converts microphone audio into live text, applies punctuation, and formats output using custom dictionaries.

The service provides the startTranscribing() method with a callback-based result handler:

let asr = AppServices.shared.asrService
asr.startTranscribing { result in
    switch result {
    case .transcript(let text):
        print("Live text: \(text)")
    case .error(let err):
        AppServices.shared.notificationService.showError(err.localizedDescription)
    }
}

ASRService is consumed by MeetingTranscriptionService, DictationPostProcessingService, and RewriteModeService. It receives its audio input from AudioDeviceService, which manages input device enumeration and selection.

MediaPlaybackService: System Media Integration

MediaPlaybackService.swift controls audio/video playback through macOS system APIs. It handles play, pause, seek operations and queries "now-playing" state to synchronize the UI with the active media player.

This service coordinates with ASRService to pause transcription when playback begins, preventing the app's own transcription from interfering with media audio:

let media = AppServices.shared.mediaPlaybackService
media.onPlaybackStarted = {
    AppServices.shared.asrService.pause()
    AppServices.shared.notificationService.showInfo("Playback started – transcription paused")
}

SpeakerDiarizationService: Multi-Speaker Detection

SpeakerDiarizationService.swift analyzes transcripts and segments them into speaker-labeled turns. This enables the meeting transcription feature to distinguish between multiple participants.

The service exposes a labelSpeakers(in:) method that returns structured speaker-turn data:

let diarizer = AppServices.shared.speakerDiarizationService
let rawTranscript = "Alice: Hello Bob. Bob: Hi Alice."
let labeled = diarizer.labelSpeakers(in: rawTranscript)
print(labeled)   // → [{speaker: "Alice", text: "Hello Bob."}, {speaker: "Bob", text: "Hi Alice."}]

MeetingTranscriptionService consumes this output to produce final, speaker-tagged meeting records.

TypingService: Text Injection and Clipboard Management

TypingService.swift simulates typing events, writes transient clipboard items, and restores application focus after text insertion. This is the primary mechanism by which FluidVoice injects transcribed or AI-generated text into other applications.

The typeText(_:completion:) method handles the full injection pipeline:

let typing = AppServices.shared.typingService
typing.typeText("This is the corrected sentence.") {
    print("Insertion complete")
}

RewriteModeService and CommandModeService both depend on this service for final text delivery.

CommandModeService: Voice-Driven Command Execution

CommandModeService.swift interprets "/command" style voice inputs and routes them to appropriate backends. It supports OS-level commands, shell execution via TerminalService, and AI-powered actions.

The service relies on ASRService for parsing spoken commands into structured directives. For shell commands, it delegates execution to TerminalService:

// Triggered by "/terminal git status" or similar voice command
AppServices.shared.terminalService.execute("git status") { output in
    // Handle command output
}

RewriteModeService: Pre-Commit Text Editing

RewriteModeService.swift provides a dedicated UI for editing generated dictation before final insertion. It coordinates multiple services to enable the rewrite workflow:

  • Re-transcription: Calls ASRService for alternative interpretations
  • Final insertion: Uses TypingService to commit approved text
  • Status feedback: Triggers NotificationService for progress updates

This service represents a key UX pattern in FluidVoice: the human-in-the-loop verification step between raw speech and final output.

NotificationService: User Feedback System

NotificationService.swift wraps macOS UNUserNotificationCenter APIs to deliver transient alerts. It provides typed convenience methods for common scenarios:

  • showError(_:) for transcription failures
  • showInfo(_:) for status updates like playback state changes
  • Custom notification categories for actionable alerts

Every major service uses this for user-facing feedback, ensuring consistent notification behavior across the application.

MeetingTranscriptionService: High-Level Orchestration

MeetingTranscriptionService.swift acts as the primary coordinator for the "record meeting" feature. It orchestrates:

  1. ASRService for real-time speech-to-text
  2. SpeakerDiarizationService for speaker labeling
  3. DictationPostProcessingService for formatting and punctuation

This service demonstrates the compositional pattern in FluidVoice's architecture—complex features emerge from service coordination rather than monolithic implementation.

DictionaryTransferService: Vocabulary Management

DictionaryTransferService.swift handles import and export of custom dictionary data in JSON format. It manages migration from legacy backup formats and provides the persistence layer for ASRService's custom vocabulary feature.

The service serves both programmatic access (for ASRService) and UI-driven settings management.

PrivateAIIntegrationService: Local and Remote LLM Support

PrivateAIIntegrationService.swift connects FluidVoice to private Large Language Model endpoints, including Ollama and OpenRouter configurations. This enables on-device or self-hosted inference for users with privacy requirements.

The sendPrompt(_:completion:) method supports async LLM queries:

let ai = AppServices.shared.privateAIIntegrationService
await ai.sendPrompt("Summarize the meeting notes.") { response in
    AppServices.shared.notificationService.showInfo(response)
}

Generated responses flow back into RewriteModeService and CommandModeService for user review or direct execution.

AudioDeviceService: Input Hardware Management

AudioDeviceService.swift enumerates available audio input devices, monitors hot-plug events, and maintains the active device selection. It supplies the selected device identifier to ASRService for stream initialization.

ClipboardService: Secure System Clipboard Access

ClipboardService.swift provides sandbox-compliant read/write access to the macOS pasteboard. It respects security constraints and privacy settings that would block raw NSPasteboard access in certain contexts.

Both TypingService and UI components use this for copy/paste operations.

TerminalService: Shell Command Execution

TerminalService.swift executes short-lived shell commands and returns structured output. It powers the "run command" feature in CommandModeService, enabling voice-activated workflow automation.

Commands execute with timeout constraints and output sanitization for safe integration with the broader application.

AppServices: Central Service Registry

AppServices.swift implements the singleton registry pattern that makes the service layer accessible throughout the application. It lazily instantiates each service and provides type-safe accessors:

AppServices.shared.asrService
AppServices.shared.mediaPlaybackService
AppServices.shared.privateAIIntegrationService
// ... etc

This design eliminates circular dependencies and simplifies testing through mock injection.

TextSelectionService: Frontmost Application Integration

TextSelectionService.swift tracks the current text selection in the active application using macOS accessibility APIs. It enables RewriteModeService and CommandModeService to replace or insert text at the precise cursor position.

The service works closely with TypingService to ensure coordinated selection-aware text injection.

Summary

Frequently Asked Questions

What audio sources does FluidVoice support?

AudioDeviceService enumerates all Core Audio input devices including built-in microphones, USB audio interfaces, and Bluetooth headsets. Users select the active device through the settings UI, and ASRService initializes its audio stream from that selection. The service monitors AVAudioSession notifications for hot-plug events.

Can FluidVoice run without cloud AI services?

Yes. PrivateAIIntegrationService supports fully local inference through Ollama for on-device operation. Users can configure private endpoints including local network hosts, eliminating dependency on cloud speech recognition or LLM providers. The ASRService architecture also allows backend swapping for alternative recognition engines.

How does FluidVoice insert text into other applications?

TypingService uses macOS accessibility and event simulation APIs to inject text at the current cursor position. For applications where direct typing is unreliable, it falls back to ClipboardService for pasteboard-based insertion with automatic focus restoration. TextSelectionService queries the frontmost application's selection state to ensure precise placement.

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 →