Skip to main content

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
tip

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:

FlagDescription
-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)
--rawSkip markdown preprocessing
--no-downloadPrint audio URL instead of downloading
--idempotency-key <key>Override auto-generated idempotency key
note

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.

Flash Voices for Speed

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
FlagDescription
--watchPoll 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:

FlagDescription
-k, --key <key>API key (overrides config and env var)
--jsonJSON output to stdout only, no human output on stderr
--quietSuppress 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

SettingEnvironment VariableDefault
API keyTTSBUDDY_API_KEY
VoiceTTSBUDDY_VOICEaf_heart
SpeedTTSBUDDY_SPEED1.0
Output dirTTSBUDDY_OUTPUT_DIR.
Poll timeoutTTSBUDDY_TIMEOUT10m
API URLTTSBUDDY_API_URL(production)
tip

Prefer the environment variable or config file for your API key. The -k flag is visible in shell history.

Output Modes

Modestdoutstderr
Default speaknothing (file saved to disk)spinner, status, file path
--jsonJSON responsenothing
-o -raw MP3 bytesspinner (if TTY)
--quietnothingnothing
--no-downloadnothingaudio 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

CodeMeaning
0Success
1Runtime or API error (auth failure, provider error, download failure)
2Usage or config error (bad flags, missing API key, invalid input)
130Interrupted 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 MessageCauseFix
"Invalid API key"Key is wrong, expired, or revokedttsbuddy config set key <new-key>
"Subscription inactive"Subscription canceled or past dueReactivate at ttsbuddy.com/billing
"Rate limited"More than 1 request/minuteWait — retries happen automatically with backoff
"Monthly minutes exhausted"Plan quota used upUpgrade plan or wait for monthly reset
"No API access"Plan doesn't include APICheck plan entitlements or contact support
"Text too long"Input exceeds 500k charactersSplit into smaller chunks
"No input provided"No text argument, file, or stdinProvide text: speak "text", speak -f file, or pipe
"Audio file has expired"Legacy: persisted audio was deletedSubmit a new request (rare — new jobs don't use retention)

Resources