CLI Tool
The TTSBuddy CLI converts text to speech from your terminal. It's a single binary with no dependencies — install it and start generating audio.
Install
Homebrew (macOS/Linux)
brew install ngelik/tap/ttsbuddy
Go
go install github.com/ngelik/ttsbuddy-cli@latest
Binary Download
Download from GitHub Releases and place in your $PATH.
Update
# Homebrew
brew upgrade ngelik/tap/ttsbuddy
# Go
go install github.com/ngelik/ttsbuddy-cli@latest
# Binary: download latest from GitHub Releases and replace in $PATH
# Check your version
ttsbuddy version
Quick Start
# 1. Set your API key (create one at ttsbuddy.com/dashboard → Settings)
ttsbuddy config set key ttsb_your_key_here
# 2. Convert text to speech
ttsbuddy speak "Hello, world!"
# 3. The audio file is saved automatically
# Output: ttsbuddy-20260405-120000-af_heart.mp3
Don't have an API key yet? See the API Keys guide to create one.
Commands
speak
Convert text to speech. This is the main command.
Input modes:
# Inline text
ttsbuddy speak "Hello world"
# From file (.md files auto-preprocessed)
ttsbuddy speak -f article.md
# From stdin
cat notes.txt | ttsbuddy speak -
Output modes:
# Save to specific file
ttsbuddy speak "Hello" -o output.mp3
# Auto-named file in current directory (default)
ttsbuddy speak "Hello"
# JSON response to stdout (for scripting)
ttsbuddy speak "Hello" --json
# Print audio URL without downloading
ttsbuddy speak "Hello" --no-download
# Raw MP3 bytes to stdout (pipe to player)
ttsbuddy speak "Hello" -o - | afplay -
All flags:
| Flag | Description |
|---|---|
-f, --file <path> | Read text from file |
-v, --voice <id> | Voice ID (default: af_heart) |
-s, --speed <n> | Speed 0.5–1.5 (default: 1.0) |
-o, --output <path> | Output file (- for stdout) |
--output-dir <dir> | Directory for auto-named files (default: .) |
--timeout <duration> | Poll timeout (default: 10m, Go duration syntax) |
--raw | Skip markdown preprocessing |
--no-download | Print audio URL instead of downloading |
--idempotency-key <key> | Override auto-generated idempotency key |
Markdown files (.md, .markdown) are automatically preprocessed before sending to the API. Headings, bold/italic markers, link URLs, images, and code blocks are removed for cleaner narration. Link text is preserved. Use --raw to skip this.
voices
List available TTS voices.
# Curated list (always works offline)
ttsbuddy voices
# Full live catalog from API
ttsbuddy voices --all
# JSON output
ttsbuddy voices --json
If --all can't reach the voice catalog, it falls back to the curated list with a warning on stderr.
For fastest generation, use Flash voices: st_f1 (Felicity), st_f2 (Fiona), st_m1 (Marcus), st_m2 (Michael). They generate 5-10x faster than standard voices with excellent quality — ideal for automation and pipelines.
ttsbuddy speak -v st_m1 "Flash voice for speed"
status
Check job status. Read-only — does not download audio. Use speak to generate and download.
# Check a specific job
ttsbuddy status <job_id>
# Check most recent job
ttsbuddy status
# Poll until job completes
ttsbuddy status <job_id> --watch
# JSON output
ttsbuddy status <job_id> --json
| Flag | Description |
|---|---|
--watch | Poll until terminal state or timeout |
--timeout <duration> | Poll timeout for --watch (default: 10m) |
config
Show or set configuration values.
# Show all values
ttsbuddy config
# Get a specific value
ttsbuddy config get voice
# Set values
ttsbuddy config set key ttsb_...
ttsbuddy config set voice bf_emma
ttsbuddy config set speed 0.9
ttsbuddy config set timeout 5m
Valid keys: key, voice, speed, timeout, output_dir, api_url, tts_api_base_url
version
ttsbuddy version
ttsbuddy version --json
ttsbuddy --version
Global Flags
Available on every command:
| Flag | Description |
|---|---|
-k, --key <key> | API key (overrides config and env var) |
--json | JSON output to stdout only, no human output on stderr |
--quiet | Suppress progress output |
Configuration
File: ~/.ttsbuddy/config.json
{
"api_key": "ttsb_...",
"default_voice": "af_heart",
"default_speed": 1.0,
"output_dir": ".",
"poll_timeout": "10m"
}
Precedence: flags > environment variables > config file > defaults
| Setting | Environment Variable | Default |
|---|---|---|
| API key | TTSBUDDY_API_KEY | — |
| Voice | TTSBUDDY_VOICE | af_heart |
| Speed | TTSBUDDY_SPEED | 1.0 |
| Output dir | TTSBUDDY_OUTPUT_DIR | . |
| Poll timeout | TTSBUDDY_TIMEOUT | 10m |
| API URL | TTSBUDDY_API_URL | (production) |
Prefer the environment variable or config file for your API key. The -k flag is visible in shell history.
Output Modes
| Mode | stdout | stderr |
|---|---|---|
Default speak | nothing (file saved to disk) | spinner, status, file path |
--json | JSON response | nothing |
-o - | raw MP3 bytes | spinner (if TTY) |
--quiet | nothing | nothing |
--no-download | nothing | audio URL |
--json and -o - are mutually exclusive — combining them exits with code 2.
When stderr is not a TTY (piped or redirected), the spinner is automatically disabled.
Exit Codes
| Code | Meaning |
|---|---|
0 | Success |
1 | Runtime or API error (auth failure, provider error, download failure) |
2 | Usage or config error (bad flags, missing API key, invalid input) |
130 | Interrupted by Ctrl+C — prints job ID and resume command |
When interrupted during polling, the CLI prints the job ID so you can resume:
Interrupted. Resume with: ttsbuddy status <job_id>
Pipe Examples
# Convert and play immediately (macOS)
ttsbuddy speak "Hello" -o - | afplay -
# Batch convert all markdown files
for f in docs/*.md; do
ttsbuddy speak -f "$f" -o "${f%.md}.mp3"
done
# Get audio URL for use in another tool
ttsbuddy speak "Hello" --no-download --json | jq -r '.audio_url'
# Convert clipboard contents (macOS)
pbpaste | ttsbuddy speak - -o clipboard.mp3
Troubleshooting
| Error Message | Cause | Fix |
|---|---|---|
| "Invalid API key" | Key is wrong, expired, or revoked | ttsbuddy config set key <new-key> |
| "Subscription inactive" | Subscription canceled or past due | Reactivate at ttsbuddy.com/billing |
| "Rate limited" | More than 1 request/minute | Wait — retries happen automatically with backoff |
| "Monthly minutes exhausted" | Plan quota used up | Upgrade plan or wait for monthly reset |
| "No API access" | Plan doesn't include API | Check plan entitlements or contact support |
| "Text too long" | Input exceeds 500k characters | Split into smaller chunks |
| "No input provided" | No text argument, file, or stdin | Provide text: speak "text", speak -f file, or pipe |
| "Audio file has expired" | Legacy: persisted audio was deleted | Submit a new request (rare — new jobs don't use retention) |
Resources
- API Reference — full endpoint documentation
- API Keys — creating and managing keys
- GitHub Repository — source code and releases