Files
fruix/docs/reports/phase10-fruix-system-command-freebsd.md

5.3 KiB

Phase 10.1: Add a real fruix system command for FreeBSD system artifacts

Date: 2026-04-02

Goal

Start Optional Phase 10 by replacing one of the remaining prototype-only workflows with a real user-facing Fruix command.

The concrete target for this subphase was:

  • expose the declarative FreeBSD operating-system machinery through a true fruix CLI entry point,
  • stop relying solely on ad hoc phase-specific harness scripts for closure/image materialization,
  • and validate that the new command can build the existing declarative system outputs.

Result

A minimal user-facing fruix command now exists in this repository.

New entry points:

  • bin/fruix
  • scripts/fruix.scm

Supported commands in this first cut:

  • fruix system build OS-FILE
  • fruix system image OS-FILE
  • fruix system rootfs OS-FILE ROOTFS-DIR

Supported options:

  • --system NAME
  • --store DIR
  • --disk-capacity SIZE
  • --rootfs DIR
  • --help

The command loads a declarative operating-system definition from a Scheme file, resolves the selected operating-system binding, and then calls the existing Fruix FreeBSD system materializers directly:

  • materialize-operating-system
  • materialize-rootfs
  • materialize-bhyve-image

The command prints machine-readable key=value metadata for the produced artifacts.

Why this matters

Up through Phase 9, the project had already achieved a real booted Fruix guest, but the operator-facing path for producing those artifacts still lived mostly in phase-specific test harnesses such as:

  • tests/system/run-phase7-system-closure.sh
  • tests/system/run-phase8-system-image.sh
  • tests/system/run-phase9-xcpng-boot.sh

Those were valuable validation tools, but they were not yet a real Fruix interface.

This subphase moves the project one step closer to a genuine OS workflow by making system artifact generation available through a Fruix CLI surface.

Implementation details

bin/fruix

Added a shell wrapper that:

  • locates the repository root,
  • locates the Guile and Guile-extra validation prefixes already used elsewhere in the project,
  • ensures the required local Guile/Fibers/Shepherd pieces exist,
  • prepares GUILE_LOAD_PATH for:
    • modules/
    • ~/repos/guix
  • and runs the Guile entry point.

This keeps the new command aligned with the currently validated local FreeBSD Guile toolchain rather than inventing a separate runtime path.

scripts/fruix.scm

Added the actual CLI implementation.

It currently:

  • parses fruix system ... actions,
  • supports --help,
  • loads an operating-system definition file,
  • resolves the selected OS variable via --system NAME or a small fallback list of conventional names,
  • validates the operating-system object,
  • dispatches to the existing FreeBSD system materializers,
  • and emits stable key=value metadata.

tests/system/run-phase10-fruix-system-command.sh

Added a dedicated validation harness for the new command.

The test verifies that:

  1. fruix system build materializes a closure under /frx/store
  2. the returned closure contains the generated activation path
  3. fruix system image materializes a disk image under /frx/store
  4. the command emits the expected metadata fields for both operations

Validation

Successful validation run:

  • PASS phase10-fruix-system-command
  • workdir: /tmp/phase10-fruix-cmd-1775117490

The new command successfully produced both:

  • a Fruix system closure path under /frx/store/*-fruix-system-fruix-freebsd
  • a Fruix image path under /frx/store/*-fruix-bhyve-image-fruix-freebsd/disk.img

Example usage:

sudo env HOME="$HOME" ./bin/fruix system build \
  tests/system/phase7-minimal-operating-system.scm \
  --system phase7-operating-system
sudo env HOME="$HOME" ./bin/fruix system image \
  tests/system/phase7-minimal-operating-system.scm \
  --system phase7-operating-system \
  --disk-capacity 5g

Current limitations

This is intentionally a first Phase 10 step, not the final Fruix command surface.

Notable current limitations:

  • system/image materialization still expects the currently validated local Guile/Shepherd build prefixes
  • writing into /frx/store and building disk images still typically requires sudo
  • the command currently targets only the FreeBSD system prototype path already implemented in modules/fruix/system/freebsd.scm
  • it does not yet integrate with the larger upstream Guix command framework; it is a Fruix-native CLI wrapper in this repo

Assessment

This subphase successfully replaces an important transitional layer with a more OS-like Fruix interface.

The project can now say not only that it can declaratively define and boot a Fruix FreeBSD system, but also that it has a direct user-facing command for materializing the resulting system artifacts.

Continue Phase 10 by reducing another transitional seam behind fruix system, most likely one of:

  1. add a fruix system vm / deploy-oriented flow on top of the now-working image path
  2. replace the current compatibility symlink handling for locally built Guile/Shepherd prefixes with a more native store-path-aware runtime arrangement
  3. factor the phase-specific system test harnesses to call bin/fruix directly where practical, so the command becomes the canonical operator path rather than just an additional wrapper