Agent skill

vocal

Speak text aloud (TTS) and transcribe speech (STT).

17 files · 188.4 KB · Source ↗ · Raw SKILL.md · Markdown directory · Download skill.tgz

Copy the prompt. Paste it into your agent.

Verify the bytes and inspect the files before trusting a skill. A matching hash is not a safety review.

Read the install prompt
Full inline prompt for offline use

Includes SKILL.md. Supporting files still require a download.

Install from a shell

Run this in a terminal. It downloads the pinned archive, checks its SHA-256 digest, and extracts it into ~/.claude/skills, where Claude Code loads skills. For Codex and other agents that read ~/.agents/skills, edit the SKILLS_DIR line. If the skill is already installed, the command stops and changes nothing.

Vocal

Speak text aloud and transcribe speech with local and cloud providers. User-invocable only (/vocal) — audio is a side-effect surface, not something to auto-trigger on.

Prerequisites: macOS (say, afplay), uv, Apple Silicon for local STT (mlx-whisper), and an ELEVENLABS_API_KEY for the cloud providers.

Every scripts/… and tests/… path below is relative to this skill's base directory — resolve them against it before running.

Usage

/vocal — turn-based vocal loop

Runs an ask-aloud / listen / respond / keep-listening cycle using the vocal-listener background agent.

/vocal What should we work on next?

Optional inline config:

Loop behavior
  1. Parse inline config from the command text:

    • stt=local|elevenlabs (default: local)
    • tts=local|elevenlabs (default: match stt)
    • duration=<seconds> (default: 8)
    • Remaining text becomes the first spoken prompt.
  2. Validate selected providers before starting (run only the checks needed):

    uv run scripts/stt_local.py --check
    uv run scripts/stt_elevenlabs.py --check
    uv run scripts/tts_local.py --check
    uv run scripts/tts_elevenlabs.py --check
    
  3. Launch the listener. Create or reuse a team named vocal and launch vocal-listener as a background task with config:

    stt_provider=<local|elevenlabs>
    duration_seconds=<duration>
    continue_token=keep-listening
    stop_token=stop-listening
    
  4. Speak the first prompt aloud (if provided). If none is provided, speak: Vocal mode active. I'm listening.

  5. For every listener message starting with [voice-input]:

    • Treat the transcript as the user turn.
    • Produce a concise assistant response.
    • Speak the response with the selected TTS provider.
    • Send keep-listening to the listener agent.
  6. Stop conditions:

    • Transcript asks to stop (e.g. "stop vocal mode", "goodbye", "exit vocal") — speak confirmation and send stop-listening.
    • Listener reports [voice-error] — surface the error and pause vocal mode.

Turn-based, not full-duplex realtime. Each listen cycle is a separate background agent turn. Keep spoken responses short unless the user asks for detail.

Web tuning console

uv run --script scripts/web_console.py

Open http://127.0.0.1:8765 to tune the skill from a local browser.

The console supports:

Options:

# Choose a port
uv run --script scripts/web_console.py --port 8799

# Use a private preference directory outside the skill checkout
VOCAL_DATA_DIR=~/Library/Application\ Support/vocal-skill \
  uv run --script scripts/web_console.py

Local TTS (macOS say)

uv run --script scripts/tts_local.py --text "Hello Michael"

Examples:

# Save audio to file
uv run --script scripts/tts_local.py \
  --text "Build succeeded" \
  --voice Alex \
  --rate 200 \
  --output /tmp/build.aiff

# List macOS voices
uv run --script scripts/tts_local.py --list-voices

Local STT (mlx-whisper, Apple Silicon)

# Record microphone for 5 seconds and transcribe
uv run --script scripts/stt_local.py --duration 5

# Transcribe an existing file
uv run --script scripts/stt_local.py --file ./meeting.wav

# List input devices
uv run --script scripts/stt_local.py --list-devices

# Use a specific device
uv run --script scripts/stt_local.py --duration 5 --device 1

ElevenLabs TTS (cloud)

uv run --script scripts/tts_elevenlabs.py \
  --text "Hello Michael" \
  --voice George

Examples:

# Save and play the generated mp3
uv run --script scripts/tts_elevenlabs.py \
  --text "Deployment complete" \
  --model eleven_turbo_v2_5 \
  --output /tmp/deploy.mp3 \
  --play

ElevenLabs STT (Scribe v2)

# Record microphone for 5 seconds and transcribe
uv run --script scripts/stt_elevenlabs.py --duration 5

# Transcribe an existing audio file
uv run --script scripts/stt_elevenlabs.py --file ./call.wav

# List input devices
uv run --script scripts/stt_elevenlabs.py --list-devices

# Use a specific device
uv run --script scripts/stt_elevenlabs.py --duration 5 --device 1

Provider checks

uv run --script scripts/tts_local.py --check
uv run --script scripts/stt_local.py --check
uv run --script scripts/tts_elevenlabs.py --check
uv run --script scripts/stt_elevenlabs.py --check

Provider Comparison

Provider Mode Latency Quality Cost
tts_local.py Local Low Good Free
stt_local.py Local Medium (first run downloads model) Good Free
tts_elevenlabs.py Cloud Very low with flash model Very high Paid API
stt_elevenlabs.py Cloud Low Very high Paid API

Environment Variables

Variable Required Used by
ELEVENLABS_API_KEY Yes (cloud only) tts_elevenlabs.py, stt_elevenlabs.py
ELEVEN_LABS_API_KEY Accepted alias tts_elevenlabs.py, stt_elevenlabs.py

Set via ~/.env or shell export.

Recommended local setup:

# Preferred name
ELEVENLABS_API_KEY=your-key-here

# Accepted legacy alias
ELEVEN_LABS_API_KEY=your-key-here

Put one of those lines in ~/.env, then restart web_console.py. The vocal scripts load ~/.env automatically before checking the process environment.

Troubleshooting

Silent TTS despite exit 0

say and afplay reach the speakers only from the user's Aqua (GUI) launchd session. From a Background session — tmux servers started by hooks or automation, daemons — they exit 0 instantly, speak nothing, and say -o renders near-empty files.

Microphone capture from Background sessions is untested.

Getting an ElevenLabs API key

  1. Open https://elevenlabs.io/app/settings/api-keys
  2. Create a key
  3. Export it:
export ELEVENLABS_API_KEY=your-key-here

macOS microphone permissions

If transcription fails with permission errors:

  1. Open System Settings -> Privacy & Security -> Microphone
  2. Allow Terminal (or your Claude host app)
  3. Re-run the command

Common issues

Self-Validation

Run fast provider checks:

uv run --script tests/test_voice.py

Run file-based ask/listen/respond loop (no microphone required):

uv run --script tests/test_voice_loop.py

Include cloud loop validation (requires ElevenLabs key):

uv run --script tests/test_voice_loop.py --cloud

Run web console helper tests:

uv run --script tests/test_web_console.py

Run browser validation for the web console:

# Starts an isolated console on a free port and validates desktop/mobile flows
uv run --script tests/test_web_console_playwright.py

# Validate a console you already have open
uv run --script tests/test_web_console_playwright.py \
  --url http://127.0.0.1:8765

# Include the ElevenLabs TTS UI path (uses API credits)
uv run --script tests/test_web_console_playwright.py \
  --url http://127.0.0.1:8765 \
  --cloud

# Watch the test in a real browser window
uv run --script tests/test_web_console_playwright.py \
  --url http://127.0.0.1:8765 \
  --headed \
  --slow-mo 100

Fixture files for loop validation:

References

Files

17 files · 188.4 KB