Immutable Fedora desktop as a Docker image.
  • Just 51.7%
  • Shell 40.8%
  • Dockerfile 6.1%
  • CSS 1.1%
  • Ruby 0.3%
Find a file
2026-06-02 22:26:44 -04:00
.devcontainer add devcontainer 2026-01-08 21:13:55 -05:00
.github Update Homebrew/actions digest to 521d405 (#185) 2026-06-02 22:26:35 -04:00
_img README.md: add screenshot, disclaimers, fixup precommit 2026-01-12 16:29:46 -05:00
brew remove flatpak-builder 2026-04-30 16:22:59 -04:00
build fix selinux again 2026-05-05 10:05:06 -04:00
files/main fix up container policy 2026-05-07 08:16:09 -04:00
flatpaks drop gaming images 2026-04-30 15:45:02 -04:00
iso tree-wide: set up pre-commit, format files 2026-01-10 01:30:54 -05:00
ujust rebase on kinoite directly 2026-04-30 23:28:39 -04:00
.gitignore fixup gitignore 2026-04-30 14:11:49 -04:00
.pre-commit-config.yaml README.md: add screenshot, disclaimers, fixup precommit 2026-01-12 16:29:46 -05:00
.prettierrc.json tree-wide: set up pre-commit, format files 2026-01-10 01:30:54 -05:00
AGENTS.md update docs 2026-04-30 17:20:47 -04:00
artifacthub-repo.yml tree-wide: set up pre-commit, format files 2026-01-10 01:30:54 -05:00
Brewfile chore: add act+yq to Brewfile 2026-01-10 00:31:18 -05:00
Containerfile Update ghcr.io/ublue-os/brew:latest Docker digest to 48be52b (#184) 2026-06-02 22:26:44 -04:00
cosign.pub bump key 2026-05-01 07:49:54 -04:00
Justfile Update docker.io/qemux/qemu:latest Docker digest to c48c441 (#182) 2026-05-31 15:52:41 -04:00
LICENSE.md update docs 2026-01-11 11:18:11 -05:00
packages.json packages: drop unnecessary pkgs 2026-05-01 14:39:09 -04:00
README.md update README.md 2026-05-01 09:14:53 -04:00
services.json services: enable auto updates with ostree 2026-05-01 08:21:30 -04:00

Kyanite

A Fedora Kinoite spin I run as my daily driver. KDE Plasma, no corporate branding, rough edges sanded off.

What's different from stock Kinoite

  • Firefox via Mozilla's official Flatpak; Bazaar in place of Discover.
  • Flathub set up on first boot; Fedora's flatpak remotes removed.
  • Fish as the default shell, dynamic wallpapers, fcitx5 for CJK input.
  • Fuller codec stack via negativo17 — h264/h265/AV1 playback just works.
  • Heavy stuff (Docker, virt, Steam, ROCm, etc.) lives in sysexts instead of the base image.
  • PipeWire filter chains for some laptop speaker DSP setups.
  • Ollama Quadlets ready to go for local LLMs on CPU, ROCm, or Vulkan.

I borrow the ujust command framework and a couple of utility packages from Universal Blue's COPR, but everything else is built straight on Fedora Kinoite.

Quick Start

If you're on a bootc system already (Kinoite, Aurora, etc.):

sudo bootc switch ghcr.io/alyraffauf/kyanite:stable
sudo systemctl reboot

After it boots, ujust --list shows what custom recipes are available. A couple things to know up front: stuff under /etc/skel doesn't auto-migrate, and rebasing across desktop environments (e.g. GNOME → KDE) usually goes badly.

Migrating from kyanite-dx / kyanite-gaming? Those tags now alias to kyanite:stable, so you'll keep getting updates. Run ujust rebase-helper to clean up the variant metadata when you get around to it.

Optional sysexts

Anything heavy or opt-in lives in kyanite-sysexts as systemd-sysext payloads. Install only what you actually want:

Sysext What you get
docker Docker CE + buildx, compose, model plugins
rocm AMD ROCm, HIP, OpenCL, rocm-smi
steam Native Steam, Gamescope, MangoHud, GameMode (i686 multilib)
syncthing Native Syncthing daemon
tailscale Tailscale mesh-VPN client + daemon
virt QEMU/KVM, libvirt, edk2-ovmf, virtio drivers
ujust install-sysext NAME
ujust remove-sysext NAME

They auto-update via systemd-sysupdate.timer. Gaming launchers (Heroic, ProtonUp-Qt, Lutris) ship as Flatpaks — ujust install-gaming-flatpaks.

Local LLMs (Ollama)

Three Quadlet units for running Ollama as a user-level systemd service. The GPU runtimes live inside the container, so you don't have to install ROCm or Vulkan ICDs on the host.

ujust enable-ollama          # CPU (or NVIDIA on a kinoite-nvidia base)
ujust enable-ollama-rocm     # AMD GPU via ROCm. Run configure-gpu-groups first.
ujust enable-ollama-vulkan   # AMD GPU via Vulkan. Works on cards ROCm doesn't.

All three listen on 127.0.0.1:11434 and share the ollama-data volume, so model weights don't redownload when you switch backends. They're mutually exclusive: starting one stops the others.

Start with ollama-rocm if you have an officially-supported AMD card (RDNA1/2 high-end, RDNA3, CDNA). If ollama list shows your model running on CPU, your card isn't in the bundled rocBLAS — switch to Vulkan.

Syncthing

ujust install-sysext syncthing
systemctl --user enable --now syncthing.service

GUI at http://127.0.0.1:8384. Existing config in ~/.local/state/syncthing/ carries over (peer devices, folder lists, etc.).

Coming from the old containerized Quadlet setup? Run ujust remove-syncthing-quadlet first to clean up.

Quadlets

Templates ship at /usr/share/kyanite/quadlets/. The ujust enable-X recipes copy a template into ~/.config/containers/systemd/ so OS updates won't clobber your edits. To customize (e.g. uncomment HSA_OVERRIDE_GFX_VERSION in ollama-rocm.container), edit your user copy, then:

systemctl --user daemon-reload
systemctl --user restart <service>

podman-auto-update.timer is on by default, so any quadlet with AutoUpdate=registry (all of mine) refreshes nightly.

Customization & forking

The configuration is declarative — fork it and edit a few JSON files:

  • packages.json — packages per variant (include / exclude)
  • services.json — systemd units to enable at build time
  • files/<variant>/ — variant-specific system files (only main/ is populated)
  • brew/ — Homebrew bundles installed at runtime via ujust install-*
  • flatpaks/ — Flatpaks preinstalled on first boot
  • ujust/ — custom ujust recipes

The variant scaffold (packages.json variants.{name}, IMAGE_FLAVOR=NAME in CI) is still wired up even though I only build kyanite now. Flipping a CI switch can revive dx or any other variant.

Building locally

Needs Podman and Just:

just build           # build the kyanite container
just build-qcow2     # build a qcow2 for VM testing
just build-iso       # ~10GB, takes 30+ min
just run-vm          # boot the qcow2 in qemu

NVIDIA base experiment:

BASE_IMAGE=ghcr.io/ublue-os/kinoite-nvidia:latest \
BASE_IMAGE_SHA=$(skopeo inspect docker://$BASE_IMAGE --format '{{.Digest}}') \
just build

Output lands in output/. I don't publish pre-built ISOs — install Fedora Kinoite and rebase, or build one yourself.

Security

Images are signed with cosign against cosign.pub:

cosign verify \
  --key https://raw.githubusercontent.com/alyraffauf/kyanite/main/cosign.pub \
  ghcr.io/alyraffauf/kyanite:stable

Switching to signed transport

ostree-image-signed: only works once the running deployment ships kyanite's policy.json and cosign.pub. A fresh switch from non-kyanite is a two-step bootstrap:

# 1. Unsigned switch — gets you a deployment with the policy + key.
sudo bootc switch ghcr.io/alyraffauf/kyanite:stable
sudo systemctl reboot

# 2. After reboot, switch the tracker to signed.
sudo rpm-ostree rebase ostree-image-signed:docker://ghcr.io/alyraffauf/kyanite:stable
sudo systemctl reboot

After step 2, rpm-ostreed-automatic.timer (on by default) verifies every pulled image against cosign.pub before any bytes touch your filesystem. rpm-ostree status should show ostree-image-signed: as the booted spec.

State of things

It works well enough for me to use daily. Despite the rename, plenty of Fedora visual branding is still around (Kickoff logo, fastfetch, wallpapers). This is intended to be a very light repackage.

Resources

License

Apache 2.0. See LICENSE.md. Based on Fedora Kinoite with KDE Plasma, inspired by Universal Blue.