<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Distros on Ivan Molodetskikh’s Webpage</title>
    <link>https://bxt.rs/tags/distros/</link>
    <description>Recent content in Distros on Ivan Molodetskikh’s Webpage</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <lastBuildDate>Fri, 05 Jun 2026 15:37:00 +0300</lastBuildDate><atom:link href="https://bxt.rs/tags/distros/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Using Fedora Silverblue for Compositor Development</title>
      <link>https://bxt.rs/blog/using-fedora-silverblue-for-compositor-development/</link>
      <pubDate>Fri, 05 Jun 2026 15:37:00 +0300</pubDate>
      <guid>https://bxt.rs/blog/using-fedora-silverblue-for-compositor-development/</guid><description>&lt;p&gt;I&amp;rsquo;ve been using &lt;a href=&#34;https://fedoraproject.org/atomic-desktops/silverblue/&#34;&gt;Fedora Silverblue&lt;/a&gt; on my desktop and laptop for the past, what, five years?
Silverblue is Fedora&amp;rsquo;s main atomic variant, a spiritual counterpart to Fedora Workstation.
I also make &lt;a href=&#34;https://github.com/YaLTeR/niri&#34;&gt;niri&lt;/a&gt;, a scrollable-tiling Wayland compositor.
In other words, a core system component that you cannot properly test from inside a container or VM&amp;mdash;you really want it directly on the host.
So, why would I choose an&amp;hellip; immutable distro?
How does that even work?&lt;/p&gt;
&lt;figure&gt;
    &lt;a href=&#34;https://bxt.rs/blog/using-fedora-silverblue-for-compositor-development/blur.png&#34;&gt;
    
    &lt;img src=&#34;https://bxt.rs/blog/using-fedora-silverblue-for-compositor-development/blur.png&#34; /&gt;
    
    &lt;/a&gt;
    &lt;figcaption&gt;
        &lt;p&gt;Fedora Silverblue makes a frequent occurrence in my &lt;a href=&#34;https://github.com/niri-wm/niri/releases&#34;&gt;niri release notes&lt;/a&gt; screenshots.&lt;/p&gt;

    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Atomic distributions have been slowly rising in popularity.
Their main selling point is reliability: upgrades work by swapping the old system for the new one in one go across a reboot, rather than modifying the files in-place.
Package conflicts and other errors are caught at the time of assembling the new version (in a separate folder), and therefore cannot break your running system.
And if a successful update turns out buggy, atomic distros let you simply reboot back into the old version and keep using it as if nothing happened.&lt;/p&gt;
&lt;p&gt;This &amp;ldquo;being able to reboot back&amp;rdquo; thing becomes even cooler once you realize that it works even across major distro upgrades!
When the next Fedora Beta rolls around, I can just &lt;em&gt;rebase&lt;/em&gt; my system on top of it to kick the tires, and if anything is broken, I can simply &lt;em&gt;reboot back&lt;/em&gt; to stable Fedora (and then undo the rebase).&lt;/p&gt;
&lt;p&gt;This is like learning about source code version control.
A big weight off your mind any time you want to mess around with your OS.
You can just &lt;em&gt;go back&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;So, by now there are plenty of atomic distributions to choose from.
There&amp;rsquo;s &lt;a href=&#34;https://fedoraproject.org/atomic-desktops/&#34;&gt;a whole host of Fedora atomic desktops&lt;/a&gt;, &lt;a href=&#34;https://www.endlessglobal.com/foundation/access/operating-system&#34;&gt;Endless OS&lt;/a&gt;, the gaming-focused &lt;a href=&#34;https://bazzite.gg/&#34;&gt;Bazzite&lt;/a&gt; and &lt;a href=&#34;https://universal-blue.org/&#34;&gt;other Universal Blue images&lt;/a&gt;.
&lt;a href=&#34;https://os.gnome.org/&#34;&gt;GNOME OS Nightly&lt;/a&gt; is atomic, as well as &lt;a href=&#34;https://store.steampowered.com/steamos&#34;&gt;SteamOS&lt;/a&gt; powering the Steam Deck.
Many of these are built with &lt;a href=&#34;https://ostreedev.github.io/ostree/&#34;&gt;OSTree&lt;/a&gt; which is something of a &amp;ldquo;git for operating system binaries&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;But, you may ask.
What if I &lt;em&gt;develop&lt;/em&gt; these operating system binaries?
Aren&amp;rsquo;t atomic distros immutable and all, how do I test my work?&lt;/p&gt;
&lt;p&gt;Turns out, this is not a problem at all!
In fact, the same tech that lets you &lt;em&gt;go back&lt;/em&gt; after an update can also let you freely tinker with your host system and safely &lt;em&gt;go back&lt;/em&gt; after a reboot.
I&amp;rsquo;d say that thanks to this ability, atomic distributions provide even more benefit for system component developers than for others, given that they&amp;rsquo;re constantly testing changes that may break their install.&lt;/p&gt;
&lt;p&gt;So, let me show you how I do compositor development on Fedora Silverblue.
We&amp;rsquo;ll start with toolbox where most of the work happens, then proceed to the fun stuff.&lt;/p&gt;
&lt;h2 id=&#34;toolbox&#34;&gt;Toolbox &lt;a href=&#34;https://bxt.rs/blog/using-fedora-silverblue-for-compositor-development/#toolbox&#34; class=&#34;anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;On your immutable host system, you need a place where you can install the development environment.
Fedora Silverblue comes pre-installed with &lt;a href=&#34;https://containertoolbx.org/&#34;&gt;Toolbox&lt;/a&gt;, which provides just that&amp;mdash;a terminal in a normal, mutable Fedora where you can &lt;code&gt;sudo dnf install&lt;/code&gt; to your heart&amp;rsquo;s content.&lt;/p&gt;
&lt;p&gt;Under the hood, it&amp;rsquo;s just a &lt;a href=&#34;https://podman.io/&#34;&gt;podman&lt;/a&gt; container with a whole range of things auto-mounted from the host: the Wayland socket, networking, devices, D-Bus, and everything else needed for apps to &amp;ldquo;just work&amp;rdquo; as much as possible from inside the container.
You can even interact with it through podman commands:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;┌ ~
└─ podman ps
CONTAINER ID  IMAGE                                         COMMAND               CREATED       STATUS         PORTS       NAMES
6ceccce5581e  registry.fedoraproject.org/fedora-toolbox:44  toolbox --log-lev...  2 months ago  Up 41 minutes              fedora-toolbox-44
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Most of your development work happens here.
Install all the libraries, compilers, editors, &lt;a href=&#34;https://microsoft.github.io/language-server-protocol/&#34;&gt;LSPs&lt;/a&gt;, debuggers, and the rest of the kitchen sink.
Since all of this resides inside the same container, it can all talk to each other and work together.&lt;/p&gt;
&lt;p&gt;One slightly annoying detail is that since your fully-configured editor is inside the toolbox, you can&amp;rsquo;t use it to edit files accessible only on the host (e.g. configs in &lt;code&gt;/etc&lt;/code&gt;&amp;mdash;the system inside the toolbox has its own files there), but that is honestly a fairly minor problem in practice.
Fedora Silverblue comes with &lt;code&gt;nano&lt;/code&gt;, which works, and if editing host-only files is a frequent occurrence for you, you can always &lt;code&gt;rpm-ostree install&lt;/code&gt; a more featureful editor.
Another annoying problem is that currently, toolbox &lt;a href=&#34;https://github.com/containers/toolbox/issues/1400&#34;&gt;prevents SIGHUP from reaching apps&lt;/a&gt;, so if you run &lt;a href=&#34;https://helix-editor.com/&#34;&gt;your favorite editor&lt;/a&gt; then close the terminal window, it will happily keep running in the background (along with all its &lt;a href=&#34;https://rust-analyzer.github.io/&#34;&gt;rust-analyzer&lt;/a&gt;s and such, eating several gigabytes of RAM).&lt;/p&gt;
&lt;p&gt;So, running things in a toolbox works perfectly well for most development.
CLI tools will run fine, GUI apps will run fine, you can build and install libraries inside the toolbox and test them on apps inside the same toolbox.
Even with Wayland compositors, most of them can run as a window (&lt;code&gt;gnome-shell --nested&lt;/code&gt;, or simply &lt;code&gt;sway&lt;/code&gt; or &lt;code&gt;niri&lt;/code&gt;), which is enough to test the majority of the code base.&lt;/p&gt;
&lt;p&gt;Moreover, &lt;a href=&#34;https://github.com/containers/toolbox/pull/997&#34;&gt;since ~2023&lt;/a&gt;, toolbox exposes everything necessary to run compositors on a TTY directly.
You can switch to a different VT with &lt;kbd&gt;Ctrl&lt;/kbd&gt;&lt;kbd&gt;Alt&lt;/kbd&gt;&lt;kbd&gt;F3&lt;/kbd&gt;, &lt;code&gt;toolbox enter&lt;/code&gt;, then start a compositor, and it will work as is.
This way you can test different input devices directly (trackpad, tablet, touchscreen), test monitor and GPU handling, do proper performance profiling, and so on.
Just remember to install a terminal and some GUI apps inside the toolbox because launching the host ones into a toolbox compositor is a bit annoying.&lt;/p&gt;
&lt;p&gt;While toolbox is somewhat Fedora-specific, for everything else there&amp;rsquo;s &lt;a href=&#34;https://distrobox.it/&#34;&gt;distrobox&lt;/a&gt;.
It&amp;rsquo;s a separate project, but by and large has the same idea&amp;mdash;let you easily install different distros as podman containers with automatic host integration.
I mainly use it to build or test things on &lt;a href=&#34;https://archlinux.org/&#34;&gt;Arch&lt;/a&gt;, but I imagine most of what I wrote above works just as well with distrobox.&lt;/p&gt;
&lt;p&gt;What if this isn&amp;rsquo;t enough, though?
Say, you&amp;rsquo;re working on a component like NetworkManager or systemd that must run on the host system.
Or, you want to be able to &lt;em&gt;log in&lt;/em&gt; to a test build of your compositor along with the rest of the full desktop session.
Let&amp;rsquo;s look at an easy way to do that.&lt;/p&gt;
&lt;h2 id=&#34;unlocking-the-host&#34;&gt;Unlocking the host &lt;a href=&#34;https://bxt.rs/blog/using-fedora-silverblue-for-compositor-development/#unlocking-the-host&#34; class=&#34;anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Run &lt;code&gt;sudo ostree admin unlock&lt;/code&gt;, also known as &lt;code&gt;rpm-ostree usroverlay&lt;/code&gt;.&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;
This will mount a mutable overlay filesystem over &lt;code&gt;/usr&lt;/code&gt; for you to play around in.
The overlay will last until the next reboot, at which point you&amp;rsquo;ll be back to a clean working system.&lt;/p&gt;
&lt;p&gt;Now you can simply &lt;code&gt;sudo cp&lt;/code&gt; your development build into &lt;code&gt;/usr/bin&lt;/code&gt; and restart the service you&amp;rsquo;re testing.&lt;/p&gt;
&lt;p&gt;This also works with libraries.
Say, you want to test your changes in &lt;a href=&#34;https://gitlab.gnome.org/GNOME/gtk&#34;&gt;GTK&lt;/a&gt; against apps installed on the host.&lt;sup id=&#34;fnref:3&#34;&gt;&lt;a href=&#34;#fn:3&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;
Build it inside the toolbox, then copy the binaries to the (unlocked) host, and there you have it.
Binary compatibility is generally not a concern since Silverblue updates daily and very closely matches the regular Fedora that you build against inside the toolbox.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sudo cp&lt;/code&gt; is not a proper substitute for installing though, and you cannot use it as easily for many projects.
So let&amp;rsquo;s get some proper tooling on the host.&lt;/p&gt;
&lt;h2 id=&#34;layering-development-tooling&#34;&gt;Layering development tooling &lt;a href=&#34;https://bxt.rs/blog/using-fedora-silverblue-for-compositor-development/#layering-development-tooling&#34; class=&#34;anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Contrary to an apparently widespread belief, you can install packages on the host in Silverblue.
This is called &lt;em&gt;layering&lt;/em&gt; and is a perfectly normal and supported operation, primarily useful for adding system components such as terminals, window managers, or GPU drivers.
Running &lt;code&gt;rpm-ostree install alacritty&lt;/code&gt; will cause rpm-ostree to install, or &lt;em&gt;layer&lt;/em&gt;, this package on top of the base Silverblue image every time it updates.
After a reboot, you&amp;rsquo;ll have Fedora with &lt;a href=&#34;https://alacritty.org/&#34;&gt;Alacritty&lt;/a&gt;, as if you installed it on a regular, non-atomic system.&lt;/p&gt;
&lt;p&gt;If the change is sufficiently non-invasive, running &lt;code&gt;sudo rpm-ostree apply-live&lt;/code&gt; lets you skip the reboot and have a newly installed program available right away.&lt;sup id=&#34;fnref:4&#34;&gt;&lt;a href=&#34;#fn:4&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;4&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;When should you layer (as opposed to installing in a toolbox)?
Layering is more annoying and slower, and misses the benefit of throwing away a toolbox to start fresh.
So, I limit layering to programs that &lt;em&gt;must&lt;/em&gt; run on the host, and tools that I frequently need on the host.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s my list of layered packages that&amp;rsquo;s been more or less unchanged for several Fedora releases:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;┌ ~
└─ rpm-ostree status
State: idle
Deployments:
  fedora:fedora/42/x86_64/silverblue
                  Version: 42.20250824.0 (2025-08-24T02:55:42Z)
               BaseCommit: d58dc92e5b05b6a95a0d9352edd864f1292c1883b9b32ac2e6f0af1a2263395a
             GPGSignature: Valid signature by B0F4950458F69E1150C6C5EDC8AC4916105EF944
                     Diff: 12 upgraded
      RemovedBasePackages: firefox firefox-langpacks 142.0-1.fc42
          LayeredPackages: alacritty distrobox dnf fastfetch fish foot fuzzel gamescope gdb
                           gnome-console google-roboto-fonts htop hyprlock i3 kanshi labwc
                           langpacks-ru lm_sensors lxqt-policykit mako nautilus-python
                           netconsole-service niri perf quickshell-git rocminfo strace sway
                           syncthing sysprof tmux trash-cli waybar wlsunset
            LocalPackages: edid-asus-1-1.fc34.noarch
                Initramfs: --include /etc/initramfs-overlay /
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In this output, you can find:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I &lt;em&gt;removed&lt;/em&gt; Firefox with &lt;code&gt;rpm-ostree override remove&lt;/code&gt;—I prefer the &lt;a href=&#34;https://flathub.org/apps/org.mozilla.firefox&#34;&gt;official build from Flathub&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Terminals (must run on the host to access the full host filesystem&lt;sup id=&#34;fnref:5&#34;&gt;&lt;a href=&#34;#fn:5&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;5&lt;/a&gt;&lt;/sup&gt;): alacritty, foot, gnome-console. My preferred shell: fish. Tool I frequently need: tmux.&lt;/li&gt;
&lt;li&gt;Services and tools that I want to run without a toolbox: syncthing, distrobox, netconsole-service, trash-cli, htop, fastfetch, lm_sensors, rocminfo.&lt;/li&gt;
&lt;li&gt;Desktop components: fuzzel, hyprlock, i3, kanshi, labwc, lxqt-policykit, mako, quickshell-git, sway, waybar, wlsunset.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;edid-asus&lt;/code&gt; and the &lt;code&gt;initramfs-overlay&lt;/code&gt; provide the EDID for one of my monitors after AMDGPU &lt;a href=&#34;https://bugzilla.kernel.org/show_bug.cgi?id=201497&#34;&gt;broke it&lt;/a&gt; back in kernel 4.19.&lt;sup id=&#34;fnref:6&#34;&gt;&lt;a href=&#34;#fn:6&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;6&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Along with these, I layer several development tools: gdb, strace, perf, sysprof.
These frequently come in handy whenever I need to debug or profile programs running on the host (or do full-system profiling in case of &lt;a href=&#34;https://gitlab.gnome.org/GNOME/sysprof&#34;&gt;Sysprof&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;And then there&amp;rsquo;s dnf.
What?&lt;/p&gt;
&lt;h2 id=&#34;layering-dnf&#34;&gt;Layering dnf &lt;a href=&#34;https://bxt.rs/blog/using-fedora-silverblue-for-compositor-development/#layering-dnf&#34; class=&#34;anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;What is dnf, a regular Fedora package manager, doing on an immutable Silverblue host system?
By itself, it&amp;rsquo;s not very useful indeed, since it can&amp;rsquo;t modify &lt;code&gt;/usr&lt;/code&gt;.
(Though, it can &lt;code&gt;dnf copr enable&lt;/code&gt;, which is convenient. &lt;code&gt;rpm-ostree copr&lt;/code&gt; when?)&lt;/p&gt;
&lt;p&gt;Where dnf on the host shines, however, is when you combine it with &lt;code&gt;sudo ostree admin unlock&lt;/code&gt;.
After unlocking, you can install whatever you need in the moment with dnf.
This is much faster than rpm-ostree, never requires a reboot, and in fact a reboot makes it all clean up and go away, since it was all in a transient &lt;code&gt;/usr&lt;/code&gt; overlayfs.&lt;/p&gt;
&lt;p&gt;Example workflows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;dnf debuginfo-install&lt;/code&gt; to debug/profile something on the host with symbols, report crashes, etc.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dnf install&lt;/code&gt; some host-only program to test it. Follow up with &lt;code&gt;rpm-ostree install&lt;/code&gt; if you decide to keep it.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dnf builddep gtk4&lt;/code&gt;, then build and &lt;code&gt;sudo ninja install&lt;/code&gt; GTK 4 right on the host to test it against host apps. If anything breaks, just reboot, and you&amp;rsquo;re back to a clean working state.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Unlocking + layering dnf is a very powerful development workflow to the point where I&amp;rsquo;d almost want dnf included in Silverblue by default.
Unfortunately, this workflow is also unobvious enough that the dnf maintainers &lt;a href=&#34;https://github.com/rpm-software-management/dnf/issues/2108&#34;&gt;accidentally prevented it from working&lt;/a&gt; some time ago (thankfully, quickly corrected).
I understand the UX concern about having dnf visibly available when it cannot work outside this specific workflow, but perhaps Silverblue could just hide it somehow unless the host is unlocked, or rename the dnf binary?&lt;/p&gt;
&lt;h2 id=&#34;persistent-unlocking&#34;&gt;Persistent unlocking &lt;a href=&#34;https://bxt.rs/blog/using-fedora-silverblue-for-compositor-development/#persistent-unlocking&#34; class=&#34;anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Generally to put something persistently on the host, you&amp;rsquo;d just layer it with &lt;code&gt;rpm-ostree install&lt;/code&gt;.
However, sometimes what you want is a &lt;em&gt;temporary&lt;/em&gt; change that also &lt;em&gt;happens to persist&lt;/em&gt; across reboots.&lt;/p&gt;
&lt;p&gt;This sounds weird, but consider testing a kernel build.
You want it to be temporary and easy to roll back, but you kinda have to reboot into the new kernel.
And you also don&amp;rsquo;t want to spend extra time building and layering .rpms.&lt;/p&gt;
&lt;p&gt;For this situation, &lt;code&gt;ostree admin unlock&lt;/code&gt; comes with a &lt;code&gt;--hotfix&lt;/code&gt; flag.
It&amp;rsquo;ll persist the temporary overlay across reboots, and will only reset itself once you explicitly make some change with &lt;code&gt;rpm-ostree&lt;/code&gt;.
Note that you never lose the ability to reboot into the previous, working system.&lt;/p&gt;
&lt;h2 id=&#34;summing-it-all-up&#34;&gt;Summing it all up &lt;a href=&#34;https://bxt.rs/blog/using-fedora-silverblue-for-compositor-development/#summing-it-all-up&#34; class=&#34;anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;So, this is what my development workflow looks like.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Most work happens in one kitchen-sink toolbox that I (like to but am not required to) reinstall every Fedora release to keep cruft from building up. This includes building and running niri on a TTY.&lt;/li&gt;
&lt;li&gt;After finishing a change, I unlock the host with &lt;code&gt;sudo ostree admin unlock&lt;/code&gt;, copy over the niri binary, and re-log in to test it in my real session. This will automatically reset upon a reboot.&lt;/li&gt;
&lt;li&gt;When working on a long-running branch, I&amp;rsquo;ll build a work-in-progress niri .rpm and layer it with &lt;code&gt;rpm-ostree install&lt;/code&gt; to persist the new version across reboots.&lt;/li&gt;
&lt;li&gt;I use &lt;code&gt;dnf install&lt;/code&gt; on the host when I want to throwaway-test something host-specific and have it automatically reset upon a reboot.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Over time I made a few small quality-of-life tweaks to smooth out some rough edges in this workflow.&lt;/p&gt;
&lt;p&gt;For example, &lt;code&gt;toolbox enter&lt;/code&gt; is a mouthful and always drops me into &lt;em&gt;bash&lt;/em&gt;.
Enter &lt;code&gt;t&lt;/code&gt;, a script in my &lt;code&gt;~/.local/bin/&lt;/code&gt;, always available in &lt;code&gt;$PATH&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$#&lt;/span&gt; -eq &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;command&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;fish
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;command&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;printf&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;%q &amp;#34;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$@&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;exec&lt;/span&gt; toolbox run -c fedora-toolbox-44 bash -ic &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$command&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, typing &lt;code&gt;t&lt;/code&gt; puts me in the toolbox directly into my dear &lt;a href=&#34;https://fishshell.com/&#34;&gt;fish&lt;/a&gt; shell.
Typing&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;t some-program &amp;#34;with complex&amp;#34; arguments | grep &amp;#34;and stuff&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;also works as expected, with correct argument passing thanks to &lt;code&gt;printf &amp;quot;%q &amp;quot;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This works for .desktop files too.
Say, you installed VSCode in the toolbox and got a .desktop file.
Just change:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Exec=/usr/share/code/code --ozone-platform-hint=auto %F
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;to:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Exec=t /usr/share/code/code --ozone-platform-hint=auto %F
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;and it&amp;rsquo;ll run in the toolbox.
(I understand distrobox handles .desktop files automatically.)&lt;/p&gt;
&lt;p&gt;Note that I use &lt;code&gt;toolbox run&lt;/code&gt; but route the command through bash.
This is necessary to get all environment variables like &lt;code&gt;$DEBUGINFOD_URLS&lt;/code&gt; that distros keep stubbornly putting in &lt;code&gt;/etc/profile.d/&lt;/code&gt; scripts, which of course don&amp;rsquo;t get sourced without a &lt;code&gt;bash -i&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Another quality-of-life improvement was binding a separate hotkey to spawning a terminal directly in the toolbox.
I actually noticed that most of the time, when I open a terminal, I want to be in the toolbox, so now my &lt;kbd&gt;Super&lt;/kbd&gt;&lt;kbd&gt;T&lt;/kbd&gt; spawns the toolbox Alacritty, while the less convenient &lt;kbd&gt;Super&lt;/kbd&gt;&lt;kbd&gt;Shift&lt;/kbd&gt;&lt;kbd&gt;T&lt;/kbd&gt; spawns the host Alacritty.&lt;/p&gt;
&lt;p&gt;Furthermore, at some point I got tired of waiting for the&amp;hellip;&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;┌ ~
└─ hyperfine -w 3 --shell=none &amp;#39;true&amp;#39; &amp;#39;t true&amp;#39;
Benchmark 1: true
  Time (mean ± σ):     411.9 µs ±  35.8 µs    [User: 248.9 µs, System: 111.3 µs]
  Range (min … max):   374.1 µs … 1147.6 µs    5794 runs

Benchmark 2: t true
  Time (mean ± σ):     257.8 ms ±   2.0 ms    [User: 3.0 ms, System: 6.1 ms]
  Range (min … max):   255.2 ms … 260.5 ms    11 runs

Summary
  true ran
  625.92 ± 54.60 times faster than t true
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&amp;hellip;extra 250 ms for &lt;code&gt;toolbox run&lt;/code&gt;, and &lt;a href=&#34;https://github.com/YaLTeR/dotfiles/blob/577e11f7b8a0a33601fc4764e8fd390cf23ff936/source/sh/executable_spawn-alacritty.bash&#34;&gt;wrote a script&lt;/a&gt; that keeps Alacritty running as a daemon inside (and outside) the toolbox, making opening a new terminal window always instant.
As a bonus, this happens to fix the SIGHUP problem that I mentioned above: since Alacritty runs directly inside the toolbox, closing its window will properly close the terminal app running inside.&lt;/p&gt;
&lt;p&gt;(Eventually I went even further and made a &lt;a href=&#34;https://github.com/YaLTeR/dotfiles/tree/577e11f7b8a0a33601fc4764e8fd390cf23ff936/source/misc/toolbox-server&#34;&gt;tiny service&lt;/a&gt; for fun that runs inside the toolbox, listens to a socket, and runs the command it receives. I only use it in .desktop files though instead of &lt;code&gt;t&lt;/code&gt; to avoid the 250 ms delay.&lt;sup id=&#34;fnref:7&#34;&gt;&lt;a href=&#34;#fn:7&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;7&lt;/a&gt;&lt;/sup&gt;)&lt;/p&gt;
&lt;h2 id=&#34;what-about-other-systems&#34;&gt;What about other systems? &lt;a href=&#34;https://bxt.rs/blog/using-fedora-silverblue-for-compositor-development/#what-about-other-systems&#34; class=&#34;anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I quite like my Silverblue setup.
It very much &lt;em&gt;works&lt;/em&gt;, and with the tools that it has, it lets me do anything that I might need.&lt;/p&gt;
&lt;p&gt;Silverblue is not without its problems however, so I&amp;rsquo;ve been thinking about what parts of the experience I find important, and how well other distributions currently satisfy them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. The ability to reboot to a previous, working system.&lt;/strong&gt;
Most new atomic/immutable distros can do this since it&amp;rsquo;s the main value proposition.
It&amp;rsquo;s also possible on &lt;a href=&#34;https://nixos.org/&#34;&gt;NixOS&lt;/a&gt;.
On traditional distros I think you can get something close with btrfs snapshots, but it requires a complex setup.&lt;/p&gt;
&lt;p&gt;A/B updates tie closely into this, where rather than mutating the running system, an update is prepared in a separate folder, then atomically swapped with the previous system version (which remains available to boot into should something go awry).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. Anti-hysteresis.&lt;/strong&gt;
The host system always stays clean, packages don&amp;rsquo;t build up over time.&lt;/p&gt;
&lt;p&gt;On a normal distro, a few months is enough for you to scarcely have any idea about all the random one-off packages you installed and forgot about, especially various development tooling and build dependencies &lt;del&gt;not to mention the texlive-full installation&lt;/del&gt;.
They use up disk space and time during system updates, sometimes cause conflicts and other annoying issues.
Config migrations build up, and your system gradually drifts away from a clean well-tested upstream state.&lt;/p&gt;
&lt;p&gt;Immutable distros solve this by not letting you install stuff on the host, and every updated rebuild of the host system starts from a fresh state, so there&amp;rsquo;s no accumulation of junk.&lt;/p&gt;
&lt;p&gt;NixOS and Silverblue do let you add (layer) packages, so they &lt;em&gt;can&lt;/em&gt; build up, but:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;they make it sufficiently annoying, making you prefer non-host environments such as toolbox for one-off packages;&lt;/li&gt;
&lt;li&gt;even with layered packages, the system is rebuilt from a fresh state every update.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Technically, you could use toolbox for everything even on a normal Fedora Workstation, but this requires discipline and doesn&amp;rsquo;t save you from config migrations, SELinux labeling changes, etc.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. The ability to easily install things on the host.&lt;/strong&gt;
This is the part where many newer immutable distros fail to provide a good experience.
I &lt;em&gt;need&lt;/em&gt; to install programs on the host, whether it&amp;rsquo;s because I want some host desktop components, or to test my own compositor, or whatever.&lt;/p&gt;
&lt;p&gt;Often, I want to install something on the host &lt;em&gt;quickly&lt;/em&gt;.
For distros such as &lt;a href=&#34;https://universal-blue.org/&#34;&gt;Universal Blue&lt;/a&gt; spins and other &lt;a href=&#34;https://bootc.dev/&#34;&gt;bootc&lt;/a&gt;-based systems, the suggested way to include components on the host is making your own downstream spin.
But this works only for long-term packages: I don&amp;rsquo;t want to spend time editing and kicking off a full system build just to test some new terminal or notification daemon, not to mention the whole question of how to keep such a custom system always up to date with its base distro.&lt;/p&gt;
&lt;p&gt;Compare this with &lt;code&gt;rpm-ostree install&lt;/code&gt; on Silverblue: one command, slow but tolerable, and the OS remains automatically updated with no extra setup.&lt;/p&gt;
&lt;p&gt;Some systems are even more limited, like &lt;a href=&#34;https://os.gnome.org/&#34;&gt;GNOME OS&lt;/a&gt; which is based on the &lt;a href=&#34;https://gitlab.com/freedesktop-sdk/freedesktop-sdk&#34;&gt;Freedesktop SDK&lt;/a&gt;.
The selection of tools and libraries available in the Freedesktop SDK is (intentionally) much more limited compared to most distros, so in many cases you&amp;rsquo;ll find yourself having to go and build whatever you need from source.
If that happens to be something big and complex like Qt (to try a hot new &lt;a href=&#34;https://quickshell.org/&#34;&gt;Quickshell&lt;/a&gt;-based desktop): good luck; I hope you didn&amp;rsquo;t have plans for the weekend.&lt;/p&gt;
&lt;p&gt;A common suggestion for these OSes is &lt;a href=&#34;https://0pointer.net/blog/testing-my-system-code-in-usr-without-modifying-usr.html&#34;&gt;systemd-sysext&lt;/a&gt; that lets you build an image and overlay it over /usr.
Florian Müllner &lt;a href=&#34;https://www.youtube.com/watch?v=4BsL0VyCoWs&amp;amp;t=10292s&#34;&gt;gave a talk&lt;/a&gt; at the 2025 GUADEC showing a nice workflow for using sysexts for Mutter and GNOME Shell development and testing on immutable distros.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s also possible to enforce system version compatibility checks in sysexts.
A system like GNOME OS could build and ship a collection of sysexts version-locked to the runtime they were built against, and automatically updated together with the rest of the system using systemd-sysupdate, resulting in an experience similar to layered packages.
(In fact, GNOME OS does have that, just the selection of sysexts is fairly small.)&lt;/p&gt;
&lt;p&gt;Some software can be packaged into self-contained sysexts that work on most distros.
The Flatcar &lt;a href=&#34;https://flatcar.github.io/sysext-bakery/&#34;&gt;sysext-bakery&lt;/a&gt; is one repository of such sysexts.&lt;/p&gt;
&lt;p&gt;What&amp;rsquo;s wrong then?
Well, the main limitation of sysexts is that they are meant for tools without dependencies.
They do not do any dependency resolution or support any dependencies other than, optionally, the base OS itself.
Back to my example, while it&amp;rsquo;s possible to build and ship sysexts for Qt apps that bundle Qt itself, all of those sysexts will carry their own copies of Qt.
Even worse, since they are mounted into the same filesystem tree, conflicting files (say, different-version Qt binaries) will get mounted only from &lt;em&gt;one&lt;/em&gt; of the sysexts, whichever one happens to mount last.
So sysexts aren&amp;rsquo;t a complete replacement for packages (nor are they intended to be).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. The ability to make transient changes to the host.&lt;/strong&gt;
While I don&amp;rsquo;t immediately see why you couldn&amp;rsquo;t put a writable overlay on any regular distro like what &lt;code&gt;ostree admin unlock&lt;/code&gt; does, I haven&amp;rsquo;t seen anyone doing it, or any simple &amp;ldquo;no thinking necessary&amp;rdquo; tools for it.&lt;sup id=&#34;fnref1:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;
Perhaps it&amp;rsquo;s too easy to mess up outside immutable systems?&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s worth noting that some paths like &lt;code&gt;/etc&lt;/code&gt; aren&amp;rsquo;t usually covered by immutability and overlays, so you still need to be a bit careful.&lt;/p&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion &lt;a href=&#34;https://bxt.rs/blog/using-fedora-silverblue-for-compositor-development/#conclusion&#34; class=&#34;anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;All in all, Silverblue appears to be a sweet spot between offering immutable/atomic guarantees with plenty of useful tooling bundled in, while also being a &lt;em&gt;normal Fedora&lt;/em&gt; with a wide package selection available for both persistent layering and quick transient installation.
I appreciate the QA and other behind-the-scenes work that goes into my ability to install Silverblue and be reasonably sure that it will work, and keep working, with all of my hardware, and that I won&amp;rsquo;t have to hunt for packages to get a working bluetooth or what have you.
My Silverblue installs are the longest I&amp;rsquo;ve kept any single distro, and I have no urge to reinstall because my host system remains clean and I know exactly what it comprises.&lt;/p&gt;
&lt;p&gt;My issues with Silverblue mostly boil down to some rough edges and slowness of &lt;code&gt;rpm-ostree&lt;/code&gt;, and some less than ideal Flatpak repository defaults.
Having to do most of the work in a container is somewhat annoying at times, especially when dealing with nested containerization or VMs.
But I&amp;rsquo;m not sure there&amp;rsquo;s a better way fundamentally, without trading host system robustness.
For the few things that do require it, I can always unlock the host.&lt;/p&gt;
&lt;p&gt;I hope this post sheds some light on immutable system workflows and perhaps inspires you to try one.
I&amp;rsquo;d also love to hear your feedback and suggestions!
Did I miss something?
Is there a better way of doing things?
A new system that solves all problems and makes everything better?
Please reach out to me on Mastodon or by email, linked at the bottom of the page!&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;I&amp;rsquo;m told the modern alternative is &lt;code&gt;systemd-sysext merge --mutable=ephemeral&lt;/code&gt;, which works across all distros and not just Silverblue. Haven&amp;rsquo;t tried it myself yet!&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref1:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;I didn&amp;rsquo;t quite realize this before, but &lt;code&gt;rpm-ostree usroverlay&lt;/code&gt; seems to literally exec &lt;code&gt;ostree admin unlock&lt;/code&gt;:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;┌ ~
└─ rpm-ostree usroverlay -h
Usage:
  ostree admin unlock [OPTION…]

Make the current deployment mutable (as a hotfix or development)
(...)
┌ ~
└─ rpm-ostree usroverlay --version
libostree:
 Version: &amp;#39;2025.4&amp;#39;
 Git: 99a03a7bb8caa774668222a0caace3b7e734042e
(...)
&lt;/code&gt;&lt;/pre&gt;&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/li&gt;
&lt;li id=&#34;fn:3&#34;&gt;
&lt;p&gt;Which is, uhh, not a lot of apps come to think of it. Nautilus, Ptyxis, Software, System Monitor, Settings, xdg-desktop-portal-gnome dialogs&amp;mdash;the rest come as Flatpaks on Silverblue. How to test your GTK changes against those Flatpak apps? Uhhhhhh&amp;#160;&lt;a href=&#34;#fnref:3&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:4&#34;&gt;
&lt;p&gt;For years, it&amp;rsquo;s been &lt;code&gt;rpm-ostree ex apply-live&lt;/code&gt;, where &lt;code&gt;ex&lt;/code&gt; stood for &lt;em&gt;experimental&lt;/em&gt;. I guess I&amp;rsquo;ve been procrastinating on this blogpost long enough that it had time to graduate to non-experimental &lt;code&gt;rpm-ostree apply-live&lt;/code&gt;.&amp;#160;&lt;a href=&#34;#fnref:4&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:5&#34;&gt;
&lt;p&gt;The &lt;a href=&#34;https://flathub.org/en/apps/app.devsuite.Ptyxis&#34;&gt;Ptyxis&lt;/a&gt; terminal can work properly on the host even when installed as a Flatpak. It does this by spawning a small binary on the host (through a host-run permission) that does all command spawning and PTY communication, while the Ptyxis GUI remains inside Flatpak. This is a clever workaround, but requires a sandbox hole and very careful engineering, and arguably runs somewhat at odds with the point of Flatpak.&amp;#160;&lt;a href=&#34;#fnref:5&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:6&#34;&gt;
&lt;p&gt;Since writing that example, I replaced that monitor and finally got rid of the custom initramfs.
This is faster because without overrides, Silverblue directly uses an initramfs built on Fedora servers, and I think it also works better with secure boot?
Either way, I wanted to leave it in as an example that you &lt;em&gt;can&lt;/em&gt; customize the initramfs on Silverblue if needed.&amp;#160;&lt;a href=&#34;#fnref:6&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:7&#34;&gt;
&lt;p&gt;See for yourself:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;┌ ~
└─ hyperfine -w 3 --shell=none &amp;#39;t true&amp;#39; &amp;#39;true&amp;#39; &amp;#39;tb true&amp;#39;
Benchmark 1: t true
  Time (mean ± σ):     259.5 ms ±   3.6 ms    [User: 2.9 ms, System: 6.2 ms]
  Range (min … max):   255.7 ms … 266.6 ms    11 runs

Benchmark 2: true
  Time (mean ± σ):     408.7 µs ±  34.2 µs    [User: 248.6 µs, System: 107.1 µs]
  Range (min … max):   370.2 µs … 1152.8 µs    6665 runs

Benchmark 3: tb true
  Time (mean ± σ):     462.8 µs ±  41.7 µs    [User: 264.2 µs, System: 135.6 µs]
  Range (min … max):   399.2 µs … 786.4 µs    6688 runs

Summary
  true ran
    1.13 ± 0.14 times faster than tb true
  635.00 ± 53.80 times faster than t true
&lt;/code&gt;&lt;/pre&gt;&amp;#160;&lt;a href=&#34;#fnref:7&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</description>
    </item>
    
  </channel>
</rss>
