Build · Internal
Nucleus Radio
A personal radio network built on the music I own. Eight stations, programmed and hosted by a local AI agent on my own hardware, that introduce their own songs, run their own shows, and know how the artists in my collection connect to one another.
Challenge
A few years ago my family talked me into a streaming subscription. I came around slowly, then got hooked on the exploration, chasing one artist into the next. After a while Spotify started telling me, every week, how many times I'd played some band, as if I'd gone looking for it, when its own playlists had been rotating the same handful of names past me for days. The exploration dried up. The deep tracks and hidden gems I used to reach for had somehow been algorithmed away from me.
I self-host the rest of my infrastructure, media library included, so I started wondering how to play my own collection the right way, while honoring the music I'd found and worn out during my time renting songs from the streamers. I wanted a station, something with a schedule and a point of view, running on my own collection and my own hardware. And I wanted it to be a place where the rest of what I build could show up, the Tugboat briefings, the Feed and Thread reads, the text-to-speech work, and the generative writing, all of it airing between the songs like segments on a broadcast.
Build
So I built it a piece at a time, and that turned out to be the whole point. First it was just the music on an open port, streaming to a browser. Then a stream URL I could point a radio app at, so it went where I did. Then metadata and album covers, so it carried itself like a station. Then a schedule, with blocks of programming like Mellow Sunday and Overnight Open. Then a TTS DJ that names the songs as they land, and then the blocks too. Then time and weather on the hour. Then a show. Then, slowly, a DJ with a mind of its own, one that watches what plays and when, learns from my scrobbles and my skips, and starts making suggestions.
What started in May as one station shuffling my library became that same station with a schedule, then a schedule with a voice, and it kept going. There are eight stations now. Nucleus Radio is still the flagship, and alongside it sit Country, Classic Rock, New Wave, Alternative, Ambient, and Pop, each with its own identity, its own schedule, and its own place on the dial. Happy Accidents outgrew being a block and became a channel of its own. They all draw from one library of 56,042 tracks by 4,432 artists, and they have aired 239,584 plays between them since the middle of May.

None of that schedules itself, though, and it would be unfair to the machine to say it did. Behind every one of those decisions is Nucleus, the agent that runs my homelab, thinking with a 27-billion-parameter Qwen model on a single GPU in the next room. What I did not plan, and now like best, is that Nucleus ended up wearing a different hat for every job. It is the program director when it proposes next week's schedule for me to approve or send back. It is the DJ when it names a song on the way in. It is the staff writer when Happy Accidents needs an intro connecting a song to something that happened on the same date in another year. It is the one that turns up in Telegram to argue that an artist has earned an hour of their own. One agent, covering a small station's worth of shifts, in the WKRP sense where the same few people do everything.

All of the thinking is local. The writing runs on Qwen on my own GPU, the voice is a Qwen text-to-speech model on the studio box, and nothing about my listening is sent anywhere to be turned into a recommendation I did not ask for. That was the point of leaving the streamers, so it would be strange to rebuild the same arrangement with better manners.

The schedule runs itself once Nucleus has set it. Each block holds a rule, and every time it comes up it reaches back into the same history the station is writing. The station learns from itself. When a Comeback Shuffle digs up a song I hadn't heard in years and airs it this morning, that play lands in the same table the pickers read, so by the afternoon it's back in the pool of recent favorites. What I play shapes what plays next.

One of the blocks writes itself, too. Happy Accidents picks a song with a known release date, digs up something that happened on that same calendar day in a different year, and asks Qwen to write a DJ intro that connects the two with total confidence. The stretch is the joke. If a pairing falls flat, it reaches for a different piece of history and tries again, so the host keeps its footing. A dozen of those become an hour-long episode, rendered ahead of time and aired on its slot, in the same measured voice every week.

The DJ side is where it got personal. Nucleus, the voice of the station, keeps a set of beliefs about what I like, weighted by how it learned them, my own words outranking a guess it drew from a skip. It proposes a week of programming for me to approve, rests the artists I've heard plenty of, and brings back the ones I love. It suggests which artists have earned a block of their own, and it builds blocks that run several related artists together, so a folk lane on Country can move between neighbours instead of sitting on one name.
The newest piece is a map of the collection. Every artist, album, genre, and band member is a node, and the lines between them are the things I actually wanted to see: who played in which band, who turned up on whose record, and which genres sit next to each other. It runs to 12,243 nodes and 17,535 edges, including 4,426 band memberships and 3,145 collaborations. It answers the question the streaming service never would, which is not what else sounds like this, but who else was in the room.

Outcome
All of it comes together at station.gogomito.com, a page that shows what's playing now, what's coming up next, the day's schedule, and the week ahead, with the shows given their own blocks and their own descriptions. There's a Listen live button that plays the stream right on the page, and the same stream drops into any radio app. The collection has its own dashboard, so I can see what each station played most today, yesterday, this week, last week, or across the last month, and the map is there to wander through whenever I want to follow a band member into something I forgot I owned. The scrobbles are honest, too. The station reads the live stream's title and logs each song at the moment it hits the air, a few minutes after it was queued.


Small things that make it feel like a station
What makes it convincing is the small stuff, the things a real station does without thinking about it. Each one took an afternoon.
- Time and weather on the hour, read in the same voice, so the station knows what time it is and what it is doing outside.
- Station IDs written to match the genre. There are 61 of them in rotation. Ambient gets "From morning fog to evening light." Alternative gets "where the b-sides live." Country gets "Roots and rhythm, curated by feel."
- Song introductions that name what just played and what is coming, so the music is hosted rather than served.
- Schedules that Nucleus proposes, a week at a time, for me to approve or send back.
- Artist blocks, and blocks of several artists at once, so a lane can move between neighbours instead of parking on one name. Nucleus is the one that suggests who has earned a block.
- Skip from anywhere. If something is wrong for the moment, one message to Nucleus on Telegram or one tap of an iOS Shortcut moves it along.
- Fourteen kinds of block have aired so far, from top-played hours and comeback shuffles to moods, albums, and artist spotlights.
The whole look is documented as a living design system rendered from the production stylesheet, a dark broadcast field with a pulsing on-air light and 8000 on the dial. It started as music on an open port. It's a station now, and it's still the same project, still getting one more layer whenever I think of one.

The Stack
- A music library on my own hardware, streamed through Icecast and played out by liquidsoap
- Eight stations off one library, each with its own identity, schedule, and mount on the dial
- A schedule engine of blocks, each a rule (shuffle, top-played, mood, comeback, artist, multi-artist, album, on-repeat) that picks fresh every time from the station's own play history
- Broadcast-style interrupts: station IDs, time and weather on the hour, and shows dropped in at track boundaries
- Nucleus, a local agent on Qwen3.6 27B, programming the stations, writing the shows, and answering in Telegram
- A TTS DJ in a single recurring voice, naming songs and blocks, rendered by a Qwen text-to-speech model on my own GPU
- Happy Accidents, a generative show that pairs a song with a same-day historical fact and lets Qwen own the connection
- Honest scrobbling, where the station reads the live stream's title and records each song at the moment it hits the air
- Nucleus, a DJ that learns from scrobbles and skips, proposes a week at a time, and suggests which artists have earned a block
- A knowledge graph of the collection, 12,243 nodes and 17,535 edges across artists, albums, genres, and the people who played on them
- Remote control from anywhere, skipping the current song by Telegram message or iOS Shortcut
- A public page with now-playing, schedule, and week views, a browsable collection with per-station play counts by day and week, a map of the library, a browser Listen-live button, and a living design system rendered from production code
- Mac Mini M4s for development and for the agent, a GPU Linux server running Qwen for inference, and a studio box for text-to-speech and playout, all of it on my own network
