Files
fruix/docs/reports/phase18-minimal-installation-flow-freebsd.md

4.7 KiB

Phase 18.1: minimal non-interactive Fruix installation flow on FreeBSD

Date: 2026-04-03

Goal

Phase 18.1 turns Fruix's existing closure/rootfs/image machinery into a real installation workflow.

The goal is not a polished installer yet. The goal is a repeatable, non-interactive install path that can:

  • take a declarative Fruix system,
  • partition and format a target disk or image,
  • populate it with the selected system closure,
  • install boot assets,
  • and leave the target bootable.

Implementation

New install spec and installer entry point

Added in modules/fruix/system/freebsd.scm:

  • operating-system-install-spec
  • install-operating-system

The installer currently supports:

  • raw image-file targets
  • /dev/... block-device targets

For raw image-file targets, Fruix now:

  • creates/truncates the target image
  • attaches it with mdconfig
  • creates a GPT layout
  • adds:
    • an EFI partition
    • a FreeBSD UFS root partition
  • formats them with:
    • newfs_msdos
    • newfs
  • mounts them
  • stages the declarative Fruix rootfs
  • copies the closure and referenced /frx/store items into the installed root
  • installs loader.efi to EFI/BOOT/BOOTX64.EFI
  • writes install metadata to:
    • /var/lib/fruix/install.scm

Rootfs staging was factored for reuse

Added internal helper:

  • populate-rootfs-from-closure

This lets image generation and installation reuse the same rootfs staging logic while differing in how the final target is created.

New CLI action

Added user-facing command support in scripts/fruix.scm:

  • fruix system install

New system option:

  • --target PATH

Install metadata now emits machine-readable fields including:

  • target
  • target_kind
  • target_device
  • esp_device
  • root_device
  • install_metadata_path
  • disk_capacity
  • root_size
  • declared/materialized FreeBSD source metadata
  • closure/native/runtime store metadata

Validation harnesses

Added:

  • tests/system/phase18-install-operating-system.scm.in
  • tests/system/run-phase18-system-install.sh

The Phase 18 install validation uses the already-validated boot mode:

  • freebsd-init+rc.d-shepherd

This keeps the install-flow validation focused on installation mechanics rather than on the separate Shepherd-as-PID-1 boot path.

Validation

Passing validation:

  • PASS phase18-system-install
  • regression re-check:
    • PASS phase17-source-revisions-qemu

Validated install result:

target_image=/tmp/fruix-phase18-install.CyrgKc/installed.img
target_kind=raw-file
disk_capacity=12g
root_size=10g
closure_path=/frx/store/ee486985797103aa5d3eeeef7f2cf066bcbd6839cd81083dbe626a594e71a703-fruix-system-fruix-freebsd
freebsd_source_kind=git
freebsd_source_ref=stable/15
freebsd_source_commit=332708a606f6bf0841c1d4a74c0d067f5640fe89
materialized_source_store=/frx/store/a892afb425235de71c9da38884e2ebdba5dafd3a1993f432fe7c446f5af2151f-freebsd-source-stable15-install-source
native_base_store_count=3
install_metadata_path=/var/lib/fruix/install.scm
esp_fstype=msdosfs
root_fstype=ufs
shepherd_status=running
sshd_status=running
install_flow=non_interactive
init_mode=freebsd-init+rc.d-shepherd
install_target_boot=ok

The harness verified all of the following:

  • GPT partitioning is created on the target image
  • the installed ESP is a valid msdosfs filesystem
  • the installed root partition is ufs
  • EFI/BOOT/BOOTX64.EFI exists on the target
  • /run/current-system points at the installed closure in /frx/store
  • the installed closure exists under the target's /frx/store
  • /var/lib/fruix/install.scm exists and records:
    • closure path
    • store items
    • install spec
    • materialized source provenance via the referenced closure/store items
  • the installed system boots under local QEMU/UEFI/TCG
  • after boot:
    • sshd is running
    • /usr/local/etc/rc.d/fruix-shepherd onestatus reports running
    • activation completed successfully

QEMU SMP note

I tested the idea of defaulting local QEMU validation to 8 vCPUs.

Result:

  • for local qemu-system-x86_64 under TCG, higher SMP did not help this validation path and in practice regressed boot responsiveness
  • the harnesses therefore keep QEMU_SMP configurable but retain a conservative default of 2 for TCG-based local validation

This keeps the validated path reliable while still allowing manual override when useful.

Result

Phase 18.1 is complete.

Fruix now has a real, repeatable, non-interactive installation workflow for FreeBSD systems:

  • declarative system input
  • native/source-driven closure output
  • partition/format/install to a target image or disk
  • bootable installed result

The next step is Phase 18.2:

  • a minimal Fruix-managed installer environment that can boot into an install context and run this workflow from within that environment.