In the previous chapter, Settings Persistence & Change Detection, we learned how to save the user's preference (turning Voice Mode ON).
However, we have a problem. What if a user turns Voice Mode ON, but they don't have a microphone plugged in? Or what if they are missing the necessary audio software?
If we simply flip the switch to "ON" without checking, the application might crash or throw scary errors later.
We need to implement Environment Pre-flight Validation.
Think of your application like an airplane. Before a pilot takes off, they don't just throttle up. They go through a strict checklist:
If any of these checks fail, the plane stays on the ground.
In our CLI, before we allow the user to enable Voice Mode, we must check:
We are going to modify the logic inside our voice.ts command. instead of immediately saving voiceEnabled: true, we will run a gauntlet of checks.
First, voice mode uses cloud AI models, so we need to ensure the user is allowed to use it.
// voice.ts
// 1. Check if the feature is globally enabled
if (!isVoiceModeEnabled()) {
return { type: 'text', value: 'Voice mode is not available.' }
}
// 2. Check if the user is signed in
if (!isAnthropicAuthEnabled()) {
return {
type: 'text',
value: 'Voice mode requires an account. Run /login.'
}
}
false, we return a text message immediately. The code stops here. The settings are not updated.
Next, we check if the computer actually has a recording device. Note that we use await import here. We don't want to load the microphone library unless we passed the Auth check (Lazy Loading!).
// Load the check service dynamically
const { checkRecordingAvailability } = await import('../../services/voice.js')
// Run the hardware check
const recording = await checkRecordingAvailability()
// If no microphone, stop here.
if (!recording.available) {
return {
type: 'text',
value: 'No microphone found in this environment.'
}
}
Our system relies on a tool called SoX (Sound eXchange) to handle audio streams. If the user hasn't installed it, we need to tell them.
const { checkVoiceDependencies } = await import('../../services/voice.js')
const deps = await checkVoiceDependencies()
if (!deps.available) {
return {
type: 'text',
value: 'No audio recording tool found. Please install SoX.'
}
}
Error: command not found, we give a helpful message guiding the user to install the missing tool.Finally, modern operating systems (macOS, Windows) require users to explicitly grant microphone permission.
const { requestMicrophonePermission } = await import('../../services/voice.js')
// This triggers the system popup asking "Allow access to Microphone?"
const hasAccess = await requestMicrophonePermission()
if (!hasAccess) {
return {
type: 'text',
value: 'Microphone access denied. Check System Privacy Settings.'
}
}
Only if all previous checks pass do we finally allow the setting to be changed.
// All systems go!
updateSettingsForSource('userSettings', { voiceEnabled: true })
settingsChangeDetector.notifyChange('userSettings')
return { type: 'text', value: 'Voice mode enabled!' }
This pattern creates a "Funnel." Many users might try to enter, but only those with a valid environment make it through to the updateSettings call.
Here is the actual implementation logic from the source code, simplified slightly for clarity. Notice how it combines everything we discussed.
// voice.ts (Logic Flow)
// ... imports ...
export const call = async () => {
// 1. Initial Gatekeeping (Kill-switch & Auth)
if (!isVoiceModeEnabled()) {
// ... return error message
}
// 2. Hardware Check
const { checkRecordingAvailability } = await import('../../services/voice.js')
const recording = await checkRecordingAvailability()
if (!recording.available) {
return { type: 'text', value: recording.reason }
}
// 3. Software Dependency Check
const { checkVoiceDependencies } = await import('../../services/voice.js')
const deps = await checkVoiceDependencies()
if (!deps.available) {
return { type: 'text', value: 'Install audio tools...' }
}
// 4. OS Permission Check
// We probe the mic now so the OS dialog appears immediately
const { requestMicrophonePermission } = await import('../../services/voice.js')
if (!(await requestMicrophonePermission())) {
return { type: 'text', value: 'Microphone access is denied...' }
}
// 5. Success - Save Settings (From Chapter 2)
updateSettingsForSource('userSettings', { voiceEnabled: true })
settingsChangeDetector.notifyChange('userSettings')
return { type: 'text', value: 'Voice mode enabled.' }
}
In this chapter, you learned Environment Pre-flight Validation.
Now that the user has successfully enabled voice mode, the system needs to tell them how to use it (e.g., "Hold Space to talk").
Next: Voice Configuration Feedback
Generated by Code IQ