Skip to content

Writing a Spec

Eric Ness edited this page Oct 14, 2026 · 3 revisions

A spec is a YAML file that describes one distro. linuxlive checks it against a schema before building anything, so most mistakes show up in seconds:

python -m linuxlive validate path/to/spec.yaml

The validator lists every problem it finds, for example version: 0.1 is not of type 'string'. It works in two passes: first the shape of the file (field names, types, allowed values), then the images and app ids. If the first pass finds problems, fix them and run it again to see the second.

A complete example

schema_version: 1
name: Classroom OS
id: classroom
version: "2026.10"
base: fedora
desktop: kde
apps:
  - firefox
  - libreoffice
  - gcompris
  - tuxpaint
  - inkscape
branding:
  wallpaper: art/classroom-wallpaper.png
  logo: art/classroom-logo.png
  accent_color: "#1565c0"

Fields

Field Required What it does Rules
schema_version yes Version of the spec format. Always 1.
name yes The display name, shown in the boot menu, on the boot splash, in the desktop's About screen and in /etc/os-release. Up to 40 characters: letters, digits, spaces and . _ + -. It must start with a letter or digit and end with a letter, digit or +.
id no The machine-friendly name, used for the hostname, file names and IMAGE_ID in /etc/os-release. 2 to 30 characters: a lower-case letter, then lower-case letters, digits and -. Made from name if you leave it out (see below).
version yes Your distro's version. Up to 20 characters: starts with a letter or digit, then letters, digits and . + ~ -. Put it in quotes, as in "0.1".
base yes The distribution your distro is built from. ubuntu or fedora (see Bases).
desktop yes The desktop environment. gnome, kde or cinnamon (see Desktops).
apps no Apps to preinstall from Flathub. A list of app ids from the Apps table, at most 50, no repeats. Leave it out for no extra apps.
branding yes Your wallpaper, logo and accent colour. See Branding.

Any other field is an error, which catches typos such as desktops: or wallpapper:.

How the id is made from the name

When id is missing, linuxlive lower-cases the name, turns every run of other characters into one -, and cuts the result to 30 characters:

name id
My Distro 2 my-distro-2
Lawn Darts Linux lawn-darts-linux
2048 Arcade os-2048-arcade (an id must start with a letter, so os- is added)

Set id yourself if you want something shorter, such as id: lawndarts.

Bases

base Builds on How it boots live
ubuntu Ubuntu 26.04 LTS, from the official ubuntu:26.04 container image casper, like Ubuntu's own live images
fedora Fedora 44, from Fedora's Atomic (bootc) desktop images dracut dmsquash-live with Fedora's livesys scripts, with SELinux enforcing

Both are 64-bit x86 only. Ubuntu ISOs come out smaller: about 2.7 to 2.9 GiB for the examples, against about 4 to 4.5 GiB for Fedora.

Desktops

desktop Desktop On Ubuntu On Fedora Built and boot-tested in CI
gnome GNOME Ubuntu's minimal GNOME desktop the Fedora Silverblue 44 image Ubuntu only
kde KDE Plasma Plasma with SDDM, Discover, Konsole and Dolphin the Fedora Kinoite 44 image Fedora only
cinnamon Cinnamon Cinnamon with LightDM, on X11 Fedora's base Atomic image plus Cinnamon and LightDM, on X11 both

Every combination compiles and is covered by the unit tests. The two marked as not boot-tested (GNOME on Fedora, KDE on Ubuntu) should work but haven't been booted in CI yet. Every desktop gets a graphical software store with Flathub set up, so people can add more apps in the live session.

Apps

Apps are installed from Flathub, so the same id works on both bases. Use the id in the first column.

App id Name Flathub ID
firefox Firefox org.mozilla.firefox
chromium Chromium org.chromium.Chromium
thunderbird Thunderbird org.mozilla.Thunderbird
libreoffice LibreOffice org.libreoffice.LibreOffice
vlc VLC org.videolan.VLC
gimp GIMP org.gimp.GIMP
inkscape Inkscape org.inkscape.Inkscape
krita Krita org.kde.krita
blender Blender org.blender.Blender
audacity Audacity org.audacityteam.Audacity
obs-studio OBS Studio com.obsproject.Studio
kdenlive Kdenlive org.kde.kdenlive
vscode Visual Studio Code com.visualstudio.code
steam Steam com.valvesoftware.Steam
lutris Lutris net.lutris.Lutris
heroic Heroic Games Launcher com.heroicgameslauncher.hgl
discord Discord com.discordapp.Discord
gcompris GCompris org.kde.gcompris
tuxpaint Tux Paint org.tuxpaint.Tuxpaint
flatseal Flatseal com.github.tchx84.Flatseal

Each app makes the ISO bigger, because its Flatpak runtime comes too. Apps that share a runtime (most KDE apps, for example) cost less together. Some apps, such as Steam, are useful only on real hardware with a network connection.

The list lives in linuxlive/data/catalog.yaml. To add an app, add a line under apps: with a short id, its name and its Flathub ID, then run python scripts/check_catalog.py (it needs a network connection) to confirm the ID exists on Flathub. Pull requests for new apps are welcome.

Branding

Field Required What it is Rules
wallpaper yes The desktop background. PNG or JPEG, at least 1280×720 pixels.
logo yes Your logo on the boot splash, as the system logo that About screens read from /etc/os-release, on GNOME's login screen, and as the KDE application launcher and the Cinnamon menu button. A square PNG of exactly 128, 256 or 512 pixels.
accent_color no The highlight colour. KDE uses it exactly. GNOME picks the nearest of its built-in accent colours. Cinnamon has no accent setting, so it is ignored there. On Ubuntu it also colours the text-mode boot screen. #rrggbb, for example "#e0661f". Put it in quotes: YAML treats an unquoted # as the start of a comment.

Paths are relative to the spec file. If the spec is examples/mydistro.yaml, then assets/mydistro/logo.png means examples/assets/mydistro/logo.png.

Images

For a build on your own machine, any image that meets the rules above works. For a build in GitHub Actions, the wallpaper must also pass CI's screenshot check, which confirms the wallpaper really appears on the booted desktop. The check finds the wallpaper's main colour and then looks for it in screenshots of the running system. So the wallpaper must be:

  • a PNG, not a JPEG;
  • 8-bit and non-interlaced, which is what most editors save by default. Avoid "16 bits per channel" and "interlaced" or "progressive" options;
  • colourful, with one dominant colour. The check ignores greys, near-whites and near-blacks, and takes the most common remaining hue. That colour, give or take a little, must then fill at least a quarter of a screenshot. Large areas of one colour (grass, sky, sea, a bold gradient) pass. A mostly black, white or grey wallpaper fails with "the wallpaper has no dominant colour to look for", and a busy photo where no colour dominates may fail too.

If the "Verify" step fails on the wallpaper, make it more strongly one colour and run the build again.

For the logo, a simple shape with a transparent background reads best at small sizes. Use 256 or 512 pixels for a sharp boot splash.

Where your branding shows up

Place What you see
Boot menu Try <name> <version> and Try <name> <version> (safe graphics)
Boot splash Your logo with a spinner
Desktop and lock screen Your wallpaper, and your accent colour on KDE and GNOME
About screen and /etc/os-release Your name, version, id and logo. PRETTY_NAME reads like Lawn Darts Linux 0.1 (based on Ubuntu 26.04.1 LTS).
Disk label of the DVD or USB stick Your name and version in capitals, for example LAWN_DARTS_LINUX_0_1
GNOME login screen Your logo
KDE application launcher, Cinnamon menu button Your logo

Ubuntu's and Fedora's own logos are their trademarks, so linuxlive replaces them: Fedora builds use Fedora's neutral generic-logos package, and on Ubuntu the dock's Show Apps button uses GNOME's grid icon instead of the Ubuntu logo. Text consoles greet with your distro's name too. The PRETTY_NAME still says which base your distro is built on.

Extras: your own packages, files, scripts and code

Since linuxlive v0.4.0 a spec can add things of its own. All four are optional; the Workshop's Extras step on linuxlive.com writes them for you.

packages:            # from the base's own archive (apt on Ubuntu, dnf on Fedora)
  - htop
files:               # copied into the system, under /etc or /usr
  - src: files/motd
    dest: /etc/motd
    mode: "0644"     # optional; "0755" for a program
scripts:
  build:             # as root while the image is built, with the network
    - scripts/build.sh
  first-boot:        # once, as root, on an installed computer before its login screen
    - scripts/first-boot.sh
  first-login:       # once for each user at their first login, as that user
    - scripts/first-login.sh
repos:               # GitHub code, fetched at an exact commit
  - url: https://github.com/owner/name
    commit: 3f2a9c1e5b7d4e8a9c217d4e5f6a8b904c1d2e3f
    run: make install PREFIX=/usr
Field When it runs Rules
packages In the build, after the desktop and before your files Names from Ubuntu's or Fedora's archive; they differ between the two (vim on Ubuntu, vim-enhanced on Fedora). At most 100.
files Copied with linuxlive's own files Under /etc or /usr, and not over a file linuxlive writes (/etc/linuxlive, /usr/lib/linuxlive, /usr/libexec/linuxlive, os-release). On Fedora, not /usr/local (it lives in /var there). The source must be inside the spec's folder. 20 MB in all.
scripts.build In the build, after repos, before linuxlive's own last step Root, network on, working directory the scripts' folder. The distro's settings are in LL_NAME, LL_ID, LL_VERSION, LL_BASE and LL_DESKTOP. A failing script fails the build.
repos In the build, before scripts.build A public GitHub repository and a full 40-character commit. run runs as root in the unpacked source. Each repo and commit is added to the ISO's package list, so its source can be found.
scripts.first-boot Once, on an installed computer, before its login screen, with the network Root. A failing script is logged in /var/lib/linuxlive/first-boot.log; the others still run. Not in the live session.
scripts.first-login Once for each user, at their first login; in the live session, at every start That user, in their home folder. Logged in ~/.local/state/linuxlive/first-login.log.

Scripts run in the order listed. Start each with #!/bin/sh (or #!/bin/bash) and set -eu. On Fedora the system is an image: a build script can write to /usr and /etc, but anything it puts in /var, /home or /usr/local is not kept.

linuxlive's own branding, installer and boot checks run after your build steps, and the CI checks each extra: every package is installed, every file has your contents, and every script ran and succeeded, in the live session and on the installed disk.

Scripts and repos run as root on every computer that installs your distro. Read them through before you share it. The Library reviews every line before it publishes a distro with code of its own, and linuxlive.com's coming Build it for me takes specs without scripts or repos.

Common errors

Message Fix
version: 0.1 is not of type 'string' Quote the version: version: "0.1".
branding/accent_color: None is not of type 'string' Quote the colour: accent_color: "#2e7d32".
apps: unknown app 'gimp2' (known apps: ...) Use an id from the Apps table.
Additional properties are not allowed ('desktops' was unexpected) That field name is misspelled or doesn't exist.
branding/logo: 'logo.png' is 1920x1080; it must be square, 128, 256, 512 pixels Resize the logo to a square of 128, 256 or 512 pixels.
branding/wallpaper: 'wallpaper.png' is 256x256; it must be at least 1280x720 Use a bigger wallpaper.
branding/wallpaper: file 'wallpaper.png' not found The path is relative to the spec file. Check the folder and the spelling, including upper and lower case.
id: could not derive a valid id from name ... Add an id: line yourself.

Next: build it with Building with GitHub Actions or Building Locally.

Clone this wiki locally