Swabble Wake-Word Daemon
Relevant source files
The following files were used as context for generating this wiki page:
Swabble is a Swift-based wake-word hook daemon designed for macOS 26+. It utilizes the Apple Speech.framework for on-device, local-only speech transcription and wake-word detection. The system acts as a bridge between continuous microphone input and external command execution, allowing users to trigger specific "hooks" or scripts using a voice-activated wake word, typically clawd or claude.
The project is split into two primary components: the swabble CLI, which targets macOS 26 for speech analysis, and SwabbleKit, a multi-platform library (supporting iOS 17+ and macOS 15+) that provides utilities for wake-word gating and segment-aware gap detection.
Sources: Swabble/README.md:1-10, Swabble/CHANGELOG.md:1-10
Architecture and Data Flow
The Swabble daemon operates as a background loop that processes audio through a multi-stage pipeline. It captures microphone input, converts it into speech segments, matches these segments against configured wake words, and executes external commands when criteria are met.
Speech Processing Pipeline
The pipeline follows a specific flow:
- Audio Capture:
AVAudioEnginetaps the microphone input. - Conversion: Audio is passed through a
BufferConverterandAnalyzerInput. - Analysis: The
SpeechAnalyzer(utilizingSpeechTranscriber) generates volatile and final transcription results. - Gating: The
WakeWordGateevaluates the text against the configured wake word (defaulting toclawd). - Execution: If the gate passes, a
HookJobis created and processed by theHookExecutor.
Sources: Swabble/README.md:46-50, Swabble/Sources/swabble/Commands/ServeCommand.swift:40-60
System Flow Diagram
The following diagram illustrates the lifecycle of a voice command from microphone capture to hook execution.
The diagram shows the transformation of raw audio into actionable text via the Speech.framework pipeline.
Sources: Swabble/README.md:46-50, Swabble/Sources/swabble/Commands/ServeCommand.swift:42-65
Core Components
ServeCommand
The ServeCommand is the primary entry point for the foreground daemon. It initializes the speech pipeline and listens to an asynchronous stream of transcription segments. It handles the logic for matching the wake word and stripping it from the final command text.
Key logic includes:
- Wake Word Matching: Uses
WakeWordGate.matchesTextOnlyto check if a segment starts with the trigger or its aliases. - Hook Execution: Triggers a
HookExecutoronce a valid command is detected. - Transcript Management: Optionally persists stripped transcripts to the
TranscriptsStore.
Sources: Swabble/Sources/swabble/Commands/ServeCommand.swift:25-70
Wake-Word Gating (SwabbleKit)
The gating mechanism is responsible for determining if the user has spoken the wake word before a command. It supports two modes:
- Text-Only: Simple prefix matching against the transcript.
- Segment-Aware: Uses
WakeWordSegmentdata to ensure there is a sufficient temporal gap between the wake word and the command, preventing false triggers.
Sources: apps/macos/Tests/ClawdbotIPCTests/VoiceWakeTesterTests.swift:1-30, apps/macos/Sources/Clawdbot/VoiceWakeTextUtils.swift:33-45
Configuration
Swabble is configured via a JSON file located at ~/.config/swabble/config.json. This file defines audio parameters, wake-word triggers, and the hook command to be executed.
| Category | Option | Default Value | Description |
|---|---|---|---|
| Wake | word | "clawd" | The primary wake word trigger. |
| Wake | aliases | ["claude"] | Alternative triggers for the gate. |
| Hook | command | "" | The path to the executable or script to run. |
| Hook | cooldownSeconds | 1.0 | Minimum time between consecutive hook executions. |
| Hook | minCharacters | 24 | Minimum length of the stripped command text. |
| Audio | sampleRate | 16000 | Sampling rate for audio analysis. |
Sources: Swabble/Sources/SwabbleCore/Config/Config.swift:5-45, Swabble/README.md:61-80
Hook Execution Protocol
When a voice command passes the WakeWordGate, Swabble executes the configured hook. The execution environment is populated with specific metadata:
- Command Invocation: The system runs
<command> <args...> "<prefix><text>". - Environment Variables:
SWABBLE_TEXT: The transcript with the wake word removed.SWABBLE_PREFIX: The rendered prefix (e.g., including hostname substitution).- Custom variables defined in
hook.env.
Sources: Swabble/README.md:83-90, Swabble/Sources/swabble/Commands/ServeCommand.swift:55-60
Execution Sequence
The sequence shows how the daemon mediates between transcription results and external process execution.
Sources: Swabble/Sources/swabble/Commands/ServeCommand.swift:45-65, apps/macos/Sources/Clawdbot/VoiceWakeTextUtils.swift:33-45
Voice Wake Utilities
Swabble includes utility functions in VoiceWakeTextUtils to normalize transcription tokens and validate command structures.
- Normalization: Tokens are trimmed of whitespace/punctuation and converted to lowercase to improve matching reliability.
- Prefix Validation:
startsWithTriggerensures the transcript specifically begins with one of the configured triggers or aliases before processing the rest as a command.
Sources: apps/macos/Sources/Clawdbot/VoiceWakeTextUtils.swift:10-31
// Example of text normalization used in gating
static func normalizeToken(_ token: String) -> String {
token
.trimmingCharacters(in: self.whitespaceAndPunctuation)
.lowercased()
}
Sources: apps/macos/Sources/Clawdbot/VoiceWakeTextUtils.swift:10-14
Summary
The Swabble Wake-Word Daemon provides a high-performance, privacy-focused solution for voice automation on macOS. By leveraging on-device Speech.framework models and a robust gating architecture in SwabbleKit, it enables reliable "clawd"-activated command hooks without network dependencies. Its modular configuration and environment-based hook protocol allow for deep integration with local developer workflows and automation scripts.