Finetuning.aiFinetuning.ai

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

CommandWhat it does
ft auth loginPrompt for an API key and store it in the OS keychain
ft auth logoutForget the stored key
ft auth whoamiShow the signed-in account
ft meAlias of ft auth whoami
ft generate <tags>Submit, poll, and download in one shot
ft listShow recent generations
ft get <id>Show one generation's detail
ft download <id>Download an already-completed track
ft doctorHealth check + resolved config dump
ft updateRe-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 form

ft 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:

FlagPurpose
--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, --verboseLog HTTP requests and responses to stderr. Keys are redacted to ft_live_ab3f...****.
--no-colorDisable 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

FlagDefaultNotes
--duration <sec>605–210 for Pro/Lifetime. Server clamps anything out of range; the CLI prints note: duration clamped from X → Y on stderr.
--bpm <n>12060–200. Also clamped.
--key <K>CC, C#, D, D#, E, F, F#, G, G#, A, A#, B
--scale <s>majormajor or minor
--time-sig <s>42, 3, 4, 5, 6, 7
--language <l>enen, ja, de, fr, es, zh, ko, pt, it, ru
--lyrics "<text>"empty0–2000 chars
--seed <n>randomPass to reproduce a previous run
-o, --output <path><slug>-<short-id>.mp3 in cwdWhere to save the MP3
--no-waitoffReturn immediately after the 202; CLI prints the id and exits
--jsonoffEmit 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>` later

If 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]
FlagDefaultNotes
--limit <n>20Max 99
--offset <n>0Pagination offset
--status <s>allpending, processing, completed, failed
--jsonoffRaw 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 record

id 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>.mp3 in 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

OSPath
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:

  1. --api-key <key> flag
  2. FINETUNING_API_KEY environment variable
  3. OS keychain (service finetuning, account default)
  4. Plaintext fallback at ~/.config/finetuning/credentials (0600) — only used on headless Linux without libsecret

Environment variables

VariablePurpose
FINETUNING_API_KEYAPI key to use. Overrides the keychain.
FINETUNING_CONFIG_HOMECustom config directory.
NO_COLORSet 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

CodeMeaning
0Success
1API error — read the stderr message; the CLI surfaces the server's message field verbatim
2Validation error — bad flag, malformed argument, bad input
3Network 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

HTTPCodeWhat to do
401MISSING_API_KEY / INVALID_API_KEYRun ft auth login — your stored key may have been revoked
401ACCOUNT_DELETEDContact support
402MONTHLY_LIMIT_REACHEDOut of credits. Check ft me, upgrade or buy a pack
403PRO_PLAN_REQUIREDFree/Plus account — upgrade at finetuning.ai
404NOT_FOUNDBad generation ID
429GENERATION_RATE_LIMITED10 creates/min cap — wait Retry-After
429QUEUE_FULLToo many concurrent in-flight generations. ft list --status processing to see them
500GENERATION_FAILEDUsually transient. Retry once; if it persists, see errors

See the full errors guide for the API-level reference.

On this page