Editions
Based on Fedora 44 COSMIC + Hyprland Image-based Fedora — transactional updates, identical on every machine, one-command rollback.Build it yourself
Based on Fedora 44 Clone the repo and run four commands. Every image is a chain of bootc layers, each an OCI image built from its parent.How an image is assembled
Each layer is an OCI image built FROM its parent, so the four shared layers are built once and reused by all six. The gold leaves are the published images; intermediates are build infrastructure.
Four commands — plain bash and podman
- See the catalog.
./build.sh listEvery image with its DE, description and pin reason.
- Generate Containerfiles.
./build.sh generate allChain-aware Containerfiles under
generated/. - Build the images.
./build.sh build all # --push to publishEach shared layer built once, in dependency order.
- Make an ISO.
./build.sh iso carino-gamingbootc-image-builder (needs
sudo) →output/IMAGE/install.iso.
Classic (non-atomic) images — experimental
./build.sh blueprint IMAGE flattens an image's whole layer chain into an osbuild blueprint for the traditional Workstation backend. It is an export, not a build path — nothing here depsolves or builds it, so you hand it to composer-cli yourself:
./build.sh blueprint carino-general composer-cli blueprints push generated/carino-general/blueprint.toml composer-cli compose start carino-general image-installer
A blueprint is a lossy copy, never an equivalent. COPR packages need the repo configured host-side or the depsolve fails; Flatpaks, static files and post-install scripts are dropped; and a service whose unit ships only in the image's own file tree is omitted from enabled, because osbuild runs systemctl enable during the build and a missing unit fails it. Every omission is listed in the TOML header and warned about on the terminal.
Why only COSMIC and Hyprland?
Because every desktop shipped is a desktop that has to be verified against every purpose, and the combinations nobody tests are the ones that break. One session, built once, means the integration work — tearing control, per-output VRR, no file indexer, no automounter — is done once and inherited by all six images.
Both sessions come from the same layer and the same greeter: pick COSMIC at login for pointer-driven use, or Hyprland when you want tiling. Purposes still declare which session they are pinned to, so adding a second desktop later stays a one-line change rather than a rewrite.
Why atomic, and what do updates look like?
The value of a purpose-built system is the integration — kernel args, service masking, session configuration — and on a mutable system that integration drifts. With bootc the whole OS is one versioned image: every install is identical, updates are transactional, and a bad one is a bootc rollback away.
bootc upgrade # staged, applied on reboot bootc switch <ref> # move between purposes bootc rollback # back to the previous deployment
Add your own purpose
Create one file, config/purposes/<name>.conf — plain bash, sourced by the build system. Four fields are required, the rest are optional:
PURPOSE="mything" # must match the filename DE="cosmic-hyprland" # must match config/layers/de/<DE>.conf PIN_REASON="…" # one line: why this session DESCRIPTION="…" # one line: what it is for PACKAGES="pkg @group" COPRS="owner/project" KARGS="…" SERVICES_ENABLE="a.service" SERVICES_MASK="b.service" FLATPAKS="org.app.Id" POST_SCRIPT="post.sh"
The catalog is derived by scanning config/purposes/*.conf, so ./build.sh list picks it up immediately. Everything that is "just a package list" for an already-installed system lives in Carino Setup instead.