Months after migrating from Wordpress to Hugo, I’m still pretty happy about the switch. Whenever I read about a new Wordpress plugin vulnerability I don’t have to worry, and my pages load really fast.
One function I was missing was the ability to create a “planet”.
In the Before Times, back when people mainly communicated through blogs, a planet was a page that aggregated posts, usually about a single topic, from various blogs. It was an easy way to group posts together, and this blog was part of a number of planets: one for our open source project, one for our local Linux users group, etc.
Planets have gone out of fashion, but I wanted to create one to group together my four blogs. There is this blog, which I consider my “professional” blog. There is my personal blog, a blog about cocktails and a blog about my “toy” car. For those of my three readers who don’t use RSS or a feed aggregator, a planet will provide a single page they can check to see what I have written recently.
When I hosted this blog on Wordpress I used a plugin called PlanetPlanet. That was also the name of the website for the original planet software, but that software was most recently updated 24 years ago in 2006 and the site no longer exists.
I figured it would be an easy job to find a current planet software project and I would use it to create my page. Then the hard work would be to skin it to match my website.
Turns out the hard work was trying to find planet software that I could get to work.
This is a long enough post without going over all of the projects I tried, but I spent an hour or so of my spare time over several days trying to get an existing planet to work.
Since I work at AWS and I have access to amazing Generative AI tools, I finally just said “enough, I’ll create my own”.
It took about 45 minutes.
The model I chose was Anthropic’s Claude Sonnet 3.5. Why? It was the default that popped up. (grin)
The first thing I did was look at the output from my RSS feed reader. It is XML that looks like this:
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>Adventures in Open Source Software</title>
<link>https://www.adventuresinoss.com/</link>
<description>Recent content on Adventures in Open Source Software</description>
<generator>Hugo -- gohugo.io</generator>
<language>en-us</language>
<copyright>Tarus Balog</copyright>
<lastBuildDate>Thu, 24 Jul 2025 07:25:17 +0000</lastBuildDate>
<atom:link href="https://www.adventuresinoss.com/index.xml" rel="self" type="application/rss+xml" />
<item>
<title>Open Source, GenAI and the Post-Truth Society</title>
<link>https://www.adventuresinoss.com/genai-post-truth/</link>
<pubDate>Thu, 24 Jul 2025 07:25:17 +0000</pubDate>
Using this I was able to create a prompt that said to create a Python program that will iterate over a list of feed URLs and extract the channel title as well as the last 10 items based on “pubDate”, along with their titles and links. I then had it merge all of that together, take the 10 most recent and output that in a markdown file.
In Hugo you can create pages under the content/page
directory by creating a subdirectory and putting an index.md
file in it. Then when you build the site it will convert that markdown into HTML, which is awesome since it means it will, out of the box, match the style of my website.
The first iteration worked in that it created a markdown page with a list of my most recent posts. The model made the number of items listed as a variable in a YAML config file, and that was cool since I realized I’d rather have 20 instead of 10.
Speaking of YAML, in order to get markdown pages to build in Hugo you need a bit of YAML at the top. This is called “front matter” and it comes from the book publishing industry where front matter is the title page, copyright page, author name, etc.
Just to make sure this was working I pasted in some front matter and was happy to see it rendered just fine. I wanted a table, not a list, and a simple update to the prompt got me what I wanted, and now all I had to do was get it to add the YAML at the top. It even knew that that part was called “front matter”.
The last change I made was to remove the planet page from the list of updates. Once I had created it, it always showed up at the top, since, of course, it was the most recently modified. I figure that was a bit redundant.
The whole process was pretty painless. The main issue I faced is that my context window timed out for some reason so I had to jump back in and paste in the current code to resume working. No biggie but a little annoying.
I manually changed the code to make a few more of the things I hard coded into parameters, but overall this is exactly what I wanted and was done much more quickly than I could have managed.
My current config.yaml
file looks like this:
# List the RSS feeds to fetch
feed_urls:
- https://tarus.io/index.xml
- https://bananasl.com/index.xml
- https://forgottencocktails.com/index.xml
- https://adventuresinoss.com/index.xml
# Max number of items to display
num_items: 20
# Name of the output file
output_file: index.md
# Title of the index.md page to be created
yaml_title: Planet
# Author of the page
yaml_author: Tarus
# Menu Item Name
yaml_menu: Planet
# Menu Item Weight
yaml_weight: -70
# Menu Item Icon
yaml_icon: planet
and you can see the finished product at https://tarus.io/page/planet/.
For the menu icon (yaml_icon
) you need to put an SVG file in your theme’s assets/icons
directory. Mine is named planet.svg
.
I’ve gone ahead and created my second Github repo so you can get it if this script will be useful for you. Note that since all of my blogs are built by Hugo I just focused on the format of the RSS feed output it creates, and this script will not work if your RSS feed is significantly different.
One final note: I work on a Mac and my version of Python is installed via Homebrew. This script will require two external Python packages: feedparser and pyyaml. I got this to work on a Linux machine and then wanted to get it to work on the Mac, but
pip3 install feedparser
gave me an error. Apparently Homebrew, being written in Python, doesn’t want you messing up its Python install, and if you need to add packages you are supposed to do it in a virtual environment.
I said “pah!” to that and by creating a file called ~/.config/pip/pip.conf
with the contents
[global]
break-system-packages = true
I was then able to add both packages and run hugo-planet locally.