Files

7.1 KiB

Fruix bootstrap boundary

This document defines the architectural boundary between:

  • fruix
  • fruix-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

  • fruix is the canonical source of Fruix package, system, installer, deployment, and node-management logic.
  • fruix-bootstrap is 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 fruix alone, without depending on fruix-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 fruix checkout 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 fruix revision
  • 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-bootstrap depends on a pinned fruix revision
  • fruix-bootstrap invokes fruix to build packages, systems, installers, and images

Not allowed:

  • fruix depending on fruix-bootstrap
  • a booted Fruix node needing fruix-bootstrap in 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 fruix identity.

That identity should eventually be recorded in:

  • installer metadata
  • image metadata
  • deployed generation metadata
  • installed-node metadata

Product flow

The intended lifecycle is:

  1. start from plain FreeBSD
  2. use fruix-bootstrap to create a Fruix builder
  3. point that builder at a pinned fruix revision
  4. materialize artifacts from fruix, such as:
    • package outputs
    • system closures
    • installer ISOs
    • VM images
    • installed systems
  5. boot or install the resulting Fruix system
  6. from that point onward, use fruix alone 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 installer
  • fruix: defines the installer artifact and the TUI installer behavior

Success criteria

The boundary is working when all of the following are true:

  1. a plain FreeBSD host can become a Fruix builder using fruix-bootstrap
  2. that builder can build a Fruix installer ISO or VM image from a pinned fruix revision
  3. the resulting Fruix system boots without requiring fruix-bootstrap
  4. the booted Fruix system can keep using fruix for:
    • build
    • build-base
    • reconfigure
    • deploy
    • rollback
    • later upgrade
  5. package and system evolution happens in fruix, not in duplicated bootstrap logic

Non-goals

This split does not mean:

  • fruix-bootstrap becomes 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