Behind the scenes

How these are made

The short version

Each episode is a documentary about one record. A pipeline researches the album from the open web, writes a script in the voice of a synthetic radio host, synthesises the narration, and publishes the result as a playlist that interleaves the narration with the album tracks themselves.

It runs on a small server in a house, not in a studio. Nobody is paid and nothing is sponsored. It exists because the results turned out to be genuinely fun to listen to.

The rule the whole thing is built on

Deterministic by default, language model by exception.

There are exactly two jobs in this pipeline a model is trusted with: reading a pile of sources and organising what they say, and turning those notes into a script in a host's voice. Both are genuinely language problems, and both are things a model is good at.

Everything else is ordinary code with tests around it: deciding which episode is next, checking the script is well-formed, estimating what the narration will cost, cutting the audio, tagging it, ordering the running sheet, building the playlist. Not because a modelcouldn't attempt those steps, but because none of them benefit from judgement, and every one of them is somewhere a plausible guess would do real damage. Roughly three hundred tests cover that side of the line. The creative half gets no tests, which is precisely why it gets everything else instead.

The pipeline

Eight stages. Two of them think; the other six check, count and execute.

  1. code Pick the episode

    A plain-text catalogue holds the season: albums, hosts, and what state each episode is in. The run claims the next one and opens a working folder for it. Everything the run produces lands there, so a half-finished episode is a resumable thing rather than a mess.

  2. model Research

    A handful of targeted searches, then the top pages are actually fetched and read, then one pass to organise what they say into notes. Sources are scored by how much they can be trusted, and a second pass re-reads the draft notes against the original page text and quarantines anything that turns out to be inference or rests only on a weak source.

    Lyrics are handled separately and never paraphrased: exact words are pulled from a lyrics database into their own bank, kept out of the summarising step so nothing can smooth them over, and quoting is only allowed from there.

  3. model Write

    The writer gets the research file and nothing else. No web access, no drawing on what the model happens to remember, no filling a gap with something that sounds right. If the research is thin or contradicts itself, the instruction is to write around it and log the hole rather than paper over it.

    It also has to produce a specific shape: numbered segments, each one either spoken or a song, each labelled, with the album tracks declared properly. That shape isn't decoration. It's what makes the next step possible.

  4. code Validate

    Because the script has to fit a known shape, a program can check it, and it does: segment numbers run in order with no gaps, every label is well-formed, no segment is empty, the host is a real persona and their name matches, every song names its title, artist and album, and the number of album tracks the script declares matches the number it actually contains.

    This is a hard gate. A script that fails does not get recorded. It's the cheapest possible check and it catches the entire class of failure where a model produces something fluent and subtly malformed.

  5. model Fact-check, advisory by design

    A separate pass re-reads the finished script against the research and flags claims that contradict the notes or aren't supported by them, while deliberately ignoring the host's opinions, jokes and persona colour, which aren't facts and shouldn't be treated as though they were.

    This one only advises; it can't block a recording. A deterministic check earns the right to stop the line because it's either right or it's broken. A model's judgement doesn't, so its findings get surfaced for a person to weigh instead of silently killing a run. The writer also keeps its own honesty log alongside the script, flagging gaps it wrote around and names it wants checked before anyone says them out loud.

  6. code Budget

    Voice synthesis is the only part of this that costs real money, so the bill is estimated from the finished script and checked against a cap before a single second is rendered. Nothing about that decision wants creativity. It wants arithmetic that happens the same way every time.

  7. code Record

    Each spoken segment is synthesised on its own and tagged, which is why the running order here is a list of segments rather than one long file. Segment-by-segment means a single bad take can be re-recorded for pennies instead of re-running the episode.

  8. code Publish

    The narration is interleaved with the album tracks in the order the script asked for, and the result becomes a playlist in the music library the station plays from. On this site you get the narration and the script; the album tracks stay with the broadcast, where they belong to their artists.

The part I got wrong first

The research step began as the obvious thing: an agent with a search tool, free to go and look into whatever it found interesting. It fired off twenty searches without reading a single page it found, and got the search engine to block it.

What replaced it isn't cleverer, it's narrower: a fixed number of targeted searches, fetch the top results, read them, then one pass to make sense of what they actually said. It is cheaper, it is polite to the sites it reads, and it produces the same shape of output every time. Most of the design here came from that direction: not "how do I make the model smarter" but "how much of this job doesn't need a model at all."

How a run starts

The pipeline runs on a small server in my house and exposes its stages as tools. A separate agent connects to it, and once a month a scheduled job wakes up, takes the next planned episode from the catalogue and produces it end to end, unattended, with the budget cap and the validator standing in for me.

The way I direct it is by editing one file: a list of albums, hosts and the order I want them in. That's the whole interface. Everything downstream of that is the machine's problem, and the interesting part of the work was deciding exactly how much of it the machine should be allowed to improvise.

The pipeline is open source:github.com/uhhuhyeah/radio-documentaries.

The hosts

Cara, Jools, and the others are not people. They are personas from the SUB/WAVE radio station I also run on my homelab. A written character, a set of dials, and a synthetic voice.

What can go wrong

A model can be confidently wrong, and none of the above makes that impossible. The validator only proves a script is well-formed, not that it's true. The fact-checker is a second opinion from the same kind of system that wrote the thing.

The first episode quoted lyrics that did not exist. They were invented, fluent, and completely wrong, and the episode was re-recorded from scratch once that was caught. The verbatim lyric bank exists because of it. That is roughly how every constraint on this page got here: something went wrong in a specific way, and the fix was to take that decision away from the model rather than ask it more nicely.

So: read the script, follow the claims, and trust the records over the radio.

Why the site looks different every episode

Because the records do. Each episode page is designed around its album with its own palette, its own typography, its own layout. What stays constant is the structure: the same disclosure, the same running order, the same full script, in the same place, every time.