Bomb-proof by design, fast on the CachyOS kernel, with a GNOME re-wired for tiling, every codec and driver already in place, and a curated set of creator tools that make it ready for work from minute one. Built on Bluefin DX with a Secure Boot-signed CachyOS kernel.
Curious how all of this is put together? The atomic distro handbook documents the whole build, from this repo's code: kernel replacement and Secure Boot signing, Flatpak strategies, rechunking, CI with the QEMU smoke gate, ISOs, updates — plus every production lesson we learned the hard way. It doubles as a generic guide to building your own bootc-based distro.
🌐 Website · 📥 Install · What it is · What you get · Install · For developers
⚡ Snappier under load — Margine's signed CachyOS/BORE kernel does up to ~1.8× the scheduling throughput and 40–55% lower median / average latency than the stock Fedora kernel, measured on the same laptop.
Median of 4 runs · Framework Laptop 13 (Ryzen 5 7640U) · governor performance · scx off · how this was measured →
Margine is a desktop Linux distribution that follows the immutable /
atomic model: the operating system is shipped as a versioned OCI image,
/usr is mounted read-only, and updates are applied by switching to a
new image rather than by modifying files in place. The same model used
by Fedora Silverblue and the Universal Blue images
(Bluefin, Bazzite, Aurora).
It targets users who want a complete, ready-to-use desktop without configuring the media stack, the kernel, the disk-encryption pipeline, or the GNOME defaults themselves. The trade-off is the standard one of immutable distributions: package installation goes through Flatpak, Toolbox, Distrobox or Homebrew rather than a system package manager; in exchange, atomic upgrades and atomic rollbacks are first-class operations.
| 🎬 Complete media stack from first boot | Mesa freeworld with proprietary codecs (not shipped in Fedora's stock Mesa for licensing reasons), VA-API and VDPAU hardware video acceleration, full ffmpeg with H.264 / H.265/HEVC / AAC / MP3 / AC3 / DTS, and the GStreamer plugin set. DRM content in Firefox- and Chromium-based browsers works without additional setup. |
| ⚡ CachyOS kernel, signed for Secure Boot | Mainline kernel from the bieszczaders/kernel-cachyos COPR, which includes the BORE scheduler (lower-latency desktop response under load) and several upstream-pending performance patches. The kernel image and every kernel module are signed at build time with the Margine MOK; ISO installs stage the public key in Anaconda before the first post-install reboot, while rebases use a one-shot service fallback. Secure Boot remains enabled once the MOK is enrolled and the kernel chain of trust is verified at every boot. Userspace BPF schedulers from the sibling kernel-cachyos-addons COPR ship in base Margine; scx_loader stays off by default and can be enabled explicitly with ujust margine-scheduler <name> or the desktop picker. |
| 🛡 Immutable filesystem, atomic upgrades | The /usr tree is part of the bootc deployment and is mounted read-only. Software updates pull a new OCI image from the registry and stage it as a new deployment; the previous deployment is kept on disk. If the new deployment fails to boot or misbehaves, bootc rollback switches back to the previous one at the next reboot. Daily updates are orchestrated in the background by Bluefin's uupd.timer. |
| 🪟 GNOME with a tiling workflow | Stock GNOME Shell, configured with the o-tiling extension (binary-tree auto-split inspired by Hyprland) and a Hyprland-style keybinding set: Super+H/J/K/L to move focus, Super+Return for the terminal, Super+E for Files, Super+period for the emoji picker, and Super+number for workspaces (the full, conflict-resolved set lives in the keyboard reference). Hide Cursor, Caffeine, and the Smile emoji-picker companion are added to the default Bluefin extension set; Blur My Shell, Search Light and LogoMenu are removed. None of this is enforced — the Extensions Manager remains fully functional and any choice is reversible. |
| 📦 Curated application set, mostly instant | ~29 Flatpak apps are baked into /var/lib/flatpak at install time by the Anaconda kickstart (Bazzite installer-image pattern — see installer/Containerfile): Zen Browser, Thunderbird, Bitwarden, LibreOffice, Extension Manager, GNOME suite (Calculator, Calendar, clocks, Contacts, Maps, Weather, TextEditor, baobab, Characters, Logs, font-viewer), viewers (Loupe, Papers, Showtime, Snapshot, SoundRecorder), audio (Audacity, EasyEffects, Reaper, g4music, Blanket), Pinta, Apostrophe, Fragments. These are ready in Activities at first login, no first-boot wait. Four heavy creative apps (GIMP, Inkscape, darktable, OBS Studio) arrive within 5-15 min of first boot via flatpak-preinstall.service; a GNOME notification appears at first login telling the user they're coming, and a second notification when they're ready. Visual Studio Code is inherited from Bluefin DX (Microsoft repo, dev-container and remote-ssh extensions). |
| 🛠 Creator-tier system tools | The base image also ships mangohud (Vulkan/OpenGL overlay for monitoring CPU/GPU/RAM during DaVinci/Blender renders, OBS recording, ffmpeg encoding), goverlay (Qt GUI to configure MangoHud), and steam-devices (udev rules for USB game controllers — useful for any creator using a controller as jog wheel / foot pedal). Plus the upstream Bluefin DX set: GameMode, input-remapper, tuned, tuned-ppd. |
| ⚙️ Opt-in CPU scheduler picker | Activities -> "Margine CPU Scheduler" opens a Zenity picker populated from scxctl list, including an Off entry that stops scx_loader and returns to kernel BORE. Right-click quick actions cover shipped schedulers such as scx_lavd, scx_bpfland, scx_rusty, scx_flash, scx_cosmos, and scx_rustland. CLI equivalent: ujust margine-scheduler <name>. |
| 🎮 Optional gaming layer (two flavours) | ujust margine-gaming installs gamescope + vkBasalt as rpm-ostree layered RPMs and Steam, Lutris, Heroic, Bottles, Protontricks, ProtonPlus, RetroArch as Flatpaks. One command, a reboot, gaming is on. For maximum Proton/Wine compatibility (anti-cheat titles, VR, NVIDIA proprietary side-by-side) ujust margine-gaming-native instead layers Steam + Lutris + RetroArch as native RPMs — better compatibility at the cost of +30-60s per update (the daily auto-update and ujust margine-update both re-apply the layer). ujust margine-gaming{,-native}-remove rolls either variant back. |
| 🤖 Optional AI workflow | ujust margine-ai installs Alpaca — a Flatpak GUI for local LLMs that bundles its own Ollama backend, no host install or daemon-running required. Pick a model from inside Alpaca on first launch (recommended starters: llama3.1:8b for general use, qwen2.5-coder:7b for code, phi3.5:3.8b for CPU-only). Power users who want the RamaLama CLI in a sandbox get instructions printed by the recipe. ujust margine-ai-remove undoes it. |
| ☁️ Rootless app helpers | ujust install-koofr (alias ujust koofr) installs the Koofr Desktop sync client natively in $HOME — no Flatpak/RPM/Distrobox, because Koofr ships only a self-updating tarball, so it stays out of the read-only image and updates itself. It autostarts hidden to the system tray at login (the binary's -silent flag), while launching it from the applications menu opens the window normally. ujust install-koofr remove uninstalls it. |
| 🔒 Disk encryption and TPM2 | Anaconda installs default to LUKS2 with a strong passphrase. After install, TPM2 unlock can be enrolled with systemd-cryptenroll, keeping the passphrase as recovery. Procedure documented in docs/spec/07-secure-boot-tpm2.md. |
| 🧪 Verified build pipeline | Every release passes three checks before it can be installed: image-internals inspection (a "candidate" tag is published first), boot test in QEMU, and only then promotion to the public :stable tag. A release that doesn't boot in a virtual machine never becomes the one your computer pulls. |
| 📚 Online + offline documentation | Activities -> "Margine documentation" opens the live docs when the site health check passes and falls back to the local mirror at /usr/share/margine/offline-docs/ when the machine is offline. The current install recommendation lives at https://margine.dev/docs/install-status. |
| 🗂 Organized application folders | GNOME's activities grid is organized into six folders: Office, Graphics, Photography, Audio, Video, System. High-frequency apps (browser, mail, files, terminal, code editor) stay at the top level for one-click access. Editable in the declarative spec. |
As of 2026-06-11, the primary install path is the Margine live ISO: it boots a full GNOME live session with Margine already baked in — try it, then install from the desktop with the graphical installer. The ISO is built with Titanoboa (ADR-0008) and was validated end to end in a VM. Rebasing from Bluefin DX remains fully supported as the alternative. Current status: https://margine.dev/docs/install-status.
Gaming is a one-command layer on top — ujust margine-gaming after
first boot installs gamescope + vkBasalt and the seven gaming Flatpaks
(Steam / Lutris / Heroic / Bottles / Protontricks / ProtonPlus /
RetroArch). The previous separate Margine Gaming ISO + OCI image were
retired 2026-06-06 to cut maintenance — same gaming stack, fewer moving
parts.
- OCI image:
ghcr.io/daniel-g-carrasco/margine:stable - Identifies as:
VARIANT_ID=margine - ISO releases (Internet Archive):
archive.org/details/margine-live-iso-YYYYMMDD
- Open the Margine site Install section
for the latest dated identifier, or browse the full
Internet Archive collection
directly. Each release is available as a
.torrent(recommended) and as a direct HTTP mirror;SHA256SUMSis published alongside. - Write the ISO to a USB stick and boot it — you land in a complete Margine live desktop you can try without touching the disk.
- Start Install Margine from the desktop (Anaconda Web UI): UEFI recommended, LUKS2 on the root disk, Btrfs (the default). Note: with Secure Boot enabled the live kernel needs the Margine key enrolled first — easiest today is installing with Secure Boot off and re-enabling it after the first-boot MOK enrollment (smoother enroll-from-ISO flow is planned).
- Reboot when the installation completes. MOK Manager appears before
the installed system starts; enroll the key with passphrase
margine-os, then reboot into Margine. - Apply the user-state once:
This runs the idempotent
ujust margine-bootstrap
margine-configure-*helpers in sequence: home layout, GNOME extensions, keybindings, appearance, default applications, app folders. Log out and back in to refresh GNOME Shell.
Step-by-step walkthrough with screenshots: https://margine.dev/docs/install-iso.
Fully supported alternative, handy if you already run a Fedora Atomic system. Install Bluefin DX stable, boot it once, then switch to the Margine image:
rpm-ostree rebase ostree-image-signed:docker://ghcr.io/daniel-g-carrasco/margine:stable
systemctl rebootAfter the reboot, two more one-time steps:
- Enroll the Margine signing key into Secure Boot. After rebasing,
mok-enroll.servicesubmits the request during the first Margine boot. Reboot once more; a blue/grey screen called MOK Manager appears automatically. ChooseEnroll MOK->Continue->Yes, type the passphrasemargine-oswhen prompted, and reboot. From this point on the kernel boots normally under Secure Boot and you will not see this screen again. Full walkthrough with the exact screen-by-screen flow is at https://margine.dev/docs/install-iso. - Run
ujust margine-bootstrap.
Margine ships two recipes for the gaming stack; pick one based on how seriously you game.
Default (Flatpak — for occasional gamers):
ujust margine-gaming # gamescope + vkBasalt as RPMs + every
# launcher (Steam, Lutris, Heroic,
# Bottles, Protontricks, ProtonPlus,
# RetroArch) as Flatpak. Asks before
# touching anything.
systemctl reboot # required to activate the rpm-ostree
# layer.Trade-off: Flatpak Steam is sandboxed (good for upgrades, bad for some anti-cheat / VR / Mesa-version-matching scenarios).
Native (RPM-layered — for daily / serious gamers):
ujust margine-gaming-native # Steam + Lutris + RetroArch as native
# RPMs (RPM Fusion). Heroic, Bottles,
# Protontricks, ProtonPlus stay
# Flatpak (no official RPM).
systemctl rebootTrade-off: maximum Proton/Wine compatibility (anti-cheat works,
VR/Steam Link/USB controllers integrate cleanly, Mesa always
matches the system), at the cost of +30-60s per update (the daily
auto-update and ujust margine-update both re-apply the layer).
Recommended if you run EAC/BattlEye titles,
VR headsets, or NVIDIA proprietary + Mesa-git side-by-side.
To remove either:
ujust margine-gaming-remove # for the Flatpak variant
ujust margine-gaming-native-remove # for the native variant
systemctl rebootGame streaming (Sunshine, experimental):
Stream games from this machine to a Moonlight client (laptop, tablet, TV, another PC). The atomic equivalent of Bazzite's setup-sunshine:
ujust margine-sunshine # Sunshine (Moonlight host) as a Flatpak,
# with uinput + firewall ports wired up.
ujust margine-sunshine-remove # roll it backThen open https://localhost:47990 to set credentials and pair. Experimental: not yet validated end to end.
The result of either is a layered (not ostree-canonical) deployment —
rpm-ostree status will show LayeredPackages: gamescope vkBasalt
(or the larger list for the native variant), and every update
re-applies the layer on top of the new base (~30-60s extra for the
Flatpak variant, ~60-90s for native). Update a layered system with the
daily auto-update or ujust margine-update — not a raw bootc upgrade, which refuses a client-layered deployment (Deployment contains local rpm-ostree modifications); and avoid rpm-ostree reset, which removes the whole layer. The recipe prints the same
trade-off warning before the install prompt.
mokutil --sb-state # SecureBoot enabled
uname -r # 7.0.x-cachyos*.fc44.x86_64
margine-validate-atomic-layout
margine-validate-cachyos-kernelEvery pushed image is signed with cosign by digest. To verify it (before rebasing, or any time):
cosign verify \
--key https://raw.githubusercontent.com/daniel-g-carrasco/margine-image/main/secrets/cosign.pub \
ghcr.io/daniel-g-carrasco/margine:stableA valid signature prints the verified payload and exits 0; a missing or
bad signature exits non-zero. The signing public key lives in this repo at
secrets/cosign.pub (the private half never leaves CI
— it signs in a separate least-privilege job, see
.github/workflows/build.yml).
Full stack summary
Base image: Bluefin DX (stable), Universal Blue's developer-oriented Bluefin variant. Built on Fedora Silverblue 44. Includes Mesa freeworld, the full virt stack (libvirt, qemu-kvm, virt-manager, swtpm, edk2-ovmf), container tooling (podman, docker, distrobox, toolbox), Visual Studio Code, Cockpit, Tailscale, bpftrace, sysprof. Inherited unchanged by Margine.
Kernel: CachyOS mainline from
bieszczaders/kernel-cachyos.
vmlinuz signed with sbsign; every .ko* module signed with
sign-file. ISO installs submit the MOK import request from Anaconda
before the first post-install reboot; mok-enroll.service remains for
rebases and missed-prompt recovery. Userspace sched_ext BPF schedulers (the
scx-scheds package from
bieszczaders/kernel-cachyos-addons)
are installed in the base image: the ujust margine-scheduler recipe
uses scxctl list for the shipped scheduler set and switches at
runtime through scx_loader. The gaming variant (gamescope, vkBasalt, the
gaming Flatpaks) is opt-in via ujust margine-gaming on top of the
same kernel — no separate image.
Build pipeline: GitHub-hosted ubuntu-24.04 runner (the
self-hosted PVE builder was decommissioned 2026-06-01 after a ZFS
spacemap corruption took the host down). The image is built with a
direct sudo -E buildah build shell call — the same pattern Bazzite
uses, not the redhat-actions/buildah-build action — then run
through hhd-dev/rechunk so
the OCI layers stay reproducible across upstream base rebases. All
GitHub Actions are SHA-pinned (e.g. actions/upload-artifact@<sha> # v7.0.1) rather than tag-pinned, to avoid the tj-actions/changed- files-style supply-chain attack vector. Cosign signs the pushed
manifest by digest (not by tag) in a separate short job, so a
sign-step failure costs ~1 min to re-run instead of redoing the
full ~25-min image build. See the inline history comment at the
top of .github/workflows/build.yml
for the full rationale.
Titanoboa migration: complete since 2026-06-11 (ADR-0008 Phase 5); see
ADR-0008.
Pin: daniel-g-carrasco/titanoboa@cce73fc (our fork of upstream ublue-os/titanoboa@5c457c3d + 3 carried patches; see .github/workflows/build-disk.yml).
Enabled GNOME extensions: AppIndicator Support, Bazaar Integration, Dash to Dock, Gradia Integration, GSConnect (from Bluefin); o-tiling, Hide Cursor, Caffeine, and the Smile emoji-picker companion (added by Margine). Blur My Shell, Search Light and LogoMenu (Bluefin defaults) are removed.
Preinstalled Flatpak apps: Zen Browser, Bitwarden, LibreOffice, g4music, Smile (emoji picker), GIMP, Inkscape, darktable, Audacity, OBS Studio, EasyEffects, Reaper, Apostrophe.
Security: Secure Boot via the Margine MOK; LUKS2 disk encryption;
optional TPM2 auto-unlock via systemd-cryptenroll; cosign
signature on the registry image.
Update orchestration: daily via uupd.timer (inherited from
Bluefin), which auto-detects the deployment and runs bootc upgrade
(unlayered) or rpm-ostree upgrade (when packages are layered, e.g.
gaming-native) — staged, applied on next reboot. flatpak update,
brew upgrade, distrobox upgrade also orchestrated by uupd. Manual
update: ujust margine-update (same auto-detection). Rollback via the
boot menu or bootc rollback.
CI workflows (under .github/workflows/):
build.yml— builds the image, runs Layer A guardrails, publishes:candidate.smoke-boot.yml— boots the candidate in QEMU; on success, promotes to:stable.build-disk.yml— builds qcow2 + anaconda-iso for the single Margine flavour (2 jobs in parallel), thenpublish_iauploads the ISO to Internet Archive (BitTorrent + 3 HTTP mirrors, seeded forever) under the identifiermargine-anaconda-iso-YYYYMMDD.
The declarative spec, configuration helpers, and validators live in
docs/spec/ and build_files/40-spec-scripts/.
This repo (margine-image) is also the build pipeline: Containerfile,
build scripts, CI workflows. To change what Margine ships — which
apps, which extensions, which keybindings — edit
declarations/margine-atomic.yaml in the spec repo. The build picks
up the new versions automatically.
Architectural decisions, postmortems, and the roadmap are documented
under docs/spec/ in this repo.
- Bluefin — base image and source of most of what Margine ships.
- Universal Blue — image-template,
CI patterns,
uupd. - CachyOS — scheduler and kernel patches.
- o-tiling — the binary-tree tiling engine that powers Margine's whole GNOME tiling workflow. No donations page — star it, file good bugs, contribute.
- Origami Linux — reference for the MOK-signing kernel script.
- MorrOS — CI workflow patterns.
- hhd-dev/rechunk — ostree rechunking action.
- Internet Archive — permanent mirror and BitTorrent seed for the ISOs.
Apache-2.0.




