Exit Node

Configuration

v1.3.3Get talkinghead

Set the judge and the transcriber in the environment, on the command line, or in a config file. Precedence, highest first: command-line flag, environment variable, config file, built-in default. Neither the judge nor the transcriber has a built-in default, so a run stops with a clear message until you name them.

variable required values what it controls example
TALKINGHEAD_JUDGE yes, unless --judge or judge in the config file is set claude, or shell:<command> the LLM that votes on every editorial decision export TALKINGHEAD_JUDGE=claude
TALKINGHEAD_TRANSCRIBER yes, unless --transcriber or transcriber in the config file is set scribe, parakeet, whisper the speech-to-text backend export TALKINGHEAD_TRANSCRIBER=whisper
OPENROUTER_API_KEY for scribe OpenRouter API key the Scribe v2 route: elevenlabs/scribe-v2 through OpenRouter, the only Scribe route export OPENROUTER_API_KEY=...
TALKINGHEAD_CONFIG no path to a TOML file the config file to load (same as --config) export TALKINGHEAD_CONFIG=$HOME/talkinghead.toml
TALKINGHEAD_CACHE no directory; default ~/.cache/talkinghead where the content-addressed cache lives export TALKINGHEAD_CACHE=/Volumes/scratch/th-cache
TALKINGHEAD_PROFILE no directory, created on first use your private editing profile: approved preferences and the feedback log (see Editing profile) export TALKINGHEAD_PROFILE=$HOME/talkinghead-profile
FLUIDAUDIO_BIN no, unless fluidaudiocli is not on PATH path to fluidaudiocli the Parakeet binary export FLUIDAUDIO_BIN=/opt/fluidaudio/fluidaudiocli
TDT_EMISSION_DELAY_FRAMES no, advanced integer, passed through a word-timing shift in fluidaudiocli (Parakeet); setting it changes the Parakeet cache key export TDT_EMISSION_DELAY_FRAMES=2
TALKINGHEAD_GAP_BUDGET_FRACTION no, advanced fraction of source duration; default 0.005 the dead-air budget in the verification table; raise it for a cook that keeps far more pause than the policy trims export TALKINGHEAD_GAP_BUDGET_FRACTION=0.15
HF_HOME no directory read by the Hugging Face libraries, not by talkinghead; moves the Whisper model cache export HF_HOME=/Volumes/scratch/hf

Judge values

claude runs Claude Code headless (claude -p) on your Claude subscription. It needs claude on PATH and a signed-in account (claude --version shows the install). With no model named, Claude Code uses its own default. --model (or model in the config file) sets Claude Code’s model, using a name Claude Code accepts, such as an alias like opus. --effort sets its effort level.

shell:<command> runs any command that reads the prompt on stdin and prints one JSON object on stdout. For example, omp, which needs a login (omp login):

export TALKINGHEAD_JUDGE='shell:omp -p --no-session --no-tools --mode text --model anthropic/claude-opus-5-5'

--model rewrites the --model token of a shell command. With no --model, the command runs as written.

shell:python3 -m talkinghead.dryrun_judge is the offline dry-run judge. It calls no model and makes no editorial decision. It exists to check the install, so do not publish its cuts.

Before transcription, every run sends one tiny call to the judge. A missing command, a signed-out account, or a model the provider does not serve stops the run before transcription starts, with exit 4.

Some providers restrict how their subscriptions may be used from third-party tools, so pick a judge route your plan allows. This README does not give legal advice on those terms.

Transcriber values

scribe sends the 16 kHz mono audio of the whole recording to OpenRouter, which serves elevenlabs/scribe-v2 with OPENROUTER_API_KEY. OpenRouter accepts a request body of at most 50 MiB, so a longer recording is cut into chunks. Each chunk holds about 19 minutes of its own audio, with 20 seconds of context on each side that has a neighbour. A cut goes at the longest silence near an even split, or at the quietest 50 ms when there is no silence. Chunks are sent a few at a time and merged onto one timeline. A word heard in two overlaps is kept once, from the chunk that owns its midpoint. A failed chunk fails the run, and a malformed response is an error. The transcript’s version records the route, and the chunk count when there is more than one chunk.

parakeet runs NVIDIA Parakeet TDT through fluidaudiocli on macOS. It is macOS only. Its word timings are tighter, which matters for the machinery cuts, so it is the better local choice.

whisper runs mlx-community/whisper-large-v3-turbo through mlx-whisper on macOS. Elsewhere it runs the same model through faster-whisper on the CPU. The model is downloaded from Hugging Face once, on first use (about 1.5 GB). Whisper’s word spans absorb some hesitations, and the CLI says so when you choose it.

Config file

talkinghead.example.toml lists the most used settings as commented lines. Where a setting has a default, the line shows that default. Copy it, uncomment what you change, and point talkinghead at the copy with --config FILE or TALKINGHEAD_CONFIG. Unknown keys are an error, so a typo stops the run instead of being ignored. A talkinghead.toml in the repository root is not loaded automatically.

The settings most people change first are votes and agree (the vote size), content_enabled, visuals_enabled, visuals_research, visuals_corner, crf and preset (final quality), and judge_timeout.

Voice isolation (macOS only, opt-in)

isolate_voice = true in the config file, or --isolate-voice on the command line, renders the audio through Apple’s voice isolation (AUSoundIsolation). It is for noisy places: a hotel lobby, a restaurant, a handheld mic. Silence for the pauses stage and the dead-air check is measured on the isolated track, so room tone the unit gates to digital silence counts as silence. The source transcript, the judges’ candidates and edge placement keep reading the original audio. The output pass judges the transcript of an original-audio companion render, one per round (an extra render and transcription each round). The isolated render’s own transcript is used only for the isolation_words count. Turning it on re-keys the pauses stage. Later stages that build on the pause cuts (restructure, polish, output rounds) recompute, and their judge calls may run again. Structure, retakes and content replay from their memos.

  • isolate_mix (default 1.0) is the isolated share of the track, from 0 (the original microphone audio) to 1 (fully isolated). --isolate-mix F sets it.
  • The unit delays its output. talkinghead measures that delay by cross-correlating the output with the original at six loud points, and trims it. The points must agree, or the run stops.
  • Words the unit swallows (their isolated level falls far below the recording’s median) are replaced by the original audio, scaled to the isolated level and joined with 10 ms equal-power crossfades. The report lists them with their output times.
  • The helper is a Swift file in the package, compiled once with xcrun swiftc into the cache. The isolated track is cached per source file and helper version. The plan records the track’s sha256, mix, latency and repaired words, so talkinghead render PLAN rebuilds the same audio.
  • On any other platform, or where the unit is missing, a run with the flag stops before doing any work.
  • The report’s ## Isolation section and the isolation_alignment and isolation_words checks show the result.

diarize = true in the config file (or --diarize) makes Scribe label every word with its speaker. Those transcripts have their own cache key, so cooks made without it keep their caches.

Editorial guidelines

editorial/guidelines.md is one creator’s example rule set. The whole file goes to the judge with every call, so it decides what the judge values: as the system prompt with claude, and at the head of the prompt on stdin with a shell: judge. Guidelines are not part of a judge answer’s cache key, so after you edit them a rerun replays answers already given; the stages that depend on them are recomputed from those answers. Replace it with your own rules in one of two ways:

uv run talkinghead run talk.mov --guidelines ~/my-rules.md

or set guidelines = "/path/to/my-rules.md" in the config file. A relative guidelines path resolves inside the clone.

Editing profile

The editing profile is a private directory that remembers how you like your videos cut. Point TALKINGHEAD_PROFILE (or --profile DIR) at it; nothing is created until you first use it. It holds two files:

file what it holds
preferences.md the rules you approved, one - rule per line. Every judge prompt carries them, for every judge
feedback.jsonl every note you recorded, with the source time it points at and its review status

Feedback comes in three kinds, and each goes to a different place:

kind example where it goes
video (default) “cut the aside at 3:10” the log only; it is about this video
preference “too salesy” with the lesson “Commit to the pitch” a proposed lesson, waiting for your approval
defect “the ‘the’ at 7:03 is clipped” a fixture and a test stub in the clone (see Other commands); a tool bug is fixed in code, never learned as a preference
uv run talkinghead feedback talk.talkinghead "cut the aside" --at 3:10
uv run talkinghead feedback talk.talkinghead "too salesy" --kind preference --lesson "Commit to the pitch."
uv run talkinghead lessons                         # list proposed lessons
uv run talkinghead lessons accept 2 --text "Commit to the pitch: pain, cost, solution."
uv run talkinghead lessons reject 3

--at is a time in the cut you watched; the log stores the matching source time, so the note still points at the right moment after a re-cut. Nothing is learned silently: a lesson becomes a preference only through lessons accept, which appends it to preferences.md. You can also edit preferences.md by hand.

Each cook keeps a snapshot of the preferences it was judged with, in <video stem>.talkinghead/preferences.md. Changing the profile affects new cooks only, so a rerun of an existing cook replays its cached judge answers. To re-judge an existing cook with the current profile, add --refresh-preferences; only the judge calls whose prompt changed run again. A cook made before the profile existed is frozen without preferences until you refresh it. With no profile, or an empty preferences.md, the prompts are unchanged.

Filler words

Every hesitation the transcriber writes as a word (uh, um, erm, hmm, hm, mm and similar) is cut by default, however short. Two config keys bring back a gentler policy:

key default effect
min_filler_dur 0.0 fillers shorter than this many seconds are kept (the earlier default was 0.15)
filler_keep_voiced_max 0.0 a filler up to this long whose edge runs straight into speech is kept, because the tight splice can sound worse than the filler (the earlier default was 0.35)

min_filler_dur is part of the pauses stage’s memo key, so rerunning a cook made under the old default recomputes that mechanical stage. No judge call runs again, and the replaced memo is kept as stages/pauses.superseded.json.

Overlay assets

editorial/assets/ is a small library of diagrams made for this project (MIT, see editorial/assets/CREDITS.md). The overlay pass places an asset where the judge’s anchors match it. To use your own library, set assets_dir in the config file or pass --assets-dir DIR. Describe your images in a manifest.toml next to them, the same way editorial/assets/manifest.toml does. visuals_avatar names an optional square PNG or JPEG that is drawn as a mascot on quote cards.