7.1 KiB
Fruix bootstrap boundary
This document defines the architectural boundary between:
fruixfruix-bootstrap
The goal is to keep Fruix itself small, self-hosting, and canonical, while isolating the foreign-host bring-up logic required to get the first Fruix-capable environment running on plain FreeBSD.
Short version
fruixis the canonical source of Fruix package, system, installer, deployment, and node-management logic.fruix-bootstrapis a thin foreign-host layer that turns a plain FreeBSD installation into a Fruix builder.- A booted Fruix system must be able to continue operating from
fruixalone, without depending onfruix-bootstrap.
Core concept: the Fruix builder
fruix-bootstrap should not be thought of as a permanent alternate Fruix implementation or a long-lived compatibility layer.
Its job is to create a Fruix builder: an environment capable of evaluating and materializing a pinned fruix revision on a non-Fruix FreeBSD host.
A Fruix builder should be able to:
- run the Fruix CLI and evaluator
- load a pinned
fruixcheckout or channel revision - materialize Fruix package outputs
- build Fruix system closures
- build Fruix installer ISOs and VM images
- install or deploy the first Fruix system
That builder may run:
- on a plain FreeBSD machine
- in CI
- in a jail
- on a later Fruix node
The important point is that the builder is generic. It is a build/evaluation environment for Fruix, not a second product identity.
Ownership boundary
fruix owns
Anything that should still matter after first Fruix boot belongs in fruix.
This includes:
- package definitions
- system definitions
- source objects and source provenance logic
- native-build and promotion logic
- executor model
- system artifact materializers:
- closures
- root filesystems
- disk images
- installers
- installer ISOs
- installed-node management logic:
- build
- build-base
- deploy
- reconfigure
- switch
- rollback
- later upgrade
- installer application / TUI logic
- publication/substitution logic when added later
- metadata formats that define Fruix identity and lifecycle
Rule of thumb:
If a booted Fruix node should conceptually understand it, it belongs in
fruix.
fruix-bootstrap owns
Anything only required to turn plain FreeBSD into a Fruix-capable builder belongs in fruix-bootstrap.
This includes:
- host environment checks
- locating or building bootstrap tool dependencies
- foreign-host setup glue
- wrapper entrypoints for invoking a pinned
fruixrevision - initial bootstrap documentation
- tests for the path from vanilla FreeBSD to first Fruix-capable builder or first Fruix artifact
Rule of thumb:
If it is only needed before Fruix exists as Fruix, it belongs in
fruix-bootstrap.
Dependency direction
The dependency direction must remain one-way.
Allowed:
fruix-bootstrapdepends on a pinnedfruixrevisionfruix-bootstrapinvokesfruixto build packages, systems, installers, and images
Not allowed:
fruixdepending onfruix-bootstrap- a booted Fruix node needing
fruix-bootstrapin order to keep building or upgrading itself
This keeps fruix canonical and prevents the bootstrap repo from becoming a second source of truth.
Canonical source of truth
fruix is the only canonical home for Fruix product logic.
In particular, these should not be duplicated long-term in fruix-bootstrap:
- canonical package definitions
- canonical system logic
- installer workflow semantics
- deployment semantics
- long-lived metadata definitions
- installed-node lifecycle behavior
fruix-bootstrap may temporarily wrap or seed those capabilities, but it should consume them from fruix, not fork them.
Pinning
fruix-bootstrap should operate on a clear Fruix identity, not an ambient checkout with unclear provenance.
Initially, that identity can be simple:
- a local checkout path
- a git commit
- a tag
- a branch plus locked commit
Later, this can become a proper Fruix channel lock/update model.
Whatever form is used, the important property is:
the first Fruix artifact is built from a known
fruixidentity.
That identity should eventually be recorded in:
- installer metadata
- image metadata
- deployed generation metadata
- installed-node metadata
Product flow
The intended lifecycle is:
- start from plain FreeBSD
- use
fruix-bootstrapto create a Fruix builder - point that builder at a pinned
fruixrevision - materialize artifacts from
fruix, such as:- package outputs
- system closures
- installer ISOs
- VM images
- installed systems
- boot or install the resulting Fruix system
- from that point onward, use
fruixalone to move the system forward
In short:
plain FreeBSD
-> fruix-bootstrap
-> Fruix builder
-> pinned fruix revision
-> build/install/deploy Fruix artifacts
-> booted Fruix node
-> future lifecycle managed by fruix
Installer implication
The installer UI and workflow belong to fruix, not fruix-bootstrap.
Why:
- the installer is part of the Fruix product surface
- Fruix should be able to build its own installer artifacts
- installed systems should be traceable to a pinned Fruix revision
- later Fruix nodes should be able to rebuild the installer without returning to bootstrap-only logic
So the split should be:
fruix-bootstrap: makes it possible to build the installerfruix: defines the installer artifact and the TUI installer behavior
Success criteria
The boundary is working when all of the following are true:
- a plain FreeBSD host can become a Fruix builder using
fruix-bootstrap - that builder can build a Fruix installer ISO or VM image from a pinned
fruixrevision - the resulting Fruix system boots without requiring
fruix-bootstrap - the booted Fruix system can keep using
fruixfor:- build
- build-base
- reconfigure
- deploy
- rollback
- later upgrade
- package and system evolution happens in
fruix, not in duplicated bootstrap logic
Non-goals
This split does not mean:
fruix-bootstrapbecomes a permanent parallel Fruix distribution- booted Fruix nodes should keep consulting bootstrap state
- bootstrap should own package or system semantics long-term
It also does not require all historical bootstrap leakage to disappear immediately. Some transitional host assumptions may remain for a while, but they should be treated as technical debt against this boundary.
Working rule for future refactors
When deciding where code belongs, ask:
Should a booted Fruix node still care about this?
- If yes, it belongs in
fruix. - If no, and it only exists to bring up Fruix from foreign FreeBSD, it belongs in
fruix-bootstrap.
Current direction
Near-term work should follow this boundary:
- keep bootstrap generic and thin
- move as much canonical logic as possible into
fruix - make the first user-facing installer a Fruix-defined product artifact
- ensure installed nodes record and operate from a pinned Fruix identity
That gives Fruix a clean product story:
- bootstrap creates a Fruix builder
- Fruix builds Fruix
- Fruix systems move forward using Fruix