Note: I'm close to splitting the streams into candidate and stable. candidate replaces daily so I'll do the same below. A SimpleStream is a collection of product streams, each product stream contains a list of products, and each product contains a list of versions. For example the MAAS stream contains three product streams, one for Ubuntu, one for CentOS, and one for bootloaders. Each product stream contains a collection of products such as 14.04, 16.04, 18.04, and 20.04. And each product contains a list of versions which are based on the date (20200720.0, 20200720.1, 20200724.0, etc). You are creating a new product stream. SimpleStreams expects this to be a collection of products, even if we only have one product now. As such I think the product stream name should be "com.ubuntu.maas:candidate:1:maas-notifications" and the product name should be "com.ubuntu.com.candidate:1:release-notifications". In the future we can add more products for things like feature-deprecation or image removal. Streams only contain metadata and the only metadata that changes in a stream is the versions. We can try to change that but the stream needs to be readable by older versions of MAAS. I do think the metadata needs to be consistent with content changing in a specific key. This format may work(I didn't test) { "content_id": "com.ubuntu.maas:candidate:1:maas-notifications", "datatype": "notifications", "format": "products:1.0", "products": { "com.ubuntu.com.candidate:1:release-notifications": { "name": "release-notifications", "label", "candidate", "notifications": { [ { "maas_version": "< 2.8", "message": "We\u2019ve released MAAS 2.8. This version supports LXD VM hosts, faster UI and many bug fixes. Find out what\u2019s new in 2.8.\n", "version": "1.0" } ] } } } } Your challenge is create a format that works now and in the future while not breaking previous versions of MAAS. This may require you to add fields which don't make sense. For example every product defines arch, arches, and os MAAS may assume those values are always available. What you should do is create a format, merge it into the MAAS stream, point a running MAAS at the stream, and verify MAAS can still download images and no errors/exceptions have been raised in the logs. You can do that as follows 1. Create a mirror of our stream KEYRING_FILE=/usr/share/keyrings/ubuntu-cloudimage-keyring.gpg IMAGE_SRC=images.maas.io/ephemeral-v3/daily IMAGE_DIR=$HOME/maas-v3-images sstream-mirror --keyring=$KEYRING_FILE \ http://images.maas.io/ephemeral-v3/daily $IMAGE_DIR \ 'arch=amd64' 'release~(centos70|xenial|bionic|focal)' --max=1 --progress sstream-mirror --keyring=$KEYRING_FILE \ http://images.maas.io/ephemeral-v3/daily $IMAGE_DIR \ 'os~(grub*|pxelinux)' --max=1 --progress # sstream doesn't grab the unsigned streams rsync -xavzhP --del --exclude .bzr \ rsync://images.maas.io/maas-images/ephemeral-v3/daily/streams $IMAGE_DIR 2. Create a modifiable copy of the mirror. I use this to save disk space and speed up the copy process src=$(realpath $IMAGE_DIR) dest="$HOME/maas-stream-with-notifications" for file in $(find $src -not -type d); do dest_file="${dest}/${file:${#src}}" mkdir -p "$(dirname $dest_file)" ln -sr "$file" "$dest_file" done for file in $src/streams/v1/*; do # Remove the sym link created above and create a copy we can modify dest_file="${dest}/${file:${#src}}" rm "$dest_file" cp "$file" "$dest_file" done 3. Create your stream meph2-util import release-notifications.yaml $HOME/release-notifications.d 4. Merge it into the copied mirror stream meph2-util merge $HOME/release-notifications.d $HOME/maas-stream-with-notifications 5. Make the stream available over HTTP, I use Python's builtin server for this cd $HOME/maas-stream-with-notifications python3 -m http.server 8000 6. Point MAAS at your stream and verify you can add or remove items without causing any errors or exceptions.