Command Reference
Every ft subcommand, flag, environment variable, and exit code
A complete reference for the ft CLI. If you're new here, start with the CLI overview instead — this page is for looking things up.
Command summary
| Command | What it does |
|---|---|
ft auth login | Prompt for an API key and store it in the OS keychain |
ft auth logout | Forget the stored key |
ft auth whoami | Show the signed-in account |
ft me | Alias of ft auth whoami |
ft generate <tags> | Submit, poll, and download in one shot |
ft list | Show recent generations |
ft get <id> | Show one generation's detail |
ft download <id> | Download an already-completed track |
ft doctor | Health check + resolved config dump |
ft update | Re-run the install script to upgrade |
ft help [command] | Print built-in help — overall or for a single command |
Built-in help
Every command has built-in help — useful when you forget a flag and don't want to leave the terminal.
ft help # overview of all commands
ft help generate # help for a specific subcommand
ft generate --help # same thing, flag form
ft -h # short formft help <command> prints the command's description, every flag with its default, and a short usage example. It's the fastest way to check whether a flag exists without opening the docs.
Global flags
These work on every command:
| Flag | Purpose |
|---|---|
--api-key <key> | Override the stored key for this invocation. Useful in CI. |
--base-url <url> | Override the API base URL. Defaults to https://pub.finetuning.ai. |
--config <path> | Use a custom config file path instead of the default. |
-v, --verbose | Log HTTP requests and responses to stderr. Keys are redacted to ft_live_ab3f...****. |
--no-color | Disable ANSI color output. |
Spinners, prompts, and progress always go to stderr; requested data goes to stdout. That's why ft list --json | jq always works.
ft auth
ft auth login
Prompts for your API key with echo off, validates the format (ft_live_ + 32 chars, 40 total), verifies it against /v1/me, and stores it in your OS keychain.
ft auth login
# Paste your API key: ft_live_********************************
# Stored in macOS Keychain. ✓
# Signed in as jane@example.com (pro tier)Flags:
-
--stdin— read the key from stdin instead of prompting. Use this in CI:echo "$FT_API_KEY" | ft auth login --stdin
ft auth logout
Removes the key from the keychain (and the plaintext fallback if present).
ft auth whoami
Calls GET /v1/me and prints the signed-in email, tier, and credit summary. ft me is an alias.
ft me --json | jq '.data.limits'ft generate
The flagship command. Submits a generation, polls until it's completed or failed, and downloads the MP3.
ft generate "<prompt>" [flags]Flags
| Flag | Default | Notes |
|---|---|---|
--duration <sec> | 60 | 5–210 for Pro/Lifetime. Server clamps anything out of range; the CLI prints note: duration clamped from X → Y on stderr. |
--bpm <n> | 120 | 60–200. Also clamped. |
--key <K> | C | C, C#, D, D#, E, F, F#, G, G#, A, A#, B |
--scale <s> | major | major or minor |
--time-sig <s> | 4 | 2, 3, 4, 5, 6, 7 |
--language <l> | en | en, ja, de, fr, es, zh, ko, pt, it, ru |
--lyrics "<text>" | empty | 0–2000 chars |
--seed <n> | random | Pass to reproduce a previous run |
-o, --output <path> | <slug>-<short-id>.mp3 in cwd | Where to save the MP3 |
--no-wait | off | Return immediately after the 202; CLI prints the id and exits |
--json | off | Emit raw API JSON to stdout instead of downloading |
Examples
# Defaults — 60s, 120 BPM, C major
ft generate "lofi chill piano, mellow, late night"
# Customised
ft generate "upbeat ad jingle, brass and snare" \
--duration 30 --bpm 128 --key D --scale major \
--output ./jingle.mp3
# Fire and forget
ft generate "deep ambient drone" --no-wait
# Queued. id=07e8d430-2310-4c57-87a8-cf1e6db376f7 status=processing
# Scripting mode — emits the final API record to stdout, skips download
ft generate "dark trap" --json | jq '.data.id'tags is the prompt, not a comma list of keywords. The field name is historical — pass free-form prose, quoted.
--json skips the download. If you want both the JSON and the file, run ft generate ... first, then ft get <id> --json separately.
Polling behaviour
Internally ft generate polls GET /v1/generations/:id every 3–15 seconds (exponential backoff) and honors Retry-After on 429 responses. Polling times out after 5 minutes with the message:
still processing, run `ft get <id>` laterIf you Ctrl-C mid-poll, the generation keeps running server-side and still costs a credit. Resume with ft get <id> or ft download <id> once it's done — never re-submit.
ft list
Shows recent generations as a table (or JSON).
ft list [flags]| Flag | Default | Notes |
|---|---|---|
--limit <n> | 20 | Max 99 |
--offset <n> | 0 | Pagination offset |
--status <s> | all | pending, processing, completed, failed |
--json | off | Raw API response on stdout |
Examples:
ft list --limit 10
ft list --status processing # what's still in-flight
ft list --status completed --limit 50
# Pipe-friendly
ft list --json | jq '.data.generations[].id'ft get
Show one generation's full detail (including audioUrl, fileSize, generationTime, and errorMessage if it failed).
ft get <id> # human-readable
ft get <id> --json # raw API recordid is the full UUID v4 (36 chars with hyphens) printed by ft list and ft generate.
While status is pending or processing, audioUrl is null.
ft download
Download a completed track without going through generation.
ft download <id> [-o <path>]- Streams the MP3 to disk (no in-memory buffering).
- Default filename:
<slug>-<short-id>.mp3in the current directory. - Shows a progress bar when stderr is a TTY.
audioUrl lives on media.finetuning.ai (a public R2 bucket). Don't curl it directly with X-API-Key — that host doesn't auth requests, and ft download handles streaming + naming + progress for you.
ft doctor
Runs a health check and dumps the resolved config. The first thing to try when something feels off.
ft doctor
# ✓ ft v0.1.0
# ✓ config: /Users/jane/Library/Application Support/finetuning/config.json
# ✓ base URL: https://pub.finetuning.ai
# ✓ /health → ok
# ✓ key: ft_live_ab3f...**** (jane@example.com, pro tier)ft update
Re-runs the install script for your OS to pull the latest release. Equivalent to running the install one-liner from the overview again.
Configuration
Config file
| OS | Path |
|---|---|
| macOS | ~/Library/Application Support/finetuning/config.json |
| Linux | ~/.config/finetuning/config.json |
| Windows | %APPDATA%\finetuning\config.json |
{
"baseUrl": "https://pub.finetuning.ai",
"defaultDuration": 60,
"defaultBpm": 120
}Override the location with FINETUNING_CONFIG_HOME=/some/path or --config <path>.
API key resolution order
When a command needs the key, the CLI checks these sources in order and uses the first hit:
--api-key <key>flagFINETUNING_API_KEYenvironment variable- OS keychain (service
finetuning, accountdefault) - Plaintext fallback at
~/.config/finetuning/credentials(0600) — only used on headless Linux without libsecret
Environment variables
| Variable | Purpose |
|---|---|
FINETUNING_API_KEY | API key to use. Overrides the keychain. |
FINETUNING_CONFIG_HOME | Custom config directory. |
NO_COLOR | Set to any value to disable ANSI color (same as --no-color). |
JSON mode and piping
Every read command supports --json. Spinners, prompts, and progress go to stderr; data goes to stdout — so this always works:
ft list --json | jq '.data.generations[] | select(.status == "completed") | .id'ft generate --json is the one exception worth knowing: it emits the final API record but does not download the MP3. That's the right shape for scripting; if you want both, run the download separately.
Exit codes
| Code | Meaning |
|---|---|
0 | Success |
1 | API error — read the stderr message; the CLI surfaces the server's message field verbatim |
2 | Validation error — bad flag, malformed argument, bad input |
3 | Network or transport error reaching the API |
Rate limits
The CLI shares limits with the public API:
POST /v1/generations(i.e.ft generate): 10 / minute / user- Every other read: 60 / minute / user
When polling completes a generation, the CLI honors Retry-After automatically. For back-to-back ft generate calls, you may need to slow down.
Common errors
| HTTP | Code | What to do |
|---|---|---|
401 | MISSING_API_KEY / INVALID_API_KEY | Run ft auth login — your stored key may have been revoked |
401 | ACCOUNT_DELETED | Contact support |
402 | MONTHLY_LIMIT_REACHED | Out of credits. Check ft me, upgrade or buy a pack |
403 | PRO_PLAN_REQUIRED | Free/Plus account — upgrade at finetuning.ai |
404 | NOT_FOUND | Bad generation ID |
429 | GENERATION_RATE_LIMITED | 10 creates/min cap — wait Retry-After |
429 | QUEUE_FULL | Too many concurrent in-flight generations. ft list --status processing to see them |
500 | GENERATION_FAILED | Usually transient. Retry once; if it persists, see errors |
See the full errors guide for the API-level reference.