Skip to main content

Runtime behaviour

What a DeskOS image does once it boots: baseline, Flatpaks, desktop, boot, trust, updates, /etc drift and the provisioning boundary. The compiler is architecture.md.

Managed baseline​

DeskOS manages what an organization requires for any authorized user, before any $HOME exists. Personal tooling (Homebrew, mise, SDKMAN, version managers, dotfiles, personal Toolboxes) stays outside the model.

Acquisition order: distribution RPM; official vendor repository (or a vendor-signed RPM file, which needs a new URL and checksum per update); checksum-pinned upstream binary; system Flatpak; managed web applications later.

BinaryArtifact needs an exact version, an https URL that is not a floating location and a SHA-256, and installs into /usr/local/bin with mode 0755 or 0555. The fetch uses curl, which the platform's image must provide; an image that neither ships nor declares it fails late at build, since "what a base provides" is not modeled. The backend resolves symlinks when it creates the destination (readlink -m), because install -D cannot traverse a /usr/local that is a dangling symlink during the build (measured on the Ubuntu base, 2026-10-18).

A single-file BinaryArtifact may declare a desktopEntry: the lowerer emits a DesktopEntry, the icon FileInstall and an IconCacheUpdate, whose Exec and TryExec are the artifact's destination, never authored text.

PackageSet.rpmFiles needs the same URL and checksum plus an armoured public key inside the root; the build fails unless the RPM is signed by that key.

System Flatpaks​

An image that declares a system Flatpak channel installs Flatpak and adds no remote. Remotes go to /usr/share/flatpak/remotes.d and applications to /usr/share/flatpak/preinstall.d, both image-owned. A generated unit runs flatpak preinstall once per boot; upstream decides what to install and does not reinstall apps a user removed.

The unit is WantedBy=multi-user.target, Type=exec, ordered after network-online.target and multi-user.target, so no boot target gains a network wait. Before each attempt it runs flatpak repair (an interrupted pull leaves a ref that preinstall will not refresh) and flatpak update --appstream (a stale summary reports a declared app as not found). It retries until it succeeds (Restart=on-failure, RestartSec=60, no start limit) and stops within 20 s.

A remote is OSTree by default; transport: oci carries Url=oci+https://… and no signing key, because the registry and its images are what get verified. An OCI remote with an authenticator gets deskos-flatpak-oci-authenticator.service, running flatpak remote-add --if-not-exists --from then flatpak remote-modify --authenticator-name, ordered before the preinstall unit. Credentials are not in the artifact: the authenticator reads them from the machine.

Offline boot, in a container with no network and a 25-second simulated nm-online timeout: gdm.service was active while network-online.target was pending; graphical.target still waits for the network because platform units are ordered after multi-user.target, bounded by NM_ONLINE_TIMEOUT=60; flatpak preinstall printed "Nothing to do." and recorded nothing, so the apps stay eligible. Installing after an offline boot is unverified, and a download failure was not tested. GDM was not exercised in the container.

GNOME​

GnomeProfile exposes administrator vocabulary (windows.buttons, shell.favorites, session.idle.blankAfter, dock.position) and the lowerer writes dconf keys to the platform's vendor database (distro on EL10). Wallpaper files are repository assets installed under /usr/share/deskos/backgrounds/.

Dock. shell.extensions names the UUID and whether it runs; dock.* settings apply only while that decision is true. A higher-layer enabled: false masks lower-layer dock settings and warns; dock settings without an enabled dock are errors. Favorites are native and work without the dock.

Appearance. appearance.colorScheme and accentColor set color-scheme and accent-color with the enums of gsettings-desktop-schemas 47.1. Core sets neither.

GNOME Software. software.updates maps to allow-updates and download-updates:

ValueallowdownloadEffect
automatictruetrueGNOME default: downloads and applies what needs no reboot
manualtruefalseoffers updates; the user applies them
disabledfalsefalseno Updates page; another updater owns updates

deskos-gnome sets manual as a default, no lock.

Terminal shortcut. keyboard.terminal names a .desktop id bound to Ctrl+Alt+T; EL10 has no native terminal key. Not modeled: the Initial Setup third-party repositories page, which needs fedora-third-party (absent on EL10).

Login screen. appearance.loginLogo sets the GDM logo; GDM's profile reads distro, which Platforms declare with gnome.loginScreen.

First boot. GNOME Initial Setup has its own dconf profile, which does not read distro, so the effective wallpaper is also a GLib vendor override (/usr/share/glib-2.0/schemas/50_deskos.gschema.override, above the distribution's 10_), compiled in the build. Verified under the gnome-initial-setup profile and on the first-boot screen of a CS10 Core VM.

Defaults and locks. EL10 reads user, local, site, distro, highest first, so a DeskOS default can be overridden and a DeskOS lock cannot:

DeskOS writesEffect
a defaultlocal, site or a user change overrides it
a lockthe distro value applies and is not writable; local and site locks are ignored

[!WARNING] A lock is image-level enforcement that defeats site and local. Core uses none. Lock only what the image must enforce; leave Ansible- or Satellite-managed settings as defaults.

Boot​

BootProfile (splash: graphical|text, quiet, watermark) lowers to bootc kernel arguments in /usr/lib/bootc/kargs.d/50-deskos.toml, and for graphical to the platform's Plymouth packages, a dracut drop-in and a rebuild of every image kernel's initramfs. The build fails if no kernel is found or Plymouth is missing from an initramfs. text adds no splash argument and no rebuild.

watermark (PNG, at most 1024x1024, inside the root) needs splash: graphical and becomes an image-owned two-step theme deskos: a generated deskos.plymouth (stock spinner layout, own ImageDir), the watermark, and the platform's stock frames except their watermark.png. plymouth-set-default-theme deskos selects it before the rebuild. A higher-layer text masks a watermark with a warning; a watermark at or above a text layer is an error.

Diagnostics stay available: ESC shows details, systemd prints failures under quiet, and dropping rhgb quiet gives full text. A serial console turns Plymouth to text, so test QCOW2s are built with --no-default-kernel-args (see tests/vm/README.md).

Trust store​

TrustAnchor places CA certificates in the platform trust store: anchors[] into the anchors directory, blocklist[] where p11-kit reads it as distrusted. It lowers to one image file per certificate and one trust.updateCommand run after COPY rootfs/. On both EL platforms that is update-ca-trust, which regenerates /etc/pki/ca-trust/extracted/, so a chain ending at a blocklisted CA is rejected and TLS is not weakened.

Certificates are keyed by name: identical definitions deduplicate, different ones conflict at any layer, and anchoring plus distrusting one name fails. The file must be a PEM CERTIFICATE; a private key is refused. A platform without trust facts fails composition, as does a blocklist on a platform with no blocklistDir: gaps are named, never dropped.

Core ships deskos-trust for the October 2026 eMudhra roots (RHSB-2026-012); organizations add their own at any layer. The render rejects a certificate that shares a path with another image file, and limits assets to the resource root.

Updates​

Every shipped Platform lists bootc-fetch-apply-updates.timer as an image-update unit. Where the base enables it, its service runs bootc upgrade --apply, which reboots on publish; that path was checked end to end on CentOS Stream 10.

UpdatePolicy (image and flatpak, each automatic, schedule: daily|weekly, requireACPower; image also an apply window) lowers to masks of the platform's updates.imageUpdateUnits for any image.automatic, and to generated units:

UnitCommand
deskos-image-update.service/usr/bin/bootc upgrade --quiet
deskos-flatpak-update.service/usr/bin/flatpak update --system --noninteractive --assumeyes
deskos-image-apply.service (opt-in)deskos window guard, then bootc upgrade --apply --quiet

bootc upgrade without --apply downloads and stages; ostree-finalize-staged applies at the next shutdown or reboot. No generated unit reboots unless an organization sets image.apply.enabled: true; a test rejects --apply, --soft-reboot and --download-only in every rendered Core and example image.

Timers use OnCalendar=daily|weekly, RandomizedDelaySec=2h and Persistent=true. requireACPower adds ConditionACPower=true: on battery the run is skipped, not failed. Services follow network-online.target; timers add no boot ordering.

An apply policy (ADR 0023) adds deskos-image-apply.timer, with days plus at or window.start and duration, an optional IANA timezone, AccuracySec=1min and Persistent=false. The service runs deskos window as an ExecCondition, so a calendar event that elapsed during suspend is skipped outside the local interval; exact at allows five minutes. A missed window is never caught up.

Core sets image updates daily on AC power; system Flatpak updates are the EL family's policy. automatic: false keeps the platform updater masked and schedules nothing; no image intent keeps the platform's rebooting timer. Masks live in /etc, so a local unmask survives updates. A staging run skipped on battery is not lost: a generated udev rule starts the same service when AC comes online, and ConditionACPower still decides. Not supported: metered networks. Checked with systemd-analyze verify and on a CentOS Stream 10 VM: the update staged with the same boot ID, a reboot booted it with rollback intact, the bootc timer stayed masked, and the Flatpak update succeeded. Not checked: RHEL 10, battery. The operator view is operations.md.

Drift and mutable /etc​

bootc updates /usr atomically; /etc persists and follows image updates only while locally unmodified. deskos check reports the drift it can measure and publishes what it leaves out. DeskOS does not enforce or reconcile the machine against its plan (ADR 0018).

Provisioning and enrollment​

StageContents
Artifacteverything identical across machines: packages, branding, client binaries, descriptors
Provisioningper-machine install choices, local bootstrap account, storage and encryption, first-boot Flatpak materialization
EnrollmentFreeIPA or AD join, device certificates, VPN identities, EDR tenancy

One digest serves many machines, so no identity or secret is ever in the artifact. Enrollment is reserved in the Plan and not implemented.