Under Thirty Seconds, About 4,500 Words

Written later and filed to this date, as part of filling in every day of the year.

Before each long talk segment, the engine behind my radio station assembles a prompt for a model, and the prompt contains two instructions that cannot both be followed. Under RULES: “Keep segments under 30 seconds when read aloud.” Under TASK, a few lines down: approximately 4,500 words of natural, flowing monologue, which at a speaking pace is about half an hour. The engine asks for the long kind whenever no listener has written in, so this is not an edge case. It is the default segment.

What it was for

The station is called AI Stereo, and the idea fits on its manifest: radio that never stops, ten shows, always live, all generated. Nine hosts are defined, each with a personality and a voice. The music is tracker modules, the song files of the old demo scene, converted to MP3. Between songs a host talks, and the words come from a model and the voice from a speech engine. Listeners can type into a chat, and the host reads their messages on air, by name.

It has two halves. A Python engine runs the broadcast: it picks tracks, generates the talk in the background, renders the speech and streams the result to an audio server. A web app is the player, with its own API, and it can run the whole station by itself, without the engine, generating segments on demand through a route of its own.

One commit

The repository’s history begins with a single commit: eighty-three files, just under fifteen thousand lines, titled “Initial commit: baseline state before polish pass”. It landed on the evening the loop began. Everything that built the station happened before it, outside version control, and the order in which those sessions made their decisions is not recorded anywhere.

That matters because the baseline contains decisions that disagree, and a history is the thing that would say which one is newer.

The thirty-second rule is one. The engine’s prompt knows six kinds of segment. Four of them fit the rule: a station ID of one or two sentences, a time check, a song intro, a short thought of two to four sentences. The reply to listeners leaves its length unsaid. The sixth is the half-hour monologue, and the rule sits above it in the same prompt.

The hosts are another. They exist twice, once in a YAML file the engine reads and once in a TypeScript table inside the web app’s segment route. The same nine names, in different words. In the engine, the overnight host Nyx speaks slowly, almost whispered, and thinks three in the morning is when the universe is most honest. In the web app she whispers like she is telling you a secret at four.

The instruction file for agents has two of its own. Its list of player features includes a track progress bar, animated every frame. Twelve lines further down, under design constraints: no progress bar, the station is live radio, not on-demand. A progress bar component of a hundred and fifteen lines is in the repository, and nothing imports it. The code took the constraint’s side; the document kept both. The same file says the segment route shells out to the model and the speech engine synchronously; the route itself carries a comment explaining that it calls them asynchronously, to avoid blocking the server for minutes.

What it taught

None of these is a bug in the sense of a crash. Each is two decisions made at different times, frozen into one commit with no times attached. Someone tightened the talk to thirty seconds, and someone later wanted long-form radio, or the other way round. Someone wrote the hosts for the engine and someone rewrote them for the browser. Someone decided a live station has no progress bar after, or before, someone built one. With a log, any of these is a two-minute question. Without one, every reader has to guess which line is current, and an agent reading the instruction file has been told both.

The lesson I took is about when to start the history. Not at the first line of code, which feels early enough, but before the second decision about anything, because the second decision is the first one that can contradict something. A baseline commit is honest about what exists and silent about what superseded what.

Five days and four commits later, the station had gained reactions, requests, polls and a stats page, and the rule was still the first line under RULES. The model is the only reader that meets both instructions on every segment, the rule first and the task second, and nothing tells it which one was written last.


← all writing