I continue my vibe coding escapade with my first bot: a song-of-the-day Telegram bot that automatically sends a tasty track to subscribers every morning to enjoy with coffee.
Before any bot building, I curated a set of my favorite songs of all time—a revelatory exercise that clarified my tastes: lots of classic rock and folk-rock from the ’60s-‘80s golden era, plus generous helpings of singer-songwriters, soul/R&B, and live tracks. Christmas music (both sacred and secular) bookends the calendar from early December through early January, confirming what I previously discussed: I do love the season. I aimed for artist diversity (no more than six tracks each) and gravitate toward deep cuts—so if you recognize a hit here, it’s because it’s genuinely great. But as Grandpa Brennan was wont to say, de gustibus non est disputandum.
This was a product of Claude (Sonnet 4.5). Admittedly, it didn’t get everything perfect on the first pass, but it sure took my abrasive feedback in stride. The process wasn’t totally linear, but it went something like this:
Fail, fail, fail, success, fail, fail...
Here’s what I ended up with:
_data/daily_song.yml) – My impeccably-curated list of 366 songs2 with date, track title, artist, and YouTube Music song ID.
- date: "12-09"
track: "Christmas Is Coming"
artist: "Vince Guaraldi Trio"
songId: "2--a88MKHZc"
telegram-subscriptions.yml) – Runs daily at 07:00 Pacific, and checks for /subscribe and /unsubscribe messages, adding/removing users to/from _data/telegram_subscribers.json, kicks out confirmation messages.telegram-daily-song.yml) – Runs a half hour later (~07:45), reading today’s song from YAML, sending the selection with clickable link to the track on YouTube Music to all subscribers in the JSON file:
/unsubscribe if you’re not feelin’ my jams.).yml files from my GitHub repo. I’ll subscribe.It’s astonishing that a non-coder like moi can go from idea to fully functional Telegram bot with auto-subscriptions in one sub-100-message chat session—that there’s some right-fine vibe codin’…at least for the standards of late 2025 (I’m sure it’ll seem quaint in a year or two).
— ᴘ. ᴍ. ʙ.
This is the type of arcana that’s over my head and so I’m totally reliant on the LLM to diagnose and fix: Node.js was trying to run our script as an ES Module (basically new JavaScript) (which doesn’t allow require()), but the thing was written in old Javascript (i.e., CommonJS style), so got this error about “require is not defined in ES module scope.” So the fix—after a number of back-and-forths—was renaming the file to .cjs (CommonJS file extension) and wrapped the await in an async function, which told Node: “Hey, this is old-style CommonJS, not modern ES Modules.” 🤓 ↩
Yes, leap year support built in. ↩