# 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: ```text 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