14 KiB
Fruix on FreeBSD, Path C: Short Hardening Pass, Then Native FreeBSD Base Builds
This document extends docs/PLAN_2.md after the completion of Phases 1 through 10 and the post-Phase-10 Shepherd/PID-1 and runtime-prefix cleanup work.
The project has already crossed the main feasibility threshold:
- Fruix can build declarative FreeBSD system artifacts
- those artifacts boot on the real XCP-ng VM
- the guest reaches DHCP and SSH
- both
freebsd-init+rc.d-shepherdandshepherd-pid1have been validated - the guest no longer depends on
/tmp/*-validate-installruntime-compatibility shims
The next architectural question is about the FreeBSD base itself.
Today, Fruix still assembles the kernel, bootloader, libraries, rc assets, and userland largely by copying curated artifacts from the build host into /frx/store. That was the right bootstrap move, but it is now the largest remaining non-native part of the system.
Long-term, the desired direction is clear:
- build FreeBSD kernel/world as Fruix-managed artifacts
- keep them in
/frx/store - make system upgrades a declarative rebuild/redeploy story instead of a host-copy refresh
However, this plan does not recommend jumping directly into full self-hosted FreeBSD base builds inside the guest. Instead, it takes a narrower and safer sequence:
- do a short hardening pass on the current working system
- then begin Option B immediately as the next major architecture phase
- start Option B on the builder side from
/usr/src, not with guest self-hosting
This keeps momentum while avoiding two failure modes:
- over-polishing the current host-copy pipeline as if it were the end state
- mixing base-system build mechanics, runtime polish, boot debugging, and self-hosting into one oversized step
Throughout this plan, the canonical Fruix roots remain:
/frx/store/frx/var/frx/etc
The user-facing system remains Fruix, with CLI fruix, while internal upstream-derived names continue to be renamed selectively rather than mechanically.
Current State at the Start of Plan 3
Fruix on FreeBSD already has:
- a functioning content-addressed store and derivation path
- daemon-mediated builds with FreeBSD-aware isolation prototypes
- real package outputs in
/frx/store - a declarative FreeBSD operating-system model
- rootfs and image generation driven by
fruix system ... - real XCP-ng validation using the approved VM/VDI path
- a working FreeBSD guest with DHCP, SSH, activation, Shepherd, and ready markers
- validated
shepherd-pid1boot on both local QEMU/TCG and the real XCP-ng VM - removal of the guest runtime's dependence on
/tmpcompatibility-prefix symlinks
The main remaining architectural compromise is that the FreeBSD base layer is still defined mostly as a set of curated host copies:
- kernel from
/boot/kernel - bootloader and boot assets from
/boot - userland/runtime pieces from
/bin,/sbin,/usr/bin,/usr/sbin,/lib,/usr/lib, and/etc - headers from
/usr/src
That means Fruix can currently rebuild and redeploy a working system, but it does not yet have a truly native upgrade story for the FreeBSD base itself.
Guiding Decision for the Next Milestone
The next milestone should be:
- just enough hardening to make the current system a reliable platform for deeper work,
- followed immediately by the first host-built FreeBSD base artifacts in
/frx/store.
This means the next work should optimize for:
- debuggability
- provenance
- repeatable deployment/validation
- clean separation between host-staged base artifacts and Fruix-built artifacts
- incremental replacement of the copy-based base layer
It should not optimize for:
- turning the current host-copy path into a heavily polished long-term abstraction
- immediate self-hosted
buildworld/buildkernelinside the Fruix guest - solving every usability concern before starting native base work
Phase 12: Short Hardening Pass on the Existing Working Pipeline
The purpose of this phase is not to beautify the bootstrap path. It is to make the existing validated system reliable enough that FreeBSD base-build work can proceed without avoidable confusion.
Intermediate Goal 12.1: Improve Deployment Provenance and Failure Diagnosis
Verification Goal 12.1: Make the current pipeline record exactly what FreeBSD base inputs and deployment artifacts were used for each generated system/image.
This should include at least:
- host
freebsd-version/unameprovenance /usr/srcrevision or identifying metadata when available- the exact staged base-package store paths used in the system closure
- image metadata that clearly distinguishes:
- host-copied FreeBSD base artifacts
- Fruix-built Guile/Shepherd/system artifacts
- better collection of boot/runtime logs where possible from the existing QEMU and XCP-ng harnesses
Success Criteria: a generated Fruix system/image can be traced back to its host-side FreeBSD base inputs and runtime validation logs without ad hoc investigation.
Intermediate Goal 12.2: Tighten Basic Runtime Completeness and Operator Diagnostics
Verification Goal 12.2: Close the most important remaining “prototype rough edges” in the current guest so it remains a dependable validation target while Option B begins.
This should focus on small, high-value improvements such as:
- clearer boot/service logs
- fewer known noisy runtime warnings where reasonably fixable
- more explicit validation of essential services and files
- better failure surfacing from activation and service startup
This phase should avoid broad feature creep. The target is not a polished distribution; it is a sharper debugging and validation baseline.
Success Criteria: the current FreeBSD guest remains reproducibly bootable and easier to debug, with fewer ambiguous failures during rebuild/redeploy cycles.
Intermediate Goal 12.3: Make the Host-Staged FreeBSD Base Boundary Explicit
Verification Goal 12.3: Refine the current package/model layer so the “host-staged FreeBSD base” is treated as an explicit transitional boundary rather than an implicit permanent design.
This should include:
- clearer grouping or manifesting of host-staged base packages
- documentation of which components are currently copied from the host
- explicit notes on which ones are planned to be replaced first by native base builds
Success Criteria: the repo documents and code clearly separate transitional host-copy FreeBSD base handling from genuine Fruix-built artifacts.
Phase 13: Option B Begins — Host-Built FreeBSD Kernel and World Artifacts in /frx/store
This is the real architectural pivot.
The goal is not yet to self-host FreeBSD base builds inside a Fruix guest. The goal is to teach Fruix to produce FreeBSD base artifacts as build outputs under /frx/store, using the builder host and /usr/src as the source of truth.
Intermediate Goal 13.1: Model FreeBSD World and Kernel as Fruix Build Artifacts
Verification Goal 13.1: Introduce Fruix build descriptions for the FreeBSD base that can represent at least:
- a
freebsd-worldartifact - a
freebsd-kernelartifact - required boot assets associated with the selected kernel/world build
The first version may still be specialized and FreeBSD-specific rather than fully generalized.
This step should determine and document:
- how
/usr/srcis treated as an input - what build parameters affect output identity
- how kernel/world configuration is hashed into the output model
- how these outputs are split or grouped in
/frx/store
Success Criteria: Fruix can describe native FreeBSD world/kernel build outputs as real store artifacts rather than only host-copy packages.
Intermediate Goal 13.2: Build and Stage Minimal FreeBSD World/Kernel Outputs From /usr/src
Verification Goal 13.2: Produce the first concrete world/kernel build outputs from /usr/src and stage them into /frx/store.
The first target should be intentionally narrow:
- build a kernel matching the validated VM target
- build a minimal world sufficient for the current Fruix guest to boot
- stage install trees under content-addressed store paths
This phase should prefer correctness and repeatability over completeness. A minimal successful output split is acceptable if it is documented.
Success Criteria: /frx/store contains native Fruix-managed FreeBSD world/kernel outputs built from /usr/src, and their contents can be inspected as build results rather than copied host snapshots.
Intermediate Goal 13.3: Boot a Fruix System Using Store-Built FreeBSD Base Artifacts
Verification Goal 13.3: Wire the operating-system/image pipeline so a generated system can boot using the newly built world/kernel outputs instead of the corresponding host-copy packages.
This should preserve the existing validation strategy:
- local QEMU/TCG + UEFI where useful
- real XCP-ng validation on the approved VM and existing VDI
The first boot target may still leave some secondary base components on the older copy path if necessary, as long as the transition boundary is explicit.
Success Criteria: a Fruix system/image boots successfully using native store-built FreeBSD base artifacts for at least the kernel and core world runtime.
Phase 14: Incrementally Replace the Host-Copy FreeBSD Base Layer
Once a minimal native world/kernel path works, the rest of the host-copy base layer should be retired incrementally rather than in one giant switch.
Intermediate Goal 14.1: Replace Kernel and Boot Assets First
Verification Goal 14.1: Move the system closure and image generator to prefer native store-built kernel and boot assets over host-copied /boot/... material.
This should include:
- kernel
- loader/boot assets as appropriate
- any required linker or boot metadata
Success Criteria: the image no longer relies on host-copied kernel/boot components for the validated boot path.
Intermediate Goal 14.2: Replace the Core Runtime World Slice
Verification Goal 14.2: Move the essential userland/runtime components to the native world outputs, including the files required for:
- boot
- activation
- networking
- SSH
- service startup
- basic operator access
Success Criteria: the booted Fruix system reaches ready state using a native store-built core FreeBSD runtime rather than a hand-curated host copy set.
Intermediate Goal 14.3: Revisit Headers, Toolchain, and Development Splits
Verification Goal 14.3: Define cleaner boundaries between:
- runtime world outputs
- development headers
- toolchain artifacts
- optional build/developer profiles
This step should reduce accidental coupling between “what the guest needs to boot” and “what the host needs to build software”.
Success Criteria: Fruix has a clearer and more maintainable model for FreeBSD runtime vs. development artifacts in /frx/store.
Phase 15: Establish a Real Fruix Upgrade Story for the FreeBSD Base
After native base artifacts exist and are used by the system closure, Fruix can move from “rebuild from current host copies” toward a more honest upgrade story.
Intermediate Goal 15.1: Make the FreeBSD Base Version a Declarative Input
Verification Goal 15.1: Define how a Fruix system declares which FreeBSD base/kernel source version it targets.
This may initially remain tied to locally available /usr/src, but it should move the model toward a declarative notion of:
- target FreeBSD branch/release
- kernel configuration
- world configuration
- boot/runtime variant
Success Criteria: FreeBSD base versioning becomes an explicit part of the Fruix system model rather than an implicit property of the builder host.
Intermediate Goal 15.2: Support Rebuild/Redeploy/Rollback Across Base Versions
Verification Goal 15.2: Demonstrate that at least two distinct FreeBSD base builds can coexist in /frx/store and that the generated system can switch between them through the normal rebuild/redeploy flow.
This should preserve the Guix-inspired strengths:
- content-addressed outputs
- side-by-side versions
- rollback-friendly system closures
Success Criteria: Fruix can rebuild and redeploy a system against a newer FreeBSD base without mutating the old one in place.
Intermediate Goal 15.3: Decide When to Pursue Self-Hosted Base Builds
Verification Goal 15.3: Reassess whether the next step should be:
- building FreeBSD base artifacts inside a Fruix-managed environment, or
- continuing to use the host builder while improving reproducibility and source acquisition
This decision should be made only after native world/kernel artifacts are already working in /frx/store.
Success Criteria: the project has a documented, evidence-based decision on whether and when to pursue self-hosted FreeBSD base builds.
Strategic Notes
Why this order?
This sequence is intended to preserve momentum and architectural clarity.
The short hardening pass prevents the next phase from being undermined by avoidable debugging ambiguity. But the hardening phase is intentionally short so the project does not over-invest in the transitional host-copy design.
Then Option B begins immediately in a way that is ambitious but still controlled:
- build FreeBSD base artifacts on the host
- store them in
/frx/store - boot from them
- replace the host-copy model incrementally
What this plan does not require yet
This plan does not require, in its first native-base stages:
- guest self-hosting
- in-place
freebsd-updateintegration - complete replacement of every base file in one step
- abandoning the validated XCP-ng/QEMU test harnesses
- immediate adoption of
shepherd-pid1as the only supported boot path
What success will mean
Success under this plan means the project moves from:
- “Fruix assembles a FreeBSD system by copying a curated slice of the host”
into:
- “Fruix builds and stores FreeBSD base artifacts itself, then assembles and deploys systems from those declared outputs.”
That is the real bridge from the current prototype to a more genuinely native Fruix system on FreeBSD.