xilcmd

A script goes in. An episode comes out.

xil-pipeline turns a markdown script and a cast list into a fully mixed, broadcast-ready audio episode: voices, sound effects, music, and a final master MP3. It comes in two implementations that produce the same output.

## SCENE 1: The porch, dusk
[AMBIENCE: crickets, distant traffic]

NARRATOR: The screen door
had been broken all summer.

[SFX: screen door creaks open]

MAGGIE: [whispering] You
heard that too, didn't you?
A waveform drawn from the script excerpt, mirrored to show the Python and Rust implementations producing the same result.
Each bar is drawn from the script beside it. Python above the line, Rust below: same script, same episode.

How it works

From markdown script to finished stereo episode in seven steps. Assemble is optional: it lets you hear the produced audio immediately, before the DAW export.

  1. WriteDraft the episode as a markdown script following the script style guide
  2. ScanCheck the script for unknown speakers before anything is generated
  3. ParseTurn the markdown script into structured JSON with voices, cues, and timing
  4. ProduceGenerate dialogue and sound effects with ElevenLabs, local Chatterbox Turbo, or gTTS
  5. AssembleOptionalStitch the produced stems into a rough cut you can listen to right away
  6. DAW exportOrganize dialogue, SFX, music, and ambience into separate WAV layers and build the episode's timeline HTML
  7. MasterMix the WAV layers down to the final stereo MP3

Pick where the voices come from

Dialogue can be generated by the ElevenLabs cloud service or by Chatterbox Turbo, an open-source model that runs on your own machine. For a quick trial with almost no setup, gTTS reads the whole script in a single voice. Every backend works with the Python and Rust versions, and you choose per run.

ElevenLabs

Commercial API, the default

Nothing to install beyond the pipeline itself. Add your API key and every character in the cast gets a voice from the ElevenLabs library. The same key also generates sound effects. Run with --dry-run first to see the character cost before any credits are spent.

# get a key at elevenlabs.io, then
export ELEVENLABS_API_KEY=your_key_here
xil-produce --episode S01E01 --dry-run
xil-produce --episode S01E01

Chatterbox Turbo

Open-source model from Hugging Face, runs locally

Free to run once it's set up, on an NVIDIA GPU or on the CPU alone. Model weights download from Hugging Face on first use, and each character is cloned from a short reference recording you provide. It lives in its own virtual environment so its PyTorch dependencies stay out of the main install, and the pipeline finds it automatically.

# one reference clip per character, over 5 seconds
voice_refs/<speaker_key>.wav

# if the model repo is gated for your account
export HF_TOKEN=hf_...
xil-produce --episode S01E01 --backend chatterbox-turbo

gTTS

Free, minimal setup, single voice

The original proof of concept, and still the fastest way to hear a script end to end. There's no API key, no GPU, and no voice setup; every character is read in the same voice. Useful for checking timing and flow before committing to a full render.

xil-produce --episode S01E01 --backend gtts
ElevenLabs, Chatterbox Turbo, and gTTS compared
ElevenLabsChatterbox TurbogTTS
CostPaid per character, from your ElevenLabs planFree to run; you supply the hardwareFree
Runs onElevenLabs servers, over the internetYour machine: an NVIDIA GPU through CUDA when one is available, otherwise the CPUGoogle's text-to-speech service, over the internet
VoicesChosen from the ElevenLabs voice libraryCloned from your own reference clipsOne voice for the whole cast
SetupAn API keyA separate virtual environment with PyTorchNothing beyond the optional extras; no key or GPU
Delivery cuesElevenLabs audio tags19 built-in tags, such as [whispering], [sigh], and [laugh]None

Scripts can be shared between backends. Under Chatterbox Turbo, any bracketed tag it doesn't recognize is stripped, so ElevenLabs-only cues can stay in the script.

Setting up a backend

Each backend has its own setup needs:

  • gTTS works as soon as the optional extras are installed.
  • ElevenLabs needs an account and a key.
  • Chatterbox Turbo needs its own Python environment and a reference clip for each voice.

Two optional local tools work the same way: Whisper checks rendered lines against the script, and MMAudio makes sound effects on your own GPU. See Local tools below.

Two environment variables keep your show separate from the pipeline's own software:

  • XIL_PROJECTROOT is your show's workspace—scripts, generated audio, and configs.
  • XIL_CODEROOT is where the pipeline and any local-model environments, like venv-chatterbox/, venv-whisper/, and venv-mmaudio/, are installed.

Both are optional; each defaults to your current folder if unset.

ElevenLabs

  1. Create an API key

    Sign in at elevenlabs.io, then open Profile and choose API Keys. Your plan's character allowance is what renders spend.

  2. Set it in your shell
    export ELEVENLABS_API_KEY=your_key_here

    To keep it across sessions, add that line to ~/.bashrc or ~/.zshrc. Check it with echo $ELEVENLABS_API_KEY.

  3. Pick voices for the cast

    Browse and audition voices with xil-voices, then assign them in the show's cast file, cast_<slug>_<TAG>.json.

  4. Preview the cost, then render
    xil-produce --episode S01E01 --dry-run
    xil-produce --episode S01E01

    Only the commands that call the API need the key: xil-produce, xil-sfx, xil-studio, xil-sample, and xil-cues --generate. Parsing, DAW export, and mastering work without it.

Chatterbox Turbo

  1. Build the environment

    Chatterbox pulls in PyTorch, so it gets its own virtual environment, venv-chatterbox/. One command builds it in your code root (XIL_CODEROOT), picks CUDA or CPU PyTorch for your hardware, installs Chatterbox, and checks that it works. The pipeline then finds it automatically.

    xil setup chatterbox --dry-run   # show the commands first
    xil setup chatterbox

    It uses uv when installed, otherwise python3.13 -m venv and pip. Force a build with --device cuda or --device cpu; running it again on a working environment does nothing. Model weights download from Hugging Face on the first render. If the model repository is gated for your account, run huggingface-cli login or set HF_TOKEN first.

    By hand instead (CUDA 12.4 shown; use .../whl/cpu for CPU only)

    cd "$XIL_CODEROOT"
    python3.13 -m venv venv-chatterbox
    venv-chatterbox/bin/pip install 'torch==2.6.0' 'torchaudio==2.6.0' \
        --index-url https://download.pytorch.org/whl/cu124
    venv-chatterbox/bin/pip install chatterbox-tts pydub
  2. Record a reference clip per character

    Save one clip for each speaker as voice_refs/<speaker_key>.wav. Each clip must be longer than 5 seconds.

  3. Render
    xil-produce --episode S01E01 --backend chatterbox-turbo

    If your environment lives somewhere else, point to its Python with --chatterbox-python PATH. Both the Python and Rust versions use the same environment.

Local tools: Whisper and MMAudio

  1. Whisper, to check rendered lines

    xil stem-verify can transcribe every rendered line with Faster-Whisper, and xil stem-compare then flags lines that do not match the script. Whisper gets its own environment, venv-whisper/. It does not need PyTorch, so it is small.

    xil setup whisper
    xil stem-verify --episode S01E01

    On an NVIDIA GPU it runs on CUDA. If the GPU libraries are missing, it falls back to the CPU by itself.

  2. MMAudio, for local sound effects

    MMAudio makes sound effects on your own GPU (about 6 GB of video memory) instead of calling ElevenLabs. It is not on PyPI, so setup clones it next to venv-mmaudio/ (this needs git). It uses Python 3.12, because MMAudio does not install on 3.13. The model weights, about 6 GB, download on the first run into the same folder.

    xil setup mmaudio --dry-run   # show the commands first
    xil setup mmaudio
    xil sfx --episode S01E01 --gen-sfx --sfx-backend mmaudio --mmaudio-accept-noncommercial

    Non-commercial only. MMAudio's code is MIT licensed, but its model weights are CC BY-NC 4.0. Audio it makes must not appear in a show that earns money. The pipeline refuses to start it without --mmaudio-accept-noncommercial, and it tags every clip it makes.

  3. Get the right Python

    Install uv first. Setup then fetches the Python version each tool needs. Without uv, setup uses whatever python3 you have and warns you if the version is wrong.

Two implementations, one pipeline

The Python package is the reference. The Rust port reimplements every command as a single binary and is checked against the Python output file by file.

Python

xilcmd/xil-pipeline

The original implementation, installed from PyPI. Each pipeline stage is its own command, and every command that calls a paid API supports --dry-run so you can preview cost before spending quota.

  • Python 3.12+ and ffmpeg
  • ElevenLabs by default, with local Chatterbox Turbo voices and MMAudio sound effects as options
  • Exports separate WAV layers for mixing in Audacity
  • Optional browser dashboard: pip install "xil-pipeline[gui]", then xil-gui
  • Man pages and full documentation on Read the Docs
# install
pip install xil-pipeline

# parse a script, then preview TTS cost
xil-parse scripts/sample_S01E01.md --episode S01E01
xil-produce --episode S01E01 --dry-run

Rust

xilcmd/rxil-pipeline

A port of all 39 commands into one xil binary. With the default ElevenLabs backend it needs no Python at all; the optional local ML models run as separate workers that xil talks to over JSON lines.

  • Prebuilt binaries for Linux, macOS, and Windows
  • Browser dashboard built in: xil gui
  • Output verified against the Python version by a parity harness
  • User guide and generated man pages
# install
# download a release, put xil on your PATH

# create a workspace, then explore
mkdir myshow && cd myshow && xil init
xil status --toolchain
xil gui

Which one should I use?

Both read the same scripts and configs and write the same workspace layout, so you can switch between them on the same show.

Choose Python if you already work in a Python environment, want to extend the pipeline in Python, or want to track the reference implementation directly.

Choose Rust if you want a single download with no Python setup, a faster start on a new machine, or the built-in web dashboard.

Checked, not assumed

The Rust port grows around the Python package one stage at a time. For every check, a parity harness runs the Python xil and the Rust xil on twin copies of the same workspace, then compares exit codes, console output, and every file written, including the audio.

CI pins the exact Python commit each check is compared against, so a difference always points to a real change.

export XIL_PY_BIN=/path/to/xil-pipeline/venv/bin/xil
python tools/parity/parity.py check --suite