# CLI Reference > Parent doc: [LLM_CONTEXT.md](LLM_CONTEXT.md) ## Overview Three CLI entry points, all in `scripts/`: | Script | Role | Default output | |--------|------|---------------| | `compose.py` | Full composition pipeline | `.rpp` file | | `generate.py` | Thin wrapper around compose | `.rpp` file + optional validation | | `run_in_reaper.py` | ReaScript generation & execution | ReaScript `.py`, result JSON, LUFS JSON | ## compose.py Full pipeline: builds all tracks, applies calibration, generates `.rpp`. ### Usage ```bash python scripts/compose.py [--bpm BPM] [--key KEY] [--output PATH] [--seed SEED] [--emotion EMOTION] [--inversion INVERSION] [--no-calibrate] ``` ### Flags | Flag | Type | Default | Description | |------|------|---------|-------------| | `--bpm` | `float` | `99` | Tempo. Must be > 0. | | `--key` | `str` | `"Am"` | Musical key. Format: `[A-G][b#]?m?` (e.g. `"Am"`, `"Dm"`, `"G"`, `"F#m"`) | | `--output` | `str` | `"output/song.rpp"` | Output `.rpp` file path. Parent directory created if missing. | | `--seed` | `int` | `None` | Random seed. `None` = non-deterministic (system time). | | `--emotion` | `str` | `"romantic"` | Chord emotion: `romantic`, `dark`, `club`, `classic` | | `--inversion` | `str` | `"root"` | Preferred chord inversion: `root`, `first`, `second` | | `--no-calibrate` | `flag` | `False` | Skip post-processing mix calibration | ### Examples ```bash # Default reggaetón at 99 BPM in Am python scripts/compose.py # Specific BPM and key python scripts/compose.py --bpm 95 --key Dm # Deterministic output with seed python scripts/compose.py --bpm 95 --key Am --seed 42 # Dark emotion with first inversion chords python scripts/compose.py --emotion dark --inversion first # Skip calibration (raw volumes from VOLUME_LEVELS in compose.py) python scripts/compose.py --no-calibrate # Custom output path python scripts/compose.py --output my_project/song_v2.rpp ``` ### Output Structure ``` output/song.rpp # REAPER project file ``` Console output includes: - BPM and key confirmation - Section count and total duration (bars + beats) - Kick detection cache summary (per drumloop file) - Final output path ## generate.py Thin wrapper around `compose.py`. Delegates by setting `sys.argv` and calling `compose.main()`. ### Usage ```bash python scripts/generate.py [--bpm BPM] [--key KEY] [--output PATH] [--seed SEED] [--emotion EMOTION] [--inversion INVERSION] [--validate] ``` ### Flags | Flag | Type | Default | Description | |------|------|---------|-------------| | `--bpm` | `float` | `95` | Tempo. Must be > 0. | | `--key` | `str` | `"Am"` | Musical key | | `--output` | `str` | `"output/song.rpp"` | Output `.rpp` path | | `--seed` | `int` | `42` | Random seed | | `--emotion` | `str` | `"romantic"` | Chord emotion | | `--inversion` | `str` | `"root"` | Chord inversion | | `--validate` | `flag` | `False` | Run validator after generation | ### Differences from compose.py - Default BPM is 95 (vs 99 in compose.py) - Default seed is 42 (vs None in compose.py) - Has `--validate` flag (runs `validate_rpp_output()` after generation) - No `--no-calibrate` flag (calibration always applied) ### Examples ```bash # Generate with default settings python scripts/generate.py # Generate with validation python scripts/generate.py --bpm 95 --key Dm --seed 123 --validate # Full custom generation python scripts/generate.py --bpm 100 --key Fm --output output/custom.rpp --seed 7 --emotion club ``` ### Validation Errors When `--validate` is set, errors are printed to stderr: ``` Validation errors: - Expected 416 beats, found 400 beats - Missing drumloop in section: chorus ``` Exit code 1 on validation failure. ## run_in_reaper.py Generates a ReaScript for post-processing and polls for results. ### Usage ```bash python scripts/run_in_reaper.py [--output WAV_PATH] [--timeout SECONDS] [--plugins-config JSON_PATH] [--action ACTIONS] ``` ### Arguments and Flags | Arg/Flag | Type | Default | Description | |----------|------|---------|-------------| | `rpp_path` | positional | *(required)* | Path to `.rpp` file | | `--output`, `-o` | `str` | `_rendered.wav` | Rendered WAV output path | | `--timeout` | `int` | `120` | Seconds to poll for result JSON | | `--plugins-config` | `str` | `None` | Path to JSON-serialized `SongDefinition` (for deriving `plugins_to_add`) | | `--action` | `str` | `"calibrate"` | Space-separated action pipeline | ### Actions Space-separated list of up to 5 actions, executed in order: ``` add_plugins configure_fx_params verify_fx calibrate render ``` Each action name maps to a function in the generated ReaScript. Unknown action names are ignored. ### Examples ```bash # Basic calibration on an existing .rpp python scripts/run_in_reaper.py output/song.rpp # Full pipeline: load plugins, calibrate, render python scripts/run_in_reaper.py output/song.rpp --action "add_plugins calibrate render" # With plugin config from JSON SongDefinition python scripts/run_in_reaper.py output/song.rpp --plugins-config output/song.json --action "add_plugins configure_fx_params" # Custom render output and extended timeout python scripts/run_in_reaper.py output/song.rpp -o output/final_mix.wav --timeout 300 --action "calibrate render" ``` ### Output Files ``` scripts/fl_control_phase2.py # Generated ReaScript scripts/fl_control_command.json # Command JSON for ReaScript scripts/fl_control_result.json # Result JSON from ReaScript (polled) output/_lufs.json # LUFS metrics output/_fx_errors.json # FX errors (if any) ``` ### Exit Codes | Code | Meaning | |------|---------| | 0 | Success | | 1 | Error: .rpp not found, plugin config not found, result read error, or REAPER error | | 2 | Timeout: result JSON not found within timeout | ## Key Validation All scripts validate the key format: `^[A-G][b#]?m?$` Valid examples: `"Am"`, `"C"`, `"D#m"`, `"Gb"`, `"F#"`. Invalid: `"A minor"`, `"c"` (lowercase), `"H"`, `"Am7"`. ## BPM Validation BPM must be > 0. Min/max enforced by `SongDefinition.validate()`: 20–999. ## Determinism - When `--seed` is provided, all random operations use `random.Random(seed)` for reproducible output. - Same `(--bpm, --key, --seed, --emotion, --inversion)` produces identical `.rpp` files. - ReaScript seed is derived from the CLI seed. Same command → same script.