Tromso is a BuildStream-based KDE Linux OCI/bootc image, modeled on Project Bluefin's projectbluefin/dakota.
It builds KDE Plasma 6 on top of freedesktop-sdk. All KDE/Plasma/freedesktop-sdk
.bst elements live directly in this repo's elements/ tree (kde/,
kde-linux-deps/, kde-linux-system/, core-deps/, core/,
freedesktop-sdk.bst, patches/, files/, keys/) — consolidated in from
the former tuna-os/kde-build-meta junctioned repo (itself a BuildStream
port of GNOME OS's gnome-build-meta scaffolding rebranded for KDE, not an
official KDE project) to eliminate a class of junction-nesting bugs and
separate-repo staleness tracking. tuna-os/kde-build-meta is retired/archived;
there is no longer a second repo or junction to keep in sync.
NEVER invent workarounds for build issues. For any infrastructure, bootc, systemd, kernel, or non-KDE/QT packages:
- FIRST: Clone and examine
/var/home/james/reference-repos/dakotaand/var/home/james/reference-repos/gnome-build-meta— those paths are local to the original maintainer's machine; if absent, clonehttps://github.com/projectbluefin/dakotaandhttps://gitlab.gnome.org/GNOME/gnome-build-metainstead - ALWAYS: Copy the
.bstpatterns and approaches from these known-good repos - NEVER: Use pre-built binaries, shortcuts, or workarounds to bypass build failures
- EXAMPLE: When bootc compilation fails with Cargo DNS errors:
- Don't create a bootc import element with a pre-built binary ❌
- Instead, examine how Dakota/gnome-build-meta compile bootc in their CI ✓
- Copy their exact
.bstconfiguration and build infrastructure
| Situation | Reference |
|---|---|
| Bootc build issues | Dakota CI config + gnome-build-meta |
| Boot infrastructure (systemd-boot, fwupd, initramfs) | gnome-build-meta |
| OCI composition, layering, or export | Dakota's oci/ elements |
| Non-KDE package configuration | gnome-build-meta |
| KDE package cmake flags, dependencies | Arch Linux PKGBUILD |
Bootc is a critical tool for creating bootable OCI images. It is compiled from source (Rust, ~400 Cargo dependencies) in:
gnome-build-meta: https://gitlab.gnome.org/GNOME/gnome-build-meta (canonical reference)projectbluefin/dakota: https://github.com/projectbluefin/dakota (proven working setup)
If bootc build fails in the containerized BuildStream environment:
- Check Dakota's and gnome-build-meta's CI/build configuration (
*.ymlin.gitlab-ci/or.github/workflows/) - Determine if they resolve DNS/Cargo issues via container networking or CI environment setup
- Apply the same approach rather than using a pre-built binary
Reference files (local maintainer paths — clone the public repos above if these are absent):
/var/home/james/reference-repos/gnome-build-meta/elements/gnomeos-deps/bootc.bst/var/home/james/reference-repos/dakota/elements/*/bootc.bst(if exists)
All KDE/Plasma/freedesktop-sdk package definitions live directly in this
repo's elements/ tree — edit them in place, same as any other element.
No separate repo, no junction, no tarball-ref update dance. freedesktop-sdk
itself remains a real external junction (elements/freedesktop-sdk.bst) and
is tracked/updated the normal way (bst source track).
MANDATORY: Always use the just recipes for running any bst (BuildStream) or diagnostic commands. The Justfile wraps BuildStream inside a pinned container image with correct volume mounts and permissions to ensure reproducibility.
# Recommended: Background build with logging and tail
just bst-build
# Foreground build + OCI export
just build
# Arbitrary BuildStream command (shell, show, checkout, etc.)
just bst <command> <args>
# Example: Run shell in a sandbox
just bst shell oci/tromso.bst
# View logs
just log- NEVER run
bstdirectly on the host or viapipxfor project work. - Never use
just bst-builddirectly in a blocking tool call — it usestail -f. - The build container image is pinned in
Justfilefor reproducibility. - Build log location:
/var/tmp/tromso-build.log
-
Check the build log for the element name:
grep "FAILURE" /var/tmp/tromso-build.log | grep -v "^ "
-
Read the detailed log:
ls -t ~/.cache/buildstream/logs/gnome/kde-frameworks-ELEMENT/ | head -1 | \ xargs -I{} cat ~/.cache/buildstream/logs/gnome/kde-frameworks-ELEMENT/{}
-
Fix the failed
.bstfile in this repository'selements/tree. -
Clear the cached failure (BST caches failed artifacts):
# Clear ONLY the failed element to preserve cache for unrelated elements rm -rf ~/.cache/buildstream/artifacts/refs/gnome/kde-CATEGORY-ELEMENT/ rm -rf ~/.cache/buildstream/logs/gnome/kde-CATEGORY-ELEMENT/
⚠️ CRITICAL: Never clearkde-*broadly — this forces rebuild of ALL KDE elements, not just the fix. Instead, clear only the specific element that failed. -
Commit the local element change, push the Tromso branch, and restart the build. There is no
kde-build-metajunction to update.
build-depends:
- freedesktop-sdk.bst:public-stacks/buildsystem-cmake.bst
- kde/frameworks/extra-cmake-modules.bst
- kde/qt6/qt6-qtbase.bst # needed at configure time for Qt6 CMake detectionUse cmake-local (NOT cmake-options) for cmake flags:
variables:
cmake-local: -DBUILD_TESTING=OFFCMake config detection requires the dependency to be present in the sandbox at configure time.
Any KDE framework listed in depends: that is needed by CMake find_package() must also appear in build-depends:.
Pattern — if upstream CMakeLists.txt has find_package(KF6Foo REQUIRED), then kde/frameworks/foo.bst must be in build-depends.
| Package | freedesktop-sdk element |
|---|---|
| pam | freedesktop-sdk.bst:components/linux-pam-base.bst |
| polkit | freedesktop-sdk.bst:components/polkit.bst |
| NetworkManager | freedesktop-sdk.bst:components/networkmanager.bst |
- Reference repos:
/var/home/james/reference-repos/(local to the original maintainer's machine — clone from GitHub/GitLab if working elsewhere)dakota/— Project Bluefin Dakota (GNOME-based, bootc-enabled) — https://github.com/projectbluefin/dakotagnome-build-meta/— GNOME's BuildStream repository — https://gitlab.gnome.org/GNOME/gnome-build-meta
- Build logs:
/var/tmp/tromso-build.log - Cache:
~/.cache/buildstream/ - This project:
/var/home/james/dev/tromso/(local checkout path — irrelevant to any other clone)
If the VM hangs or boots to an emergency shell with "Ordering cycle found" messages in the serial log:
- Check
elements/tromso/system-config.bst. - NEVER use
Before=basic.targeton core services likedbus.service. This is a common source of cycles that causes D-Bus to be skipped, breaking SDDM and other dependencies.
To ensure the system boots to a KDE login:
- Explicit Enablement: SDDM must be explicitly enabled in
elements/tromso/system-config.bstby creating symlinks fordisplay-manager.serviceand addingsddm.servicetographical.target.wants. - Default Target: The default systemd target should be symlinked to
graphical.target. - Dependencies: SDDM requires
accountsservice(core-deps/accountsservice.bst) to list users and manage sessions. Ensure it is inelements/tromso/deps.bst. - Software Rendering: In virtualized environments (libvirt/QEMU), SDDM may fail to start with GPU errors. Add a systemd drop-in for
sddm.servicesettingEnvironment=QT_QUICK_BACKEND=softwareto use the software rasterizer.
The composed OCI image requires a fresh linker cache for SDDM to resolve Qt6 libraries at boot:
- Use
chroot /layer ldconfigorldconfig -r /layer -f /layer/etc/ld.so.confinelements/oci/tromso.bst. - Omit
-C /etc/ld.so.cacheif it causes "need absolute file name" errors.
When generating bootable images with bootc install:
- Avoid Sparse Files:
truncatefollowed bybootcon loop devices can lead to metadata corruption (especially on EXT4). - Use
fallocate: Always pre-allocate the full disk size usingfallocate -l 30G bootable.raw. - Prefer XFS: For the bootable image filesystem, XFS has shown better resilience than EXT4 in this specific loopback deployment workflow.
- Syncing: Always
syncbefore detaching loop devices or starting the VM.
When you are asked to fix a build failure, add a package, or resolve an infrastructure issue:
- DO NOT search the web or guess at solutions.
- DO read the reference repo files from
/var/home/james/reference-repos/, or a fresh clone of the public repos listed under "File locations" if that path isn't present. - DO compare the working configuration in Dakota/gnome-build-meta to the upstream ublue-os/aurora configuration.
- DO apply the exact pattern or approach used in the reference repos.
- DO document the reasoning in memory or commit messages.
The live ISO's installer uses tuna-installer (fisherman backend) to install
Tromso KDE Linux. The ISO pipeline (Containerfile, iso.justfile,
build-iso.yml) lives directly in this repo — tuna-os/tromso-iso was the
former separate repo for this and is now archived/retired. It was modeled on
projectbluefin/dakota-iso and the patterns below still apply.
Always use composeFsBackend: true in the fisherman recipe.
When composeFsBackend: true:
- fisherman exports the OCI image to an OCI layout on the TARGET DISK scratch (
/var/tmp) before calling bootc - bootc receives
--composefs-backend --source-imgref oci:/var/tmp/oci-cache - The
-v /var/lib/containers:/var/lib/containersbind-mount is NOT passed to the container - bootc does NOT check for
bootupdin this code path - The install works without
bootupdbeing present in the image (same as dakota)
Do NOT use composeFsBackend: false. That path requires bootupd (specifically bootupctl) which is not shipped in the tromso image.
The tromso OCI image must have gzip-compressed layers for composefs to work:
- Set
gzip: gzipinelements/oci/tromso.bst(NOTgzip: disabled) gzip: disabledproduces uncompressed layers that cause bootc's composefs splitstream to deadlock- In the ISO build, force gzip re-compression when exporting:
skopeo copy --dest-compress-format gzip --dest-force-compress-format
The squashfs embeds the tromso OCI image as VFS containers-storage. The skopeo import into VFS must run from inside the installer container (not the build host) so the tar-split metadata is written in the format the live ISO can read. See dakota-iso's justfile comment for details.
Always check dakota-iso for the correct behavior before making changes to tromso-iso.
That path is local to the original maintainer's machine; clone
https://github.com/projectbluefin/dakota-iso if it isn't present.
See docs/ci-and-iso-pipeline.md for the multi-runner build architecture,
live-ISO pipeline, LUKS e2e test, source-update automation, and the running
CI troubleshooting log (append to it while debugging CI).
- Never add
paths:filters to workflows whose jobs are required checks — a non-reporting required check deadlocks automerge. - Renaming a required job means updating the branch-protection contexts in the same PR, or automerge waits forever on the stale name.
- Never wrap a gate in
|| echo— bst-validate and pytest were silently dead for months that way. - Source URLs must go through an alias in
include/aliases.yml—unaliased-urlis fatal inproject.conf, so a hardcodedhttps://…in a.bstfailsbst-validate. Prefer a specific alias over the generictar_https:; only the specific ones are mirrored ininclude/mirrors.yml. Seedocs/adr/0004-freedesktop-sdk-upstream-practices.md. tests/pytest/test_iso_invariants.pyencodes shipped bug classes; when you fix a CI/ISO bug, add an invariant for it there and a row to docs/ci-and-iso-pipeline.md.- Upstream watch:
invent.kde.org/packaging/kde-buildstreamis a real but very early (2 weeks old at last check) independent effort toward an official KDE BuildStream project — not a migration target yet, revisit later (issue #85). Note official KDE Linux itself (invent.kde.org/kde-linux/kde-linux) uses mkosi+Arch, not BuildStream at all.