[kde-linux/kde-linux/buildstream] /: Adopt BuildStream

Harald Sitter <[email protected]>
Newsgroups gmane.comp.kde.cvs
Message-ID <[email protected]>
Git commit e06c2765e97012b827e627ce146bcf78390f7566 by Harald Sitter.
Committed on 31/07/2026 at 22:15.
Pushed by sitter into branch 'buildstream'.

Adopt BuildStream

This is a first step towards the adoption of BuildStream as a technology
to produce the binaries needed for KDE Linux.

M  +11   -7    .gitlab-ci.yml
M  +2    -0    addons.sh
M  +73   -58   build.sh
A  +64   -0    buildstream.conf
A  +14   -0    elements/kde-linux-packages.bst
A  +20   -0    elements/os/filesystem-compose.bst
A  +42   -0    elements/os/filesystem.bst
A  +10   -0    elements/os/initial-scripts.bst
A  +34   -0    elements/os/initrd-payload.bst
A  +56   -0    elements/os/initrd.bst
A  +48   -0    elements/os/os-release.bst
A  +26   -0    elements/os/systemd-initrd-compose.bst
A  +33   -0    elements/os/systemd-initrd-mkosi-extra.bst
A  +27   -0    elements/os/systemd-initrd-payload.bst
A  +10   -0    elements/plugins/buildstream-plugins-community.bst
A  +7    -0    include/aliases.yml
M  +7    -3    mkosi.conf
A  +9    -0    mkosi.conf.d/zz-buildstream.conf
A  +2    -0    mkosi.extra/etc/ld.so.conf.d/kde-linux-payload.conf
A  +2    -0    mkosi.extra/etc/ld.so.conf.d/kde-linux-payload.conf.license
A  +13   -0    mkosi.extra/etc/shells
M  +1    -1    mkosi.extra/live/usr/calamares/desktop/settings.conf
M  +0    -3    mkosi.extra/live/usr/lib/live-setup
A  +22   -0    mkosi.extra/usr/bin/vi
R  +0    -0    mkosi.extra/usr/lib/pam.d/kde [from: mkosi.extra/etc/pam.d/kde - 100% similarity]
R  +0    -0    mkosi.extra/usr/lib/pam.d/kde-fingerprint [from: mkosi.extra/etc/pam.d/kde-fingerprint - 100% similarity]
R  +0    -0    mkosi.extra/usr/lib/pam.d/kde-smartcard [from: mkosi.extra/etc/pam.d/kde-smartcard - 100% similarity]
A  +29   -0    mkosi.extra/usr/lib/pam.d/system-auth
A  +8    -0    mkosi.extra/usr/lib/pam.d/system-local-login
A  +23   -0    mkosi.extra/usr/lib/pam.d/system-login
A  +8    -0    mkosi.extra/usr/lib/pam.d/system-remote-login
A  +13   -0    mkosi.extra/usr/lib/pam.d/system-services
M  +5    -12   mkosi.extra/usr/lib/rebuild-efi
M  +7    -4    mkosi.extra/usr/lib/systemd/system-generators/kde-linux-live-generator
M  +1    -17   mkosi.extra/usr/lib/systemd/system-preset/00-kde-linux.preset
M  +0    -5    mkosi.extra/usr/lib/tmpfiles.d/etc.conf
M  +2    -2    mkosi.finalize.d/10-modify-nsswitch.py.chroot
M  +0    -20   mkosi.finalize.d/40-core.sh.chroot
M  +16   -27   mkosi.finalize.d/99-etc.sh.chroot
A  +121  -0    mkosi.images/initrd-build/mkosi.conf
A  +40   -0    mkosi.images/initrd-build/mkosi.prepare
A  +28   -0    mkosi.images/uki.live/mkosi.conf
A  +27   -0    mkosi.images/uki/mkosi.conf
A  +5    -0    mkosi.initrd.conf
M  +12   -56   mkosi.postinst.chroot
D  +0    -4    mkosi.sandbox/etc/pacman.d/.gitignore
M  +1    -1    permission-fix.sh
A  +76   -0    project.conf

https://invent.kde.org/kde-linux/kde-linux/-/commit/e06c2765e97012b827e627ce146bcf78390f7566

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 585c03ab..077079c3 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -44,12 +44,19 @@ imaging:
       aud: https://tokens.kde.org
   variables: &variables
     RUNNER_AFTER_SCRIPT_TIMEOUT: 1h
+  before_script:
+    - sudo pacman --sync --refresh --noconfirm mtools
+    - sudo pacman --remove --nosave --recursive --noconfirm mkosi
+    - sudo pip install --break-system-packages git+https://github.com/systemd/mkosi.git
+    - which mkosi
+    - mkosi --version
   script:
     - if [ "$IMAGING_MODE" = stage ]; then curl -s https://gitlab.com/gitlab-org/incubation-engineering/mobile-devops/download-secure-files/-/raw/main/installer | bash; fi
-    - sudo ./build.sh --force --debug
+    - KDECI_BUILD=TRUE ./build.sh --force --debug
     - if [ "$IMAGING_MODE" = stage ]; then ./upload.sh --stage; fi
     - if [ "$IMAGING_MODE" = test ]; then ./upload-to-storage.sh; fi # Need this to have something to pass to OpenQA.
   after_script:
+    - cp --archive ~/.cache/buildstream/logs buildstream-logs || true
     - if [ "$IMAGING_MODE" = stage ] && [ "$CI_JOB_STATUS" = success ]; then exit 0; fi
     - if [ "$IMAGING_MODE" = test ]; then exit 0; fi
     - ./upload-to-storage.sh || true
@@ -58,6 +65,7 @@ imaging:
     when: always
     paths:
       - "**/erofs.log"
+      - "buildstream-logs/**/*.log"
     reports:
       dotenv: build.env
 
@@ -130,7 +138,7 @@ publish:
   script:
     - curl -s https://gitlab.com/gitlab-org/incubation-engineering/mobile-devops/download-secure-files/-/raw/main/installer | bash
     - ./upload.sh --publish
-  artifacts:
+  artifacts: &artifacts
     expire_in: 4 weeks
     when: always
     paths:
@@ -157,8 +165,4 @@ publish-manual:
   script:
     - curl -s https://gitlab.com/gitlab-org/incubation-engineering/mobile-devops/download-secure-files/-/raw/main/installer | bash
     - ./upload.sh --publish
-  artifacts:
-    expire_in: 4 weeks
-    when: always
-    paths:
-      - "**/erofs.log"
+  artifacts: *artifacts
diff --git a/addons.sh b/addons.sh
index fd40911d..d8cbcabc 100755
--- a/addons.sh
+++ b/addons.sh
@@ -18,6 +18,8 @@ ukify build \
     systemd.log_level=debug systemd.log_target=kmsg log_buf_len=1M printk.devkmsg=on systemd.show_status=auto rd.udev.log_level=3' \
   --output debug.addon.efi
 
+# also useful:  rd.systemd.break=pre-switch-root
+
 ukify build \
   --cmdline 'init=/usr/lib/systemd/systemd-bootchart' \
   --output bootchart.addon.efi
diff --git a/build.sh b/build.sh
index 682bb743..f2fabf5c 100755
--- a/build.sh
+++ b/build.sh
@@ -17,7 +17,12 @@ make_debug_archive () {
   mkdir --parents /var/tmp/debugroot
 
   # Download and extract debug symbols produced by the packages pipeline.
-  curl --fail https://storage.kde.org/kde-linux-packages/testing/artifacts/debug.tar.zst \
+  url="https://storage.kde.org/kde-linux-packages/testing/artifacts/debug.tar.zst"
+  if [ "${CI_COMMIT_BRANCH:-}" == "testing-buildstream" ]; then
+    url="https://storage.kde.org/kde-linux-packages/testing-buildstream/artifacts/debug.tar.zst"
+  fi
+
+  curl --fail "$url" \
     | zstd --decompress | tar --extract --directory=/var/tmp/debugroot
 
   # systemd-sysext uses the os-release in extension-release.d to verify the sysext matches the base OS,
@@ -57,28 +62,26 @@ LIVE_EFI=${EFI_BASE}.efi   # Name of live UKI in the ESP (no tries counter — E
 # Clean up old build artifacts.
 rm --recursive --force kde-linux.cache/*.raw kde-linux.cache/*.iso kde-linux.cache/*.mnt
 
-cat /etc/pacman.conf.nolinux >> mkosi.sandbox/etc/pacman.conf
-
-# Enable multilib; we need it later for steam-devices
-cat <<EOF >> mkosi.sandbox/etc/pacman.conf
-[multilib]
-Include = /etc/pacman.d/mirrorlist
+BUILDSTREAM_ROOTFS="buildstream-rootfs"
+BUILDSTREAM_BOOTFS="buildstream-bootfs"
+BUILDSTREAM_TOOLFS="buildstream-toolfs"
+BUILDSTREAM_INITRDFS="buildstream-initrdfs"
+BUILDSTREAM_EFI="buildstream-efi"
+
+cat <<EOF > "include/kde-linux-image.yml"
+# SPDX-FileCopyrightText: 2026 KDE Linux Contributors
+# SPDX-License-Identifier: BSD-2-Clause
+
+variables:
+  kde-linux-version-date: '${VERSION_DATE}'
+  kde-linux-image-version: '${VERSION}'
+  kde-linux-build-id: '${CI_COMMIT_SHORT_SHA:-unknownSHA}'
+  kde-linux-commit-sha: '${CI_COMMIT_SHA:-unknownSHA}'
+  kde-linux-commit-short-sha: '${CI_COMMIT_SHORT_SHA:-unknownSHA}'
+  kde-linux-ci-url: '${CI_PIPELINE_URL:-https://invent.kde.org}'
 EOF
 
-mkdir --parents mkosi.sandbox/etc/pacman.d
-# Ensure the base image does not go out of sync with the Arch snapshot used to build packages.
-# WARNING: code copy in bootstrap.sh
-BUILD_REPO=$(curl --fail --silent https://storage.kde.org/kde-linux-packages/testing/repo/build_repo.txt)
-if [ -z "$BUILD_REPO" ]; then
-  echo "ERROR: Could not fetch build_repo.txt — refusing to build out-of-sync image." >&2
-  exit 1
-fi
-echo "Server = ${BUILD_REPO}/\$repo/os/\$arch" > mkosi.sandbox/etc/pacman.d/mirrorlist
-# ... and make sure our cache is up to date. Second --refresh forces a refresh.
-pacman --sync --refresh --refresh --noconfirm
-
-# Make sure permissions are sound
-./permission-fix.sh
+mkdir -p "$PWD/mkosi.extra/usr/lib"
 
 cargo build --release --manifest-path btrfs-migrator/Cargo.toml
 cp -v btrfs-migrator/target/release/btrfs-migrator mkosi.extra/usr/lib/
@@ -91,30 +94,47 @@ rm --recursive --force etc-factory
 git clone https://invent.kde.org/kde-linux/etc-factory
 DESTDIR=$PWD/mkosi.extra make --directory=etc-factory install
 
-# Extract the KDE packages pipeline output into mkosi.extra so kde-builder built files
-# are baked directly into the image instead of going through the package repo.
-curl --fail https://storage.kde.org/kde-linux-packages/testing/artifacts/install.tar.zst \
-    -o install.tar.zst
+if [ "${KDECI_BUILD:-}" = "TRUE" ]; then
+    # Set up cache overrides
+    git clone --depth=1 https://invent.kde.org/sitter/kde-buildstream.git
+    mkdir --parents ~/.config
+    cp kde-buildstream/buildstream.conf.readable ~/.config/buildstream.conf
+fi
+
+rm -rf "$BUILDSTREAM_ROOTFS" "$BUILDSTREAM_BOOTFS" "$BUILDSTREAM_TOOLFS" "$BUILDSTREAM_INITRDFS" "$BUILDSTREAM_EFI"
+bst build \
+    os/filesystem.bst \
+    os/initrd.bst \
+    os/systemd-initrd-payload.bst \
+    kde-linux-packages.bst:kde-buildstream.bst:components/calamares.bst \
+    kde-linux-packages.bst:kde-buildstream.bst:freedesktop-sdk.bst:components/ovmf-maybe.bst \
+    kde-linux-packages.bst:kde-buildstream.bst:freedesktop-sdk.bst:vm/prepare-image.bst
+bst artifact checkout os/filesystem.bst --directory $BUILDSTREAM_ROOTFS
+bst artifact checkout os/initrd.bst --directory $BUILDSTREAM_BOOTFS
+bst artifact checkout os/systemd-initrd-payload.bst --directory $BUILDSTREAM_INITRDFS
+bst artifact checkout kde-linux-packages.bst:kde-buildstream.bst:components/calamares.bst --deps none --directory $BUILDSTREAM_ROOTFS/live
+bst artifact checkout kde-linux-packages.bst:kde-buildstream.bst:freedesktop-sdk.bst:vm/prepare-image.bst --deps none --directory $BUILDSTREAM_TOOLFS
+bst artifact checkout kde-linux-packages.bst:kde-buildstream.bst:freedesktop-sdk.bst:components/ovmf-maybe.bst --directory $BUILDSTREAM_EFI
+
+mkdir -p $BUILDSTREAM_ROOTFS/usr/share/ovmf/
+cp $BUILDSTREAM_EFI/usr/share/ovmf/Shell.efi $BUILDSTREAM_ROOTFS/usr/share/ovmf/Shell.efi
+
+# Remove debug symbols from live directory. It'd be inconvenient to do this in bst right now.
+rm --recursive --force $BUILDSTREAM_ROOTFS/live/usr/lib/debug
 
-# Generate a mkosi dropin with the packages from the packages pipeline
-curl --fail https://storage.kde.org/kde-linux-packages/testing/artifacts/packages.txt \
-    -o packages.txt
+# Make sure permissions are sound
+./permission-fix.sh
 
-mkdir -p mkosi.conf.d
-{
-    echo "[Content]"
-    while IFS= read -r pkg; do
-        echo "Packages=$pkg"
-    done < packages.txt
-} > mkosi.conf.d/40-kde-packages.conf
+url="https://storage.kde.org/kde-linux-packages/testing/artifacts/install.tar.zst"
+if [ "${CI_COMMIT_BRANCH:-}" == "testing-buildstream" ]; then
+    url="https://storage.kde.org/kde-linux-packages/testing-buildstream/artifacts/install.tar.zst"
+fi
+wget --output-document=install.tar.zst "$url"
 
 mkosi \
-    --environment="CI_COMMIT_SHORT_SHA=${CI_COMMIT_SHORT_SHA:-unknownSHA}" \
-    --environment="CI_COMMIT_SHA=${CI_COMMIT_SHA:-unknownSHA}" \
-    --environment="CI_PIPELINE_URL=${CI_PIPELINE_URL:-https://invent.kde.org}" \
-    --environment="VERSION_DATE=${VERSION_DATE}" \
     --image-version="$VERSION" \
-    --extra-tree="$PWD/install.tar.zst" --extra-tree="$PWD/mkosi.extra" \
+    --extra-tree="$PWD/install.tar.zst" \
+    --extra-tree="$PWD/mkosi.extra" \
     "$@"
 
 # Adjust mtime to reduce unnecessary churn between images caused by us rebuilding repos that have possibly not changed in source or binary interfaces.
@@ -130,20 +150,21 @@ if [ -f "$PWD/.secure_files/ssh.key" ]; then
   scp -i "$PWD/.secure_files/ssh.key" mtimer.json [email protected]:/home/kdeos/mtimer.json
 fi
 
+chmod u+w "$OUTPUT" # mkosi tries to be nice by making it read-only
 # NOTE: /efi must be empty so auto mounting can happen. As such we put our templates in a different directory
 rm -rfv "${OUTPUT}/efi"
 [ -d "${OUTPUT}/efi" ] || mkdir --mode 0700 "${OUTPUT}/efi"
 [ -d "${OUTPUT}/usr/share/factory/boot" ] || mkdir --mode 0700 "${OUTPUT}/usr/share/factory/boot"
 [ -d "${OUTPUT}/usr/share/factory/boot/EFI" ] || mkdir --mode 0700 "${OUTPUT}/usr/share/factory/boot/EFI"
 [ -d "${OUTPUT}/usr/share/factory/boot/EFI/Linux" ] || mkdir --mode 0700 "${OUTPUT}/usr/share/factory/boot/EFI/Linux"
+[ -d "${OUTPUT}/usr/share/factory/boot/loader" ] || mkdir --mode 0700 "${OUTPUT}/usr/share/factory/boot/loader"
+[ -d "${OUTPUT}/usr/share/factory/boot/loader/entries" ] || mkdir --mode 0700 "${OUTPUT}/usr/share/factory/boot/loader/entries"
 [ -d "${OUTPUT}/usr/share/factory/boot/EFI/Linux/$EFI_BASE.efi.extra.d" ] || mkdir --mode 0700 "${OUTPUT}/usr/share/factory/boot/EFI/Linux/$EFI_BASE.efi.extra.d"
 
 # Save the main UKI (with tries counter) aside as it must NOT go into factory/boot yet
 # so it doesn't end up on the live ESP.
-cp -v "${OUTPUT}"/kde-linux.efi "$MAIN_UKI"
-rm -v "${OUTPUT}"/kde-linux.efi
-mv -v "${OUTPUT}"/erofs.addon.efi "${OUTPUT}_erofs.addon.efi"
-mv -v "${OUTPUT}"/live.efi "$LIVE_UKI"
+mv -v mkosi.output/uki.efi "$MAIN_UKI"
+mv -v mkosi.output/uki.live.efi "$LIVE_UKI"
 
 make_debug_archive
 
@@ -157,20 +178,11 @@ mv "$LIVE_UKI" "${OUTPUT}/usr/share/factory/boot/EFI/Linux/$LIVE_EFI"
 # Change to kde-linux.cache since we'll be working there.
 cd kde-linux.cache
 
-# Create a 280M large FAT32 filesystem inside of esp.raw.
-fallocate -l 280M esp.raw
+# Create a FAT32 filesystem inside of esp.raw, just large enough to hold our initrd
+fallocate -l 160M esp.raw
 mkfs.fat -F 32 esp.raw
-
-# Mount it to esp.raw.mnt.
-mkdir -p esp.raw.mnt
-mount esp.raw esp.raw.mnt
-
-# Copy everything from /usr/share/factory/boot into esp.raw.mnt.
-# At this point only LIVE_EFI is in factory/boot/EFI/Linux/ so the installed UKI (+3) is not there yet.
-cp --archive --recursive "${OUTPUT}/usr/share/factory/boot/." esp.raw.mnt
-
-# We're done, unmount esp.raw.mnt.
-umount esp.raw.mnt
+# We use mcopy so we don't have to mount the image (which would require sudo) and have less code
+mcopy -i esp.raw -s "${OUTPUT}/usr/share/factory/boot/"* ::/
 
 cd .. # and back to root
 
@@ -194,7 +206,10 @@ mv "$OUTPUT/live" live-root
 time mkfs.erofs -zzstd -C 65536 --chunksize 65536 \
     kde-linux.cache/live.raw live-root > erofs-live.log 2>&1
 
-time mkfs.erofs -zzstd -C 65536 --chunksize 65536 "$ROOTFS_EROFS" "$OUTPUT" > erofs.log 2>&1
+# Needs sudo so it can tinker with setuid files
+time sudo mkfs.erofs --all-root -zzstd -C 65536 --chunksize 65536 "$ROOTFS_EROFS" "$OUTPUT" > erofs.log 2>&1
+# Then chown back the result
+sudo chown $UID:$UID "$ROOTFS_EROFS"
 cp --reflink=auto "$ROOTFS_EROFS" kde-linux.cache/root.raw
 
 # Now assemble the image using systemd-repart and the definitions in mkosi.repart into $ISO.
diff --git a/buildstream.conf b/buildstream.conf
new file mode 100644
index 00000000..3e13a58b
--- /dev/null
+++ b/buildstream.conf
@@ -0,0 +1,64 @@
+# SPDX-License-Identifier: CC0-1.0
+# SPDX-FileCopyrightText: none
+
+# The user configuration for CI builds.
+# https://docs.buildstream.build/master/using_config.html
+
+projects:
+  freedesktop-sdk:
+    # - Augment fd-sdk with our own caches as well so that we can catch objects that have fallen out of the remote cache or aren't there yet.
+    # - As a fallback try to use our proxy cache for fd-sdk
+    artifacts:
+      override-project-caches: true
+      servers:
+        - url: https://buildstream.cache.kde-linux.haraldsitter.eu:11001
+        - url: https://freedesktop.buildstream.cache.kde-linux.haraldsitter.eu
+    source-caches:
+      override-project-caches: true
+      servers:
+        - url: https://buildstream.cache.kde-linux.haraldsitter.eu:11001
+        - url: https://freedesktop.buildstream.cache.kde-linux.haraldsitter.eu
+  gnome:
+    # - Augment gnome with our own caches as well so that we can catch objects that have fallen out of the remote cache or aren't there yet.
+    # - As a fallback try to use our proxy cache for gnome
+    artifacts:
+      override-project-caches: true
+      servers:
+        - url: https://buildstream.cache.kde-linux.haraldsitter.eu:11001
+        - url: https://gnome.buildstream.cache.kde-linux.haraldsitter.eu
+    source-caches:
+      override-project-caches: true
+      servers:
+        - url: https://buildstream.cache.kde-linux.haraldsitter.eu:11001
+        - url: https://gnome.buildstream.cache.kde-linux.haraldsitter.eu
+  kde-buildstream:
+    artifacts:
+      override-project-caches: true
+      servers:
+        - url: https://buildstream.cache.kde-linux.haraldsitter.eu:11001
+    source-caches:
+      override-project-caches: true
+      servers:
+        - url: https://buildstream.cache.kde-linux.haraldsitter.eu:11001
+  kde-linux-packages:
+    artifacts:
+      override-project-caches: true
+      servers:
+        - url: https://buildstream.cache.kde-linux.haraldsitter.eu:11001
+    source-caches:
+      override-project-caches: true
+      servers:
+        - url: https://buildstream.cache.kde-linux.haraldsitter.eu:11001
+  kde-linux:
+    artifacts:
+      override-project-caches: true
+      servers:
+        - url: https://buildstream.cache.kde-linux.haraldsitter.eu:11001
+    source-caches:
+      override-project-caches: true
+      servers:
+        - url: https://buildstream.cache.kde-linux.haraldsitter.eu:11001
+
+logging:
+  # Be more verbose when things fail. In particular the kde-builder issue may be a ways back in the log.
+  error-lines: 1000
diff --git a/elements/kde-linux-packages.bst b/elements/kde-linux-packages.bst
new file mode 100644
index 00000000..dae98d12
--- /dev/null
+++ b/elements/kde-linux-packages.bst
@@ -0,0 +1,14 @@
+# SPDX-FileCopyrightText: 2025 Aleix Pol Gonzalez <[email protected]>
+# SPDX-License-Identifier: BSD-2-Clause
+
+kind: junction
+
+sources:
+- kind: git_repo
+  url: invent:kde-linux/kde-linux-packages.git
+  track: work/sitter/bst
+  ref: 1de11eaa2ddf42e55e5c82661431e54ec9343552
+
+config:
+  overrides:
+    plugins/buildstream-plugins-community.bst: plugins/buildstream-plugins-community.bst
diff --git a/elements/os/filesystem-compose.bst b/elements/os/filesystem-compose.bst
new file mode 100644
index 00000000..bd6d8ff3
--- /dev/null
+++ b/elements/os/filesystem-compose.bst
@@ -0,0 +1,20 @@
+# SPDX-FileCopyrightText: 2025 Aleix Pol Gonzalez <[email protected]>
+# SPDX-License-Identifier: BSD-2-Clause
+
+kind: compose
+
+build-depends:
+- kde-linux-packages.bst:kde-buildstream.bst:os/deps.bst
+- os/initial-scripts.bst
+- os/os-release.bst
+- kde-linux-packages.bst:kde-buildstream.bst:freedesktop-sdk.bst:public-stacks/runtime-gnu.bst
+- kde-linux-packages.bst:components/debian.bst
+
+config:
+  exclude:
+  - debug
+  - doc
+  - tests
+  - shells
+  - static-blocklist
+  include-orphans: True
diff --git a/elements/os/filesystem.bst b/elements/os/filesystem.bst
new file mode 100644
index 00000000..fb7de8c4
--- /dev/null
+++ b/elements/os/filesystem.bst
@@ -0,0 +1,42 @@
+# SPDX-License-Identifier: BSD-2-Clause
+# SPDX-FileCopyrightText: 2026 Harald Sitter <[email protected]>
+
+kind: script
+
+build-depends:
+- os/filesystem-compose.bst
+
+variables:
+  install-root: /
+
+config:
+  commands:
+  # de-configure the audit system, we don't need it by default
+  - rm --recursive --force /etc/audit/audit.rules # auto generated; may not exist
+  - rm --recursive /etc/audit/plugins.d/*
+  - rm --recursive /etc/audit/rules.d/*
+  # Don't need the uncompressed kernel
+  - rm /usr/lib/modules/*/vmlinux
+  # Drop some static libs.
+  # Be very careful with what you add here.
+  # Some things are actually needed to build stuff! (notably some gcc .a files)
+  - rm /usr/lib/x86_64-linux-gnu/libQt*.a
+  - rm /usr/lib/x86_64-linux-gnu/libqpdf.a
+  # Don't need the thesaurus, we have no framework or app to consume them. And they are huge!
+  - rm --recursive /usr/share/locale/*/mythes
+  - rm --recursive /usr/share/mythes
+  # Same for hyphen, a hyphenation library of hunspell
+  - rm --recursive /usr/share/locale/*/hyphen
+  # Don't need hunspell either, we consume them from the flatpak runtime
+  - rm --recursive /usr/share/locale/*/hunspell
+  # Definitely don't need installed tests
+  - rm --recursive /usr/share/installed-tests
+  # GTK Demo stuff
+  - rm /usr/bin/gtk4-demo*
+  - rm /usr/share/applications/gtk3*.desktop
+  - rm /usr/share/applications/org.gtk.*.desktop
+  # Excessive vim leakage
+  - rm /usr/share/applications/gvim.desktop
+  # Debug utils. Super large and probably not useful 99.999999% of the time
+  - rm /usr/bin/lto-dump
+  - rm /usr/bin/llvm-exegesis
diff --git a/elements/os/initial-scripts.bst b/elements/os/initial-scripts.bst
new file mode 100644
index 00000000..a06aea15
--- /dev/null
+++ b/elements/os/initial-scripts.bst
@@ -0,0 +1,10 @@
+# SPDX-FileCopyrightText: 2025 Aleix Pol Gonzalez <[email protected]>
+# SPDX-License-Identifier: BSD-2-Clause
+
+kind: collect_initial_scripts
+
+build-depends:
+- kde-linux-packages.bst:kde-buildstream.bst:os/deps.bst
+
+config:
+  path: /etc/fdsdk/initial_scripts
diff --git a/elements/os/initrd-payload.bst b/elements/os/initrd-payload.bst
new file mode 100644
index 00000000..f0ee07e9
--- /dev/null
+++ b/elements/os/initrd-payload.bst
@@ -0,0 +1,34 @@
+# SPDX-FileCopyrightText: 2026 Aleix Pol <[email protected]>
+#
+# SPDX-License-Identifier: BSD-2-Clause
+
+kind: manual
+
+build-depends:
+- kde-linux-packages.bst:kde-buildstream.bst:freedesktop-sdk.bst:public-stacks/runtime-gnu.bst
+
+variables:
+  strip-binaries: ''
+
+environment:
+  INSTALL_ROOT: '%{install-root}'
+
+config:
+  install-commands:
+  - |
+    install -d "$INSTALL_ROOT/usr/lib"
+    install -d "$INSTALL_ROOT/usr/lib/udev/rules.d"
+    install -d "$INSTALL_ROOT/usr/lib/systemd/system-generators"
+    install -d "$INSTALL_ROOT/usr/lib/systemd/system/local-fs-pre.target.wants"
+    cp -a mkosi-extra-src/usr/lib/rootfs-transition "$INSTALL_ROOT/usr/lib/rootfs-transition"
+    cp -a mkosi-extra-src/usr/lib/btrfs-migrator "$INSTALL_ROOT/usr/lib/btrfs-migrator"
+    cp -a mkosi-extra-src/usr/lib/etc-factory "$INSTALL_ROOT/usr/lib/etc-factory"
+    cp -a mkosi-extra-src/usr/lib/systemd/system-generators/kde-linux-live-generator "$INSTALL_ROOT/usr/lib/systemd/system-generators/kde-linux-live-generator"
+    cp -a mkosi-extra-src/usr/lib/systemd/system-generators/kde-linux-mount-generator "$INSTALL_ROOT/usr/lib/systemd/system-generators/kde-linux-mount-generator"
+    cp -a mkosi-extra-src/usr/lib/systemd/system/etc-factory.service "$INSTALL_ROOT/usr/lib/systemd/system/etc-factory.service"
+    cp -a mkosi-extra-src/usr/lib/systemd/system/local-fs-pre.target.wants/etc-factory.service "$INSTALL_ROOT/usr/lib/systemd/system/local-fs-pre.target.wants/etc-factory.service"
+
+sources:
+- kind: local
+  path: mkosi.extra
+  directory: mkosi-extra-src
diff --git a/elements/os/initrd.bst b/elements/os/initrd.bst
new file mode 100644
index 00000000..db3e72f4
--- /dev/null
+++ b/elements/os/initrd.bst
@@ -0,0 +1,56 @@
+# SPDX-FileCopyrightText: 2026 Aleix Pol <[email protected]>
+#
+# SPDX-License-Identifier: BSD-2-Clause
+
+kind: script
+
+build-depends:
+- kde-linux-packages.bst:kde-buildstream.bst:freedesktop-sdk.bst:components/fakecap.bst
+- kde-linux-packages.bst:kde-buildstream.bst:freedesktop-sdk.bst:components/btrfs-progs.bst
+- kde-linux-packages.bst:kde-buildstream.bst:freedesktop-sdk.bst:components/dbus.bst
+- kde-linux-packages.bst:kde-buildstream.bst:freedesktop-sdk.bst:components/dracut.bst
+- kde-linux-packages.bst:kde-buildstream.bst:freedesktop-sdk.bst:components/shadow.bst
+- kde-linux-packages.bst:kde-buildstream.bst:freedesktop-sdk.bst:components/systemd.bst
+- kde-linux-packages.bst:kde-buildstream.bst:freedesktop-sdk.bst:components/tzdata.bst
+- kde-linux-packages.bst:kde-buildstream.bst:freedesktop-sdk.bst:vm/boot/efi/deps.bst
+- kde-linux-packages.bst:kde-buildstream.bst:freedesktop-sdk.bst:vm/boot/efi/initial-scripts.bst
+- kde-linux-packages.bst:kde-buildstream.bst:freedesktop-sdk.bst:vm/prepare-image.bst
+- kde-linux-packages.bst:kde-buildstream.bst:freedesktop-sdk.bst:public-stacks/runtime-gnu.bst
+- os/initrd-payload.bst
+- os/os-release.bst
+
+variables:
+  # A stable UUID namespace used by prepare-image.sh to derive reproducible root/EFI UUIDs and password salt.
+  uuidnamespace: df2427db-01ec-4c99-96b1-be3edb3cd9f6
+  # build.sh checks this artifact out into BUILDSTREAM_BOOTFS and mounts it at /boot
+  install-root: /boot
+
+environment:
+  LD_PRELOAD: /usr/libexec/fakecap/fakecap.so
+  FAKECAP_DB: /fakecap
+
+config:
+  commands:
+  - mkdir -p /fakecap
+  - mkdir -p /tmp
+  - mkdir -p /var/tmp
+  - mkdir -p /boot
+  - prepare-image.sh --sysroot / --rootpasswd root --seed "%{uuidnamespace}" >/tmp/vars
+  - echo '/usr/lib/x86_64-linux-gnu' >/etc/ld.so.conf
+  - |
+    . /tmp/vars
+    version="$(ls -1 /lib/modules | head -n1)"
+    mkdir -p /tmp/initrd-overlay/usr/lib/systemd/system-generators
+    mkdir -p /tmp/initrd-overlay/usr/lib/systemd/system/local-fs-pre.target.wants
+    mkdir -p /tmp/initrd-overlay/usr/lib/udev/rules.d
+    cp /usr/lib/kde-linux/os-release /tmp/initrd-overlay/usr/lib/os-release
+    cp /usr/lib/kde-linux/os-release /tmp/initrd-overlay/usr/lib/initrd-release
+    cp /usr/lib/udev/rules.d/90-image-dissect.rules /tmp/initrd-overlay/usr/lib/udev/rules.d/90-image-dissect.rules
+    dracut -v --xz --reproducible --fstab \
+      --no-machineid \
+      --kernel-image "/lib/modules/${version}/vmlinuz" \
+      --kver "${version}" \
+      --kernel-cmdline "rw console=tty0 console=ttyS0 quiet" \
+      --filesystems "ext4 btrfs erofs" \
+      --install 'basename grep fsck.ext4 systemd-dissect /usr/lib/btrfs-migrator /usr/lib/etc-factory /usr/lib/rootfs-transition /usr/lib/systemd/system-generators/kde-linux-live-generator /usr/lib/systemd/system-generators/kde-linux-mount-generator /usr/lib/systemd/system/etc-factory.service /usr/lib/systemd/system/local-fs-pre.target.wants/etc-factory.service /usr/lib/systemd/system/[email protected]' \
+      --include /tmp/initrd-overlay /
diff --git a/elements/os/os-release.bst b/elements/os/os-release.bst
new file mode 100644
index 00000000..26f3f5e9
--- /dev/null
+++ b/elements/os/os-release.bst
@@ -0,0 +1,48 @@
+# SPDX-FileCopyrightText: 2026 KDE Linux Contributors
+# SPDX-License-Identifier: BSD-2-Clause
+
+kind: manual
+
+(@):
+- include/kde-linux-image.yml
+
+build-depends:
+- kde-linux-packages.bst:kde-buildstream.bst:freedesktop-sdk.bst:public-stacks/runtime-gnu.bst
+
+variables:
+  strip-binaries: ''
+
+environment:
+  INSTALL_ROOT: '%{install-root}'
+
+config:
+  install-commands:
+  - |
+    install -d "$INSTALL_ROOT/usr/lib"
+    install -d "$INSTALL_ROOT/usr/lib/kde-linux"
+    install -d "$INSTALL_ROOT/etc"
+    cat > "$INSTALL_ROOT/usr/lib/os-release" <<EOF
+    NAME="KDE Linux"
+    PRETTY_NAME="KDE Linux"
+    ID="kde-linux"
+    DEFAULT_HOSTNAME="kde-linux"
+    VERSION_ID="%{kde-linux-version-date}"
+    BUILD_ID="%{kde-linux-build-id}"
+    ANSI_COLOR="38;2;61;174;233"
+    HOME_URL="https://linux.kde.org"
+    DOCUMENTATION_URL="https://community.kde.org/KDE_Linux"
+    SUPPORT_URL="https://kde.org/support/"
+    BUG_REPORT_URL="https://invent.kde.org/kde-linux/kde-linux/-/issues"
+    PRIVACY_POLICY_URL="https://kde.org/privacypolicy-apps/"
+    LOGO="/usr/share/pixmaps/kde-linux-logo.png"
+    IMAGE_ID="kde-linux"
+    IMAGE_VERSION="%{kde-linux-image-version}"
+    KDE_LINUX_COMMIT_SHA="%{kde-linux-commit-sha}"
+    KDE_LINUX_COMMIT_SHORT_SHA="%{kde-linux-commit-short-sha}"
+    KDE_LINUX_CI_URL="%{kde-linux-ci-url}"
+    KDE_LINUX_SYSUPDATE_ENDPOINT="sysupdate/v2"
+    EOF
+    cp "$INSTALL_ROOT/usr/lib/os-release" "$INSTALL_ROOT/usr/lib/kde-linux/os-release"
+    ln -sf ../usr/lib/os-release "$INSTALL_ROOT/etc/os-release"
+    printf 'KDE Linux \\n \\l\n' > "$INSTALL_ROOT/etc/issue"
+    printf 'KDE Linux %%h\n' > "$INSTALL_ROOT/etc/issue.net"
diff --git a/elements/os/systemd-initrd-compose.bst b/elements/os/systemd-initrd-compose.bst
new file mode 100644
index 00000000..81f6372a
--- /dev/null
+++ b/elements/os/systemd-initrd-compose.bst
@@ -0,0 +1,26 @@
+# SPDX-License-Identifier: BSD-2-Clause
+# SPDX-FileCopyrightText: 2026 Harald Sitter <[email protected]>
+
+kind: compose
+
+# Mind that we don't need to compose drivers we don't ship (e.g. nvidia) because they won't end up in the initrd
+# but get loaded after the switch-root.
+build-depends:
+- kde-linux-packages.bst:kde-buildstream.bst:freedesktop-sdk.bst:components/systemd.bst
+- kde-linux-packages.bst:kde-buildstream.bst:freedesktop-sdk.bst:components/linux.bst
+- kde-linux-packages.bst:kde-buildstream.bst:freedesktop-sdk.bst:components/linux-firmware.bst
+- kde-linux-packages.bst:kde-buildstream.bst:gnome-build-meta.bst:gnomeos-deps/intel-ucode.bst
+- os/os-release.bst
+- os/systemd-initrd-mkosi-extra.bst
+- kde-linux-packages.bst:kde-buildstream.bst:freedesktop-sdk.bst:public-stacks/runtime-gnu.bst
+
+config:
+  exclude:
+  - debug
+  - doc
+  - tests
+  - devel
+  - shells
+  - zoneinfo
+  - locale
+  include-orphans: True
diff --git a/elements/os/systemd-initrd-mkosi-extra.bst b/elements/os/systemd-initrd-mkosi-extra.bst
new file mode 100644
index 00000000..bba4468a
--- /dev/null
+++ b/elements/os/systemd-initrd-mkosi-extra.bst
@@ -0,0 +1,33 @@
+# SPDX-License-Identifier: BSD-2-Clause
+# SPDX-FileCopyrightText: 2026 Aleix Pol <[email protected]>
+# SPDX-FileCopyrightText: 2026 Harald Sitter <[email protected]>
+
+kind: manual
+
+build-depends:
+- kde-linux-packages.bst:kde-buildstream.bst:freedesktop-sdk.bst:public-stacks/runtime-gnu.bst
+- kde-linux-packages.bst:kde-buildstream.bst:freedesktop-sdk.bst:bootstrap/stripper.bst
+- kde-linux-packages.bst:kde-buildstream.bst:freedesktop-sdk.bst:components/binutils.bst # for objdump
+
+depends:
+- kde-linux-packages.bst:kde-buildstream.bst:freedesktop-sdk.bst:components/btrfs-progs.bst # runtime dep of btrfs stuff
+
+config:
+  install-commands:
+  - |
+    install -d "%{install-root}/usr/lib"
+    install -d "%{install-root}/usr/lib/udev/rules.d"
+    install -d "%{install-root}/usr/lib/systemd/system-generators"
+    install -d "%{install-root}/usr/lib/systemd/system/local-fs-pre.target.wants"
+    cp -a mkosi-extra-src/usr/lib/rootfs-transition "%{install-root}/usr/lib/rootfs-transition"
+    cp -a mkosi-extra-src/usr/lib/btrfs-migrator "%{install-root}/usr/lib/btrfs-migrator"
+    cp -a mkosi-extra-src/usr/lib/etc-factory "%{install-root}/usr/lib/etc-factory"
+    cp -a mkosi-extra-src/usr/lib/systemd/system-generators/kde-linux-live-generator "%{install-root}/usr/lib/systemd/system-generators/kde-linux-live-generator"
+    cp -a mkosi-extra-src/usr/lib/systemd/system-generators/kde-linux-mount-generator "%{install-root}/usr/lib/systemd/system-generators/kde-linux-mount-generator"
+    cp -a mkosi-extra-src/usr/lib/systemd/system/etc-factory.service "%{install-root}/usr/lib/systemd/system/etc-factory.service"
+    cp -a mkosi-extra-src/usr/lib/systemd/system/local-fs-pre.target.wants/etc-factory.service "%{install-root}/usr/lib/systemd/system/local-fs-pre.target.wants/etc-factory.service"
+
+sources:
+- kind: local
+  path: mkosi.extra
+  directory: mkosi-extra-src
diff --git a/elements/os/systemd-initrd-payload.bst b/elements/os/systemd-initrd-payload.bst
new file mode 100644
index 00000000..b8165b65
--- /dev/null
+++ b/elements/os/systemd-initrd-payload.bst
@@ -0,0 +1,27 @@
+# SPDX-License-Identifier: BSD-2-Clause
+# SPDX-FileCopyrightText: 2026 Harald Sitter <[email protected]>
+
+kind: script
+
+build-depends:
+- kde-linux-packages.bst:kde-buildstream.bst:freedesktop-sdk.bst:public-stacks/runtime-gnu.bst
+- os/systemd-initrd-compose.bst
+
+variables:
+  install-root: /
+
+config:
+  commands:
+  # de-configure the audit system, we don't need it by default
+  - rm --recursive --force /etc/audit/audit.rules # auto generated; may not exist
+  - rm --recursive /etc/audit/plugins.d/*
+  - rm --recursive /etc/audit/rules.d/*
+
+  # Remove some cruft pulled in by plymouth and friends
+  - rm --recursive /usr/share/terminfo
+  - rm --recursive /usr/share/misc
+  - rm --recursive /usr/share/mime
+  - rm --recursive /usr/share/bash-completion
+
+  # There is no need for charset conversion in the initrd. Besides, everything is UTF-8 on KDE Linux anyway.
+  - rm --recursive /usr/lib/x86_64-linux-gnu/gconv
diff --git a/elements/plugins/buildstream-plugins-community.bst b/elements/plugins/buildstream-plugins-community.bst
new file mode 100644
index 00000000..84563714
--- /dev/null
+++ b/elements/plugins/buildstream-plugins-community.bst
@@ -0,0 +1,10 @@
+# SPDX-FileCopyrightText: 2026 Aleix Pol <[email protected]>
+#
+# SPDX-License-Identifier: BSD-2-Clause
+
+kind: junction
+
+sources:
+- kind: tar
+  url: pypi:08/b4/4b5311dd4ea599bdc69d911263f5d3f8b4c14789d69265d7ea2be7e4e120/buildstream_plugins_community-2.3.0.tar.gz
+  ref: cdd3b73ff998e4145d2bb1a1215b961c65b073a4956609417ab747ef8f462c44
diff --git a/include/aliases.yml b/include/aliases.yml
new file mode 100644
index 00000000..72411f6b
--- /dev/null
+++ b/include/aliases.yml
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: BSD-2-Clause
+# SPDX-FileCopyrightText: 2025 Aleix Pol Gonzalez <[email protected]>
+
+aliases:
+  pypi: https://files.pythonhosted.org/packages/
+  kde: https://invent.kde.org/
+  invent: https://invent.kde.org/
diff --git a/mkosi.conf b/mkosi.conf
index 37c1d71f..18b1f730 100644
--- a/mkosi.conf
+++ b/mkosi.conf
@@ -2,8 +2,7 @@
 # SPDX-FileCopyrightText: 2023 Harald Sitter <[email protected]>
 
 [Distribution]
-Distribution=arch
-Mirror=https://mirror.23m.com/archlinux/
+Distribution=custom
 
 [Output]
 ImageId=kde-linux
@@ -12,6 +11,8 @@ SplitArtifacts=yes
 OutputDirectory=mkosi.output
 
 [Content]
+# BuildStream provides the base rootfs; mkosi only assembles the final image.
+BaseTrees=buildstream-rootfs
 # We do not want an initrd or any other boot artifacts, we generate all this stuff ourselves since we need more
 # control than mkosi gives us. Bootable also has the unfortunate side effect that the os-release file gets eaten
 # for some reason (supposedly as a side effect of the initrd creation?)
@@ -19,12 +20,15 @@ Bootable=no
 KernelCommandLine=
 # No root login thank you very much. We'll provision a live user as part of spinup
 # RootPassword=
+Bootloader=systemd-boot
+CleanPackageMetadata=no
+UnifiedKernelImages=no # buildstream builds it
 
 [Build]
+# needed to clone calamares, flatpak, etc
 WithNetwork=true
 # Make sure kernel-install knows where we expect the ESP to be mounted so it can create correct loader entries.
 Environment=BOOT_MNT=/usr/share/factory/boot
-PackageCacheDirectory=/var/cache/mkosi.pacman
 
 [Runtime]
 Console=gui
diff --git a/mkosi.conf.d/zz-buildstream.conf b/mkosi.conf.d/zz-buildstream.conf
new file mode 100644
index 00000000..68e0cf5e
--- /dev/null
+++ b/mkosi.conf.d/zz-buildstream.conf
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
+# SPDX-FileCopyrightText: 2026
+
+[Content]
+# BuildStream provides the full rootfs; disable mkosi package management.
+Packages=
+BuildPackages=
+VolatilePackages=
+RemovePackages=
diff --git a/mkosi.extra/etc/ld.so.conf.d/kde-linux-payload.conf b/mkosi.extra/etc/ld.so.conf.d/kde-linux-payload.conf
new file mode 100644
index 00000000..048c498e
--- /dev/null
+++ b/mkosi.extra/etc/ld.so.conf.d/kde-linux-payload.conf
@@ -0,0 +1,2 @@
+/usr/lib
+/usr/lib64
diff --git a/mkosi.extra/etc/ld.so.conf.d/kde-linux-payload.conf.license b/mkosi.extra/etc/ld.so.conf.d/kde-linux-payload.conf.license
new file mode 100644
index 00000000..0bf4a5a1
--- /dev/null
+++ b/mkosi.extra/etc/ld.so.conf.d/kde-linux-payload.conf.license
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
+# SPDX-FileCopyrightText: 2026 Aleix Pol Gonzalez <[email protected]>
diff --git a/mkosi.extra/etc/shells b/mkosi.extra/etc/shells
new file mode 100644
index 00000000..d43bb81b
--- /dev/null
+++ b/mkosi.extra/etc/shells
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
+# SPDX-FileCopyrightText: 2026 Harald Sitter <[email protected]>
+
+/bin/sh
+/bin/bash
+/bin/rbash
+/usr/bin/sh
+/usr/bin/bash
+/usr/bin/rbash
+/usr/bin/systemd-home-fallback-shell
+/usr/bin/git-shell
+/bin/zsh
+/usr/bin/zsh
diff --git a/mkosi.extra/live/usr/calamares/desktop/settings.conf b/mkosi.extra/live/usr/calamares/desktop/settings.conf
index bcee4bdf..ac1d6f01 100644
--- a/mkosi.extra/live/usr/calamares/desktop/settings.conf
+++ b/mkosi.extra/live/usr/calamares/desktop/settings.conf
@@ -3,7 +3,7 @@
 # SPDX-FileCopyrightText: 2017 Jonathan Riddell <[email protected]>
 # SPDX-FileCopyrightText: 2016 Rohan Garg <[email protected]>
 ---
-modules-search: [ local, /usr/lib/calamares/modules, /usr/share/calamares/modules  ]
+modules-search: [ local, /usr/lib/x86_64-linux-gnu/calamares/modules, /usr/lib/calamares/modules, /usr/share/calamares/modules  ]
 
 instances:
 - id: subvol
diff --git a/mkosi.extra/live/usr/lib/live-setup b/mkosi.extra/live/usr/lib/live-setup
index a0bae049..a56b9b7f 100755
--- a/mkosi.extra/live/usr/lib/live-setup
+++ b/mkosi.extra/live/usr/lib/live-setup
@@ -28,9 +28,6 @@ useradd --create-home --comment "Live User" live
 usermod --append --groups wheel live
 passwd --delete live
 
-# systemd is a bit unreliable with creating the file if the timezone is UTC, so make sure it's in place
-ln -s ../usr/share/zoneinfo/UTC /etc/localtime
-
 timedatectl set-timezone UTC
 localectl set-locale C.UTF-8
 
diff --git a/mkosi.extra/usr/bin/vi b/mkosi.extra/usr/bin/vi
new file mode 100755
index 00000000..6873ced3
--- /dev/null
+++ b/mkosi.extra/usr/bin/vi
@@ -0,0 +1,22 @@
+#!/usr/bin/bash
+# SPDX-FileCopyrightText: Arch Linux Contributors
+# SPDX-License-Identifier: ISC
+#
+# Calls `vim` using its `vi` compatibility mode (`-C`).
+# Ignores all `vim` configuration, except for the `EXINIT` environment
+# variable and the `.exrc` file, which are required by POSIX.
+# Accepts further options.
+
+if [[ -n "${EXINIT}" ]]; then
+  readonly VIMRC="$(mktemp)"
+  trap 'rm "${VIMRC}"' EXIT
+  printf '%s\n' "${EXINIT}" > "${VIMRC}"
+elif [[ -f "${HOME}/.exrc" ]]; then
+  readonly VIMRC="${HOME}/.exrc"
+elif [[ -f './.exrc' ]]; then
+  readonly VIMRC='./.exrc'
+else
+  readonly VIMRC='NONE'
+fi
+
+exec /usr/bin/vim -C -u "${VIMRC}" "$@"
diff --git a/mkosi.extra/etc/pam.d/kde b/mkosi.extra/usr/lib/pam.d/kde
similarity index 100%
rename from mkosi.extra/etc/pam.d/kde
rename to mkosi.extra/usr/lib/pam.d/kde
diff --git a/mkosi.extra/etc/pam.d/kde-fingerprint b/mkosi.extra/usr/lib/pam.d/kde-fingerprint
similarity index 100%
rename from mkosi.extra/etc/pam.d/kde-fingerprint
rename to mkosi.extra/usr/lib/pam.d/kde-fingerprint
diff --git a/mkosi.extra/etc/pam.d/kde-smartcard b/mkosi.extra/usr/lib/pam.d/kde-smartcard
similarity index 100%
rename from mkosi.extra/etc/pam.d/kde-smartcard
rename to mkosi.extra/usr/lib/pam.d/kde-smartcard
diff --git a/mkosi.extra/usr/lib/pam.d/system-auth b/mkosi.extra/usr/lib/pam.d/system-auth
new file mode 100644
index 00000000..04fb2bd3
--- /dev/null
+++ b/mkosi.extra/usr/lib/pam.d/system-auth
@@ -0,0 +1,29 @@
+#%PAM-1.0
+# SPDX-FileCopyrightText: Arch Linux Contributors
+# SPDX-License-Identifier: ISC
+
+auth       required                    pam_faillock.so      preauth
+# Optionally use requisite above if you do not want to prompt for the password
+# on locked accounts.
+-auth      [success=2 default=ignore]  pam_systemd_home.so
+auth       [success=1 default=bad]     pam_unix.so          try_first_pass nullok
+auth       [default=die]               pam_faillock.so      authfail
+auth       optional                    pam_permit.so
+auth       required                    pam_env.so
+auth       required                    pam_faillock.so      authsucc
+# If you drop the above call to pam_faillock.so the lock will be done also
+# on non-consecutive authentication failures.
+
+-account   [success=1 default=ignore]  pam_systemd_home.so
+account    required                    pam_unix.so
+account    optional                    pam_permit.so
+account    required                    pam_time.so
+
+-password  [success=1 default=ignore]  pam_systemd_home.so
+password   required                    pam_unix.so          try_first_pass nullok shadow
+password   optional                    pam_permit.so
+
+-session   optional                    pam_systemd_home.so
+session    required                    pam_limits.so
+session    required                    pam_unix.so
+session    optional                    pam_permit.so
diff --git a/mkosi.extra/usr/lib/pam.d/system-local-login b/mkosi.extra/usr/lib/pam.d/system-local-login
new file mode 100644
index 00000000..59e6dd8a
--- /dev/null
+++ b/mkosi.extra/usr/lib/pam.d/system-local-login
@@ -0,0 +1,8 @@
+#%PAM-1.0
+# SPDX-FileCopyrightText: Arch Linux Contributors
+# SPDX-License-Identifier: ISC
+
+auth      include   system-login
+account   include   system-login
+password  include   system-login
+session   include   system-login
diff --git a/mkosi.extra/usr/lib/pam.d/system-login b/mkosi.extra/usr/lib/pam.d/system-login
new file mode 100644
index 00000000..03185b34
--- /dev/null
+++ b/mkosi.extra/usr/lib/pam.d/system-login
@@ -0,0 +1,23 @@
+#%PAM-1.0
+# SPDX-FileCopyrightText: Arch Linux Contributors
+# SPDX-License-Identifier: ISC
+
+auth       required   pam_shells.so
+auth       requisite  pam_nologin.so
+auth       include    system-auth
+
+account    required   pam_access.so
+account    required   pam_nologin.so
+account    include    system-auth
+
+password   include    system-auth
+
+session    optional   pam_loginuid.so
+session    optional   pam_keyinit.so       force revoke
+session    include    system-auth
+# session    optional   pam_lastlog2.so      silent
+session    optional   pam_motd.so
+session    optional   pam_mail.so          dir=/var/spool/mail standard quiet
+session    optional   pam_umask.so
+-session   optional   pam_systemd.so
+session    required   pam_env.so
diff --git a/mkosi.extra/usr/lib/pam.d/system-remote-login b/mkosi.extra/usr/lib/pam.d/system-remote-login
new file mode 100644
index 00000000..59e6dd8a
--- /dev/null
+++ b/mkosi.extra/usr/lib/pam.d/system-remote-login
@@ -0,0 +1,8 @@
+#%PAM-1.0
+# SPDX-FileCopyrightText: Arch Linux Contributors
+# SPDX-License-Identifier: ISC
+
+auth      include   system-login
+account   include   system-login
+password  include   system-login
+session   include   system-login
diff --git a/mkosi.extra/usr/lib/pam.d/system-services b/mkosi.extra/usr/lib/pam.d/system-services
new file mode 100644
index 00000000..92d63090
--- /dev/null
+++ b/mkosi.extra/usr/lib/pam.d/system-services
@@ -0,0 +1,13 @@
+#%PAM-1.0
+# SPDX-FileCopyrightText: Arch Linux Contributors
+# SPDX-License-Identifier: ISC
+
+auth      sufficient  pam_permit.so
+
+account   include     system-auth
+
+session   optional    pam_loginuid.so
+session   required    pam_limits.so
+session   required    pam_unix.so
+session   optional    pam_permit.so
+session   required    pam_env.so
diff --git a/mkosi.extra/usr/lib/rebuild-efi b/mkosi.extra/usr/lib/rebuild-efi
index 16df8d07..62e3ba1d 100755
--- a/mkosi.extra/usr/lib/rebuild-efi
+++ b/mkosi.extra/usr/lib/rebuild-efi
@@ -8,7 +8,7 @@ set -ex
 
 kernel_version="$1"
 if [ -z "$kernel_version" ]; then
-  versions=(/usr/lib/modules/*)
+  versions=(/usr/lib/modules/*.*.*)
   version="${versions[-1]}"
   kernel_version="$(basename "$version")"
 fi
@@ -18,14 +18,9 @@ if [ -z "$kernel_version" ]; then
   exit 1
 fi
 
-# NOTE: plymouth MUST be after systemd as per the wiki!
-cat <<- EOF > mkinitcpio.conf
-MODULES=(overlay)
-BINARIES=()
-FILES=()
-HOOKS=(base systemd modconf kms keyboard block sd-encrypt filesystems fsck systemd-extension plymouth microcode sd-shutdown)
-EOF
+initrd=/boot/initramfs-$kernel_version.img
 
+# NOTE: plymouth MUST be after systemd as per the wiki!
 echo "rw \
   systemd.volatile=overlay systemd.firstboot=false systemd.hostname=kde-linux kde-linux.live=1 plasma.live.user=live \
   lsm=landlock,lockdown,yama,integrity,bpf \
@@ -36,10 +31,9 @@ echo "rw \
   amdgpu.dcdebugmask=0x10 \
   nowatchdog \
   vt.global_cursor_default=0 quiet splash plymouth.ignore-serial-consoles loglevel=3" > cmdline
-mkinitcpio --config mkinitcpio.conf --generate initrd --kernel "$kernel_version"
 ukify build \
   --linux /usr/lib/modules/$kernel_version/vmlinuz \
-  --initrd initrd \
+  --initrd "$initrd" \
   --cmdline @cmdline \
   --output live.efi
 
@@ -69,10 +63,9 @@ echo "rw rootflags=subvol=@system,compress=zstd:-4,lazytime \
   systemd.hostname=kde-linux \
   nowatchdog \
   vt.global_cursor_default=0 quiet splash plymouth.ignore-serial-consoles loglevel=3" > cmdline
-mkinitcpio --config mkinitcpio.conf --generate initrd --kernel "$kernel_version"
 ukify build \
   --linux /usr/lib/modules/$kernel_version/vmlinuz \
-  --initrd initrd \
+  --initrd "$initrd" \
   --cmdline @cmdline \
   --output kde-linux.efi
 
diff --git a/mkosi.extra/usr/lib/systemd/system-generators/kde-linux-live-generator b/mkosi.extra/usr/lib/systemd/system-generators/kde-linux-live-generator
index 67ce77f7..ca3e76b1 100755
--- a/mkosi.extra/usr/lib/systemd/system-generators/kde-linux-live-generator
+++ b/mkosi.extra/usr/lib/systemd/system-generators/kde-linux-live-generator
@@ -17,10 +17,13 @@ if ! grep "kde-linux.live=1" /proc/cmdline; then
     exit 0
 fi
 
-if [ "$(readlink --canonicalize /dev/disk/by-partlabel/KDELinuxLive)" != "$(readlink --canonicalize /dev/gpt-auto-root)" ]; then
-    echo "gpt-auto-root is not KDELinuxLive"
-    exit 0
-fi
+mkdir -p "$normal_dir/systemd-volatile-root.service.d" || true
+cat <<- EOF > "$normal_dir/systemd-volatile-root.service.d/50-kde-linux-live.conf"
+# Generated by $(basename "$0")
+[Unit]
+Requires=sysroot.mount
+After=sysroot.mount
+EOF
 
 cat <<- EOF > "$normal_dir/var-lib-flatpak.mount"
 # Generated by $(basename "$0")
diff --git a/mkosi.extra/usr/lib/systemd/system-preset/00-kde-linux.preset b/mkosi.extra/usr/lib/systemd/system-preset/00-kde-linux.preset
index d67b4be0..1ce10639 100644
--- a/mkosi.extra/usr/lib/systemd/system-preset/00-kde-linux.preset
+++ b/mkosi.extra/usr/lib/systemd/system-preset/00-kde-linux.preset
@@ -50,25 +50,9 @@ enable kde-linux-opt-cleaner-mask.service
 enable plasma-setup-live-system.service
 
 # KMSCON
-enable kmsconvt@
-enable [email protected]
-
-# Disable stuff we don't want
-# ===========================
-# getty - we use kmscon
-disable [email protected]
 disable [email protected]
-disable [email protected]
+enable [email protected]
 
 # networkd - we use networkmanager
 disable systemd-networkd.service
 disable systemd-networkd-wait-online.service
-
-# Pacman - we don't do packages
-disable archlinux-keyring-wkd-sync.timer
-disable [email protected]
-disable [email protected]
-disable [email protected]
-disable [email protected]
-disable [email protected]
-disable [email protected]
diff --git a/mkosi.extra/usr/lib/tmpfiles.d/etc.conf b/mkosi.extra/usr/lib/tmpfiles.d/etc.conf
index 58cf71fa..b8ca88c8 100644
--- a/mkosi.extra/usr/lib/tmpfiles.d/etc.conf
+++ b/mkosi.extra/usr/lib/tmpfiles.d/etc.conf
@@ -7,9 +7,4 @@
 L /etc/os-release - - - - ../usr/lib/os-release
 L+ /etc/mtab - - - - ../proc/self/mounts
 
-# KMSCON
-L+ /etc/systemd/system/[email protected]                          - - - - /usr/lib/systemd/system/[email protected]
-L+ /etc/systemd/system/[email protected]                      - - - - /usr/lib/systemd/system/[email protected]
-L+ /etc/systemd/system/getty.target.wants/[email protected] - - - - /usr/lib/systemd/system/[email protected]
-
 # Prefer the etc-factory tool over adding things here.
diff --git a/mkosi.finalize.d/10-modify-nsswitch.py.chroot b/mkosi.finalize.d/10-modify-nsswitch.py.chroot
index 42dbeca4..81f4a289 100755
--- a/mkosi.finalize.d/10-modify-nsswitch.py.chroot
+++ b/mkosi.finalize.d/10-modify-nsswitch.py.chroot
@@ -8,7 +8,7 @@ import sys
 
 def replace_lines_in_place(lines):
     for i, line in enumerate(lines):
-        if not line.startswith("hosts: mymachines resolve"):
+        if not line.startswith("hosts: "):
             continue
 
         lines[i] = line.replace("mymachines", "mymachines mdns_minimal [NOTFOUND=return]", 1)
@@ -16,7 +16,7 @@ def replace_lines_in_place(lines):
     raise RuntimeError("Expected modification but no changes were made.")
 
 def modify_nsswitch():
-    with open("/etc/nsswitch.conf", "r+") as file:
+    with open("/usr/share/factory/etc/nsswitch.conf", "r+") as file:
         lines = file.readlines()
         replace_lines_in_place(lines)
         file.seek(0)
diff --git a/mkosi.finalize.d/40-core.sh.chroot b/mkosi.finalize.d/40-core.sh.chroot
index 1f820ad7..ef7f7c67 100755
--- a/mkosi.finalize.d/40-core.sh.chroot
+++ b/mkosi.finalize.d/40-core.sh.chroot
@@ -6,7 +6,6 @@ set -ex
 
 userdel --remove --force builder || true
 passwd --delete root
-passwd --lock root
 
 if [ -f "$SRCDIR/.secure_files/gpg.public.key" ]; then # only useful and available for publishing branches
     # Put our key into the systemd keyring
@@ -21,25 +20,6 @@ if [ -f "$SRCDIR/.secure_files/gpg.public.key" ]; then # only useful and availab
     # https://invent.kde.org/kde-linux/kde-linux/-/issues/199
 fi
 
-# Uninstall solaar and sane, but keep their udev rules.
-# This ensures that they stay up to date.
-UDEV_BACKUP_DIR=$(mktemp -d)
-pacman -Qlq solaar sane | grep '^/usr/lib/udev/' | xargs -r cp -a --parents -t "$UDEV_BACKUP_DIR"
-pacman -Rns --noconfirm solaar sane
-cp -a "$UDEV_BACKUP_DIR"/* /
-rm -rf "$UDEV_BACKUP_DIR"
-
-# De-initialize pacman
-rm -rf \
-    /etc/pacman.d/gnupg \
-    /.gnupg \
-    /var/cache/pacman \
-    /var/lib/pacman \
-    /var/log/pacman.log
-
-## Pacman being present confuses users into thinking they can use it to install packages.
-rm -f /usr/bin/pacman
-
 # Remove all excess things we don't want in the final image
 
 ## locale-gen doesn't work because /usr is read-only. Removing it means calamares won't attempt to use it.
diff --git a/mkosi.finalize.d/99-etc.sh.chroot b/mkosi.finalize.d/99-etc.sh.chroot
index 7ff8ad58..90aaf58c 100755
--- a/mkosi.finalize.d/99-etc.sh.chroot
+++ b/mkosi.finalize.d/99-etc.sh.chroot
@@ -23,31 +23,20 @@ echo "deny = 12" >> /etc/security/faillock.conf
 rm --recursive --force /usr/share/factory/etc/pam.d
 
 # Copy all of etc into factory dir for tmpfiles.d (see tmpfiles.d docs).
+# Exclude the content that we absolutely do not want because it is machine/installation dependent.
 [ -d /usr/share/factory ] || mkdir /usr/share/factory
-cp --archive --no-target-directory --update=all /etc /usr/share/factory/etc
-
-# Clean up factory content that we absolutely do not want because it is machine/installation dependent.
-cd /usr/share/factory/etc
-rm --force \
-    .pwd.lock \
-    passwd \
-    passwd- \
-    shadow \
-    shadow- \
-    gshadow \
-    gshadow- \
-    group \
-    group- \
-    localtime \
-    machine-id \
-    crypttab \
-    vconsole.conf \
-    hostname \
-    locale.conf
-
-    # These are actually needed and must be copied from the factory onto the host. If they are missing useradd will
-    # not configure subuids, breaking podman for instance.
-    # subuid \
-    # subgid- \
-    # subgid \
-    # subgid- \
+cd /etc
+rsync --archive --update \
+    --exclude='.pwd.lock' \
+    --exclude='passwd*' \
+    --exclude='shadow*' \
+    --exclude='gshadow*' \
+    --exclude='group*' \
+    --exclude='localtime' \
+    --exclude='machine-id' \
+    --exclude='crypttab' \
+    --exclude='resolv.conf' \
+    --exclude='vconsole.conf' \
+    --exclude='hostname' \
+    --exclude='locale.conf' \
+    /etc/ /usr/share/factory/etc/
diff --git a/mkosi.images/initrd-build/mkosi.conf b/mkosi.images/initrd-build/mkosi.conf
new file mode 100644
index 00000000..45bcd9bb
--- /dev/null
+++ b/mkosi.images/initrd-build/mkosi.conf
@@ -0,0 +1,121 @@
+# SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
+# SPDX-FileCopyrightText: 2026 Harald Sitter <[email protected]>
+
+# Partially a huge hack to work around https://github.com/systemd/mkosi/issues/4397
+# This subimage produces nothing itself. Rather it gets mkosi to build a default initrd.
+# We then manually unpack it here and prepare it for pickup by the actual UKI images.
+
+# ALSO this is a convenient place to inject an initrd-exclusive relationship that runs udev trigger to load modules
+# after the switch-root pivot into the sysroot.
+# We only have the tiniest set of kernel modules in the initrd to get us out of initrd. All additional stuff such as GPU
+# gets loaded after the switch-root. This allows us to keep all firmwars out of the initrd and consequently sport a reasonably sized
+# unified kernel image.
+
+[Output]
+ImageVersion= # disable to get a stable name "initrd-build" without version or anything
+Format=directory
+
+[Content]
+Initrds=default
+MakeInitrd=yes
+UnifiedKernelImages=no
+Bootable=no
+KernelModules=
+        # Default from mkosi/resources/mkosi-initrd/mkosi.conf
+        ahci
+        amd_atl
+        amd_ctl
+        amd-pmc
+        amd64_edac
+        atkbd
+        autofs4
+        binfmt_misc
+        btrfs
+        cdrom
+        cfg80211
+        configfs
+        crc-ccitt
+        dm-crypt
+        dm-integrity
+        dm-mod
+        dm-multipath
+        dm-raid
+        dm-verity
+        dmi-sysfs
+        edac_mce_amd
+        efi-pstore
+        efivarfs
+        erofs
+        evdev
+        ext4
+        firmware_attributes_class
+        hid-generic
+        i2c-algo-bit
+        i2c_hid_acpi
+        i2c-mux
+        i2c-smbus
+        i8042
+        intel_pmc_ssram_telemetry
+        intel_rapl_common
+        intel-uncore-frequency-common
+        intel-vsec
+        kvm
+        libphy
+        loop
+        mdio_devres
+        mei
+        nvme
+        nvmet-tcp
+        overlay
+        parport
+        platform_profile
+        pmt_telemetry
+        qemu_fw_cfg
+        raid[0-9]*
+        rapl
+        scsi_mod
+        sd_mod
+        sr_mod
+        serio
+        sg
+        skx_edac_common
+        squashfs
+        thunderbolt_net
+        tpm_tis
+        tpm_vtpm_proxy
+        typec_ucsi
+        ucsi_acpi
+        usbhid
+        usb-storage
+        vfat
+        video
+        virtio_balloon
+        virtio_blk
+        virtio_console
+        virtio_dma_buf
+        virtio_mmio
+        virtio_net
+        virtio_pci
+        virtio_scsi
+        virtio-rng
+        virtiofs
+        vmd
+        vmw_vsock_virtio_transport
+        vsock
+        watchdog
+        wmi
+        wmi-bmof
+        x_tables
+        xfs
+        xhci-pci-renesas
+        /fs/nls/
+        crypto/
+        -/drivers/crypto/ # exclude specialized hardware
+        ccp_crypto # AMD crypto accelerator available in ryzen
+        zram      # for early/systemd-zram-setup
+        nfnetlink # for firewalld.service
+        # KDE Linux adjustments
+        -xfs # very large and we heavily rely on btrfs for the rootfs, so xfs could only possibly be used for extra mounts after switch-root
+        -ext4 # we heavily rely on btrfs for the rootfs, so ext4 could only possibly be used for extra mounts after switch-root
+        -watchdog # we don't run watchdogs in KDE Linux
+        -nfnetlink # we don't start firewalld in the initrd
diff --git a/mkosi.images/initrd-build/mkosi.prepare b/mkosi.images/initrd-build/mkosi.prepare
new file mode 100755
index 00000000..2dab67a6
--- /dev/null
+++ b/mkosi.images/initrd-build/mkosi.prepare
@@ -0,0 +1,40 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
+# SPDX-FileCopyrightText: 2026 Harald Sitter <[email protected]>
+
+set -eux
+
+cd "$BUILDROOT"
+zstd -c --decompress "$SRCDIR"/mkosi.output/initrd.cpio.zst | cpio --extract --make-directories --preserve-modification-time
+
+for dir in "$SRCDIR"/buildstream-initrdfs/lib/modules/*; do
+    name=$(basename "$dir")
+    target="$BUILDROOT/usr/lib/modules/$name"
+    # target must already exist since the initrd tree was seeded by the same directory!
+
+    # In an unfortunate turn of events we need to put the vmlinuz in the tree so that the ukis find it.
+    # Because of https://github.com/systemd/mkosi/issues/4397 that unfortunately also means it will be
+    # in the actual initrd. Nothing to be done about it except fix mkosi.
+    cp "$dir/vmlinuz" "$target/"
+done
+
+# Make sure we don't accidentally leak useless artifacts into the initrd
+rm --recursive --force "$BUILDROOT"/usr/src
+rm --recursive --force "$BUILDROOT"/usr/include
+rm --recursive --force "$BUILDROOT"/usr/lib/debug
+
+# Next let's inject our bespoke udev trigger. The way this works is that systemd will shut down the switch-root service
+# and then we force a trigger run so the modules get loaded as necessary, ASAP.
+
+cd "$BUILDROOT"/usr/lib/systemd/system/
+[ -d initrd-switch-root.service.d ] || mkdir initrd-switch-root.service.d
+cat > initrd-switch-root.service.d/kde-linux-udev.conf <<'EOF'
+[Service]
+ExecStopPost=systemctl --no-block systemd-udev-trigger.service
+EOF
+
+[ -d breakpoint-pre-switch-root.service.d ] || mkdir breakpoint-pre-switch-root.service.d
+cat > breakpoint-pre-switch-root.service.d/kde-linux-udev.conf <<'EOF'
+[Service]
+ExecStopPost=systemctl --no-block systemd-udev-trigger.service
+EOF
diff --git a/mkosi.images/uki.live/mkosi.conf b/mkosi.images/uki.live/mkosi.conf
new file mode 100644
index 00000000..22d8ef2d
--- /dev/null
+++ b/mkosi.images/uki.live/mkosi.conf
@@ -0,0 +1,28 @@
+# SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
+# SPDX-FileCopyrightText: 2026 Harald Sitter <[email protected]>
+
+[Output]
+ImageVersion= # disable to get a stable name without version or anything
+ImageId=kde-linux
+Format=uki
+ElTorito=no
+
+[Config]
+Dependencies=initrd-build
+
+[Content]
+BaseTrees=../../mkosi.output/initrd-build
+UnifiedKernelImages=yes
+Bootloader=uki
+Bootable=yes
+KernelCommandLine=
+    rw
+    systemd.volatile=overlay systemd.firstboot=false kde-linux.live=1 plasma.live.user=live
+    lsm=landlock,lockdown,yama,integrity,bpf
+    zswap.enabled=0
+    preempt=full threadirqs
+    nohz=on nohz_full=all
+    rcu_nocbs=all rcutree.enable_rcu_lazy=1
+    amdgpu.dcdebugmask=0x10
+    nowatchdog
+    vt.global_cursor_default=0 quiet splash plymouth.ignore-serial-consoles loglevel=3
diff --git a/mkosi.images/uki/mkosi.conf b/mkosi.images/uki/mkosi.conf
new file mode 100644
index 00000000..653a2d85
--- /dev/null
+++ b/mkosi.images/uki/mkosi.conf
@@ -0,0 +1,27 @@
+# SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
+# SPDX-FileCopyrightText: 2026 Harald Sitter <[email protected]>
+
+[Output]
+ImageVersion= # disable to get a stable name without version or anything
+ImageId=kde-linux
+Format=uki
+ElTorito=no
+
+[Config]
+Dependencies=initrd-build
+
+[Content]
+BaseTrees=../../mkosi.output/initrd-build
+UnifiedKernelImages=yes
+Bootloader=uki
+Bootable=yes
+KernelCommandLine=
+    rw rootflags=subvol=@system,compress=zstd:-4,lazytime
+    lsm=landlock,lockdown,yama,integrity,bpf
+    zswap.enabled=0
+    preempt=full threadirqs
+    nohz=on nohz_full=all
+    rcu_nocbs=all rcutree.enable_rcu_lazy=1
+    amdgpu.dcdebugmask=0x10
+    nowatchdog
+    vt.global_cursor_default=0 quiet splash plymouth.ignore-serial-consoles loglevel=3
diff --git a/mkosi.initrd.conf b/mkosi.initrd.conf
new file mode 100644
index 00000000..bc9ad420
--- /dev/null
+++ b/mkosi.initrd.conf
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
+# SPDX-FileCopyrightText: 2026 Harald Sitter <[email protected]>
+
+[Content]
+BaseTrees=buildstream-initrdfs
diff --git a/mkosi.postinst.chroot b/mkosi.postinst.chroot
index 8e59ceb1..9933935d 100755
--- a/mkosi.postinst.chroot
+++ b/mkosi.postinst.chroot
@@ -6,71 +6,21 @@ set -ex
 
 env
 
-# Safety nets to prevent excessive breakage
-## sudo should have sticky bit set
-[ -u /usr/bin/sudo ] || exit 1
-## newuidmap should have a capability set
-[ "$(getcap /usr/bin/newuidmap)" != "" ] || exit 1
-
 mkdir --mode 0700 /system # for the kde-linux-overlay.service
 
 export SYSTEMD_ESP_PATH="$BOOT_MNT"
-mkdir --mode 0700 "$SYSTEMD_ESP_PATH"
+mkdir -p --mode 0700 "$SYSTEMD_ESP_PATH"
 bootctl install
 echo 'timeout 7' >> "$SYSTEMD_ESP_PATH/loader/loader.conf"
-cp /usr/share/edk2-shell/x64/Shell.efi "$SYSTEMD_ESP_PATH/shellx64.efi"
-
-# Meanwhile cleanup a bit
-## Unnecessary for us
-pacman --remove --noconfirm qt6-doc qt6-examples || true
-# FIXME: needed by cxx-rust-cssparser; can't remove these for now
-# pacman --remove --noconfirm corrosion rust || true
-# FIXME: pulled in as a secret service provider
-pacman --remove --noconfirm gnome-keyring
-
-# No packagekit support or AppStream metadata in discover please! We don't want discover talking about pacman things.
-pacman --remove --noconfirm packagekit libpackagekit-glib archlinux-appstream-data || true
+cp /usr/share/ovmf/Shell.efi "$SYSTEMD_ESP_PATH/"
 rm -rf /usr/share/swcatalog
 
-# Calamares
-cd /tmp
-# We're building Calamares from master, due to https://codeberg.org/Calamares/calamares/pulls/2470 not being in a release yet.
-# It can be switched back to build from the latest release once a new release is cut that includes that PR.
-#LATEST_RELEASE=$(curl -s "https://codeberg.org/api/v1/repos/Calamares/calamares/releases" | jq -r '.[0].tag_name')
-#git clone --branch "$LATEST_RELEASE" --depth 1 https://codeberg.org/Calamares/calamares.git
-git clone --depth 1 https://codeberg.org/Calamares/calamares.git
-cmake -S calamares -B calamares/build -DCMAKE_BUILD_TYPE=MinSizeRel -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_TESTING=OFF -DWITH_QT6=ON
-cmake --build calamares/build "-j$(nproc)"
-DESTDIR=/live/ cmake --install calamares/build
-
+mkdir -p /usr/share/icons/default/
 cat <<- EOF > /usr/share/icons/default/index.theme
 [Icon Theme]
 Inherits=breeze_cursors
 EOF
 
-# WARNING: only set up os-release after the build otherwise kde-build doesn't know how to handle the system currently
-cat <<- EOF > /usr/lib/os-release
-NAME="KDE Linux"
-PRETTY_NAME="KDE Linux"
-ID=kde-linux
-DEFAULT_HOSTNAME=kde-linux
-VERSION_ID="$VERSION_DATE"
-BUILD_ID=$CI_COMMIT_SHORT_SHA
-ANSI_COLOR="38;2;61;174;233"
-HOME_URL="https://linux.kde.org"
-DOCUMENTATION_URL="https://community.kde.org/KDE_Linux"
-SUPPORT_URL="https://kde.org/support/"
-BUG_REPORT_URL="https://invent.kde.org/kde-linux/kde-linux/-/issues"
-PRIVACY_POLICY_URL="https://kde.org/privacypolicy-apps/"
-LOGO=/usr/share/pixmaps/kde-linux-logo.png
-IMAGE_ID=kde-linux
-IMAGE_VERSION=$IMAGE_VERSION
-# KDE Linux specific keys.
-KDE_LINUX_COMMIT_SHA=$CI_COMMIT_SHA
-KDE_LINUX_COMMIT_SHORT_SHA=$CI_COMMIT_SHORT_SHA
-KDE_LINUX_CI_URL=$CI_PIPELINE_URL
-KDE_LINUX_SYSUPDATE_ENDPOINT=sysupdate/v2
-EOF
 [ -f /usr/lib/os-release ] || false
 cat /usr/lib/os-release
 
@@ -155,6 +105,12 @@ for theme in $(plymouth-set-default-theme --list); do
     fi
 done
 
-cd /tmp
-/usr/lib/rebuild-efi
-mv -v ./*.efi /
+for f in /etc/fdsdk/initial_scripts/*; do
+    $f /
+done
+
+# Safety nets to prevent excessive breakage
+## sudo should have sticky bit set
+[ -u /usr/bin/sudo ] || exit 1
+## newuidmap should have a capability set
+[ "$(getcap /usr/bin/newuidmap)" != "" ] || exit 1
diff --git a/mkosi.sandbox/etc/pacman.d/.gitignore b/mkosi.sandbox/etc/pacman.d/.gitignore
deleted file mode 100644
index b8fbfc9e..00000000
--- a/mkosi.sandbox/etc/pacman.d/.gitignore
+++ /dev/null
@@ -1,4 +0,0 @@
-# SPDX-FileCopyrightText: none
-# SPDX-License-Identifier: CC0-1.0
-
-*
diff --git a/permission-fix.sh b/permission-fix.sh
index 7e67c9da..23a4d292 100755
--- a/permission-fix.sh
+++ b/permission-fix.sh
@@ -10,7 +10,7 @@
 # do not recurse into generated trees such as a stale mkosi.output because
 # that can make this step unexpectedly expensive.
 
-DIRS="mkosi.conf.d mkosi.extra mkosi.finalize.d mkosi.repart mkosi.sandbox mkosi.skeleton"
+DIRS="mkosi.conf.d mkosi.extra mkosi.finalize.d mkosi.repart mkosi.skeleton"
 
 find $DIRS -type d -exec chmod 755 {} + # ensure all directories are rwxr-xr-x
 find $DIRS -type f -perm /111 -exec chmod 755 {} + # ensure all executable files (-perm filters by permission) has rwxr-xr-x
diff --git a/project.conf b/project.conf
new file mode 100644
index 00000000..779c8c1b
--- /dev/null
+++ b/project.conf
@@ -0,0 +1,76 @@
+# SPDX-FileCopyrightText: 2025 Aleix Pol Gonzalez <[email protected]>
+# SPDX-License-Identifier: BSD-2-Clause
+
+# Unique project name
+name: kde-linux
+
+# Required BuildStream version
+min-version: 2.5
+
+# Subdirectory where elements are stored
+element-path: elements
+
+(@):
+- kde-linux-packages.bst:freedesktop-sdk.bst:include/runtime.yml
+- kde-linux-packages.bst:freedesktop-sdk.bst:include/arch.yml
+- include/aliases.yml
+
+# Options to specify for the project, these provide
+# command line switches which control the behavior of
+# conditional directives in the element.bst files.
+#
+options:
+  arch:
+    type: arch
+    description: Machine architecture
+    variable: arch
+    values:
+    - aarch64
+    - x86_64
+    - riscv64
+  minimal_vm:
+    type: flags
+    description: Parts to include in minimal vm builds (firmware, locale).
+    values:
+    - firmware
+    - locale
+    default:
+    - firmware
+    - locale
+
+sandbox:
+  build-arch: '%{arch}'
+
+variables:
+  branch: 'qt6.11'
+  fsdk-branch: master
+  runstatedir: "/run"
+
+environment:
+# These need getting set so that projects can run tools and not get weird warnings.
+# trigger to adding this was qca's usage of qmake -query (which in turn comes from Qt upstream)
+  LANG: C.UTF-8
+  LC_ALL: C.UTF-8
+
+plugins:
+- origin: junction
+  junction: plugins/buildstream-plugins-community.bst
+  sources:
+  - git_repo
+
+- origin: junction
+  junction: kde-linux-packages.bst:kde-buildstream.bst:freedesktop-sdk.bst
+  elements:
+  - collect_initial_scripts
+  - uki_builder
+
+sources:
+  git_repo:
+    config:
+      ref-format: git-describe
+
+artifacts:
+- url: https://buildstream.cache.kde-linux.haraldsitter.eu:11001
+
+source-caches:
+- url: https://buildstream.cache.kde-linux.haraldsitter.eu:11001
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.