# Progress ## 2026-04-01 — Phase 1.1 started: Guile verified on FreeBSD amd64 Completed work: - installed/confirmed `guile3-3.0.10` - added a reusable verification harness: - `tests/guile/run-phase1-verification.sh` - `tests/guile/verify-phase1.scm` - `tests/guile/modules/phase1/sample.scm` - verified the following on `FreeBSD 15.0-STABLE` amd64: - module loading - deterministic output generation - file I/O - process handling with `primitive-fork`/`waitpid` - loopback TCP sockets - FFI calls into libc - execution of Guix bootstrap-related code from `(guix build make-bootstrap)` - wrote the results to `docs/reports/phase1-guile-freebsd.md` Notable findings: - `guile3` and `guile-3.0` are present, but there is no unversioned `guile` binary - `system*` and `open-pipe*` currently segfault on this host (`exit 139`) - despite that crash, the lower-level process primitives needed for further investigation do work Current assessment: - Phase 1.1 has a solid amd64 smoke-verification baseline - Phase 1.1 is not fully complete yet because `i386` has not been checked and the subprocess crash needs investigation - verification harness committed as `e380e88` (`Add FreeBSD Guile verification harness`) ## 2026-04-01 — Phase 1.1 follow-up: subprocess crash isolated Completed work: - added a dedicated subprocess diagnostic harness: - `tests/guile/run-subprocess-diagnostics.sh` - `tests/guile/posix-spawn-freebsd-diagnostics.c` - reproduced crashes for: - `system*` - `spawn` - `open-pipe*` - confirmed all three fail with `SIGSEGV` / `exit 139` - confirmed native FreeBSD `posix_spawn` + `posix_spawn_file_actions_addclosefrom_np` works in a standalone C program - confirmed FreeBSD behavior that triggers gnulib replacement logic: - `posix_spawn_file_actions_adddup2` accepts an invalid fd in the gnulib probe - `posix_spawn_file_actions_addopen` accepts an invalid fd in the gnulib probe - `posix_spawnp` accepts a shebang-less executable script in the gnulib security probe - wrote the analysis to `docs/reports/phase1-guile-subprocess-crash.md` Conclusion: - this is most likely an upstream Guile/gnulib ABI bug on FreeBSD, not a Guix-specific problem - likely sequence: 1. gnulib enables `REPLACE_POSIX_SPAWN=1` 2. Guile still enables `HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSEFROM_NP` 3. Guile passes a gnulib replacement `posix_spawn_file_actions_t` object to native `posix_spawn_file_actions_addclosefrom_np` 4. libc interprets gnulib struct fields as a native pointer and crashes - evidence from the lldb core matches this hypothesis (`*fa = 0x0000000600000008`, consistent with gnulib `_allocated=8`, `_used=6`) Current assessment: - Phase 1.1 amd64 investigation is now much stronger and has a concrete root-cause hypothesis - the next practical step is to validate a workaround or patch in Guile so subprocess helpers stop crashing - after that, continue with Phase 1.2 (minimal native build environment / GNU Hello) ## 2026-04-01 — Phase 1.1 follow-up: local Guile build validated the fix Completed work: - installed the additional build tooling needed for a local Guile checkout build: - `autoconf` - `automake` - `libtool` - `gettext-tools` - `texinfo` - `help2man` - `gperf` - `pkgconf` - confirmed a FreeBSD-specific bootstrap quirk: - Guile `autogen.sh` needs GNU `m4` - FreeBSD base `/usr/bin/m4` is not sufficient - `M4=gm4 ./autogen.sh` works - built a disposable validation copy from `~/repos/guile` - confirmed `~/repos/guile` already contains upstream commit: - `eb828801f621d3e130b6fe88cfc4acaa69b98a03` - `Don't use posix_spawn_file_actions_addclosefrom_np with glib posix_spawn` - updated the local test harnesses so they can test non-system Guile builds: - `tests/guile/run-phase1-verification.sh` - `tests/guile/run-subprocess-diagnostics.sh` - both now accept `GUILE_BIN` - both now prepend the sibling `../lib` directory to `LD_LIBRARY_PATH` when a matching local `libguile-3.0.so.1` exists - subprocess diagnostics now supports `EXPECT_GUILE_SUBPROCESS_CRASH=0` for fixed builds - validated that the packaged Guile still reproduces the crash - validated that the locally built Guile succeeds for: - `system*` - `spawn` - `open-pipe*` - re-ran the broader Phase 1.1 Scheme verification suite successfully against the local Guile build - wrote the results to `docs/reports/phase1-guile-local-build-validation.md` Important findings: - the local Guile executable initially still crashed until it was forced to load its matching local `libguile-3.0.so.1` - once `LD_LIBRARY_PATH` pointed at the local install lib directory, subprocess helpers worked correctly - this strongly supports the earlier diagnosis and shows that the upstream Guile fix resolves the problem in practice - the local `~/repos/bdwgc` checkout was not needed for this step; packaged `boehm-gc-threaded` was sufficient so far Current assessment: - Phase 1.1 now has both a root-cause analysis and a working validated fix path on amd64 - no source changes were needed in `~/repos/guile` because the local checkout already contains the relevant upstream fix - no source changes were needed in `~/repos/bdwgc` yet, but the earlier FreeBSD warning keeps it on the watch list - the project can now move on to Phase 1.2 with a known-good local Guile fallback ## 2026-04-01 — Phase 1.2 started: native GNU Hello build validated on FreeBSD Completed work: - added a reusable native build harness: - `tests/native-build/run-gnu-hello.sh` - used the current Guix package definition in `~/repos/guix/gnu/packages/base.scm` as the source of truth for: - GNU Hello version `2.12.3` - expected Guix nix-base32 source hash `183a6rxnhixiyykd7qis0y9g9cfqhpkk872a245y3zl28can0pqd` - verified the downloaded tarball against the translated SHA256: - `0d5f60154382fee10b114a1c34e785d8b1f492073ae2d3a6f7b147687b366aa0` - successfully executed the standard native build lifecycle on `FreeBSD 15.0-STABLE` amd64: - fetch - hash verification - extract - configure - build - staged install - runtime execution - confirmed the staged binary runs and prints: - `Hello, world!` - captured build metadata including: - compiler and make versions - host triplet - configure command - staged output path - runtime shared-library dependencies - wrote the results to `docs/reports/phase1-native-gnu-hello.md` Important findings: - GNU Hello built successfully with FreeBSD base `make`, not just `gmake` - that contrasts with the earlier local Guile build, which did require GNU `gmake` - even this minimal GNU package links against FreeBSD-userland-provided libraries such as `libiconv` and `libintl`, which is useful data for later Guix package modeling - this step is still a native shell-driven build exercise, not yet a real Guix package build Current assessment: - Phase 1.2 now has a concrete native autotools success case on FreeBSD - the host can perform the basic fetch/verify/configure/build/install/run cycle needed for later `gnu-build-system` adaptation work - Guix-specific build orchestration is still missing, but the environmental baseline is stronger now Recent commits: - `e380e88` — `Add FreeBSD Guile verification harness` - `cd721b1` — `Update progress after Guile verification` - `27916cb` — `Diagnose Guile subprocess crash on FreeBSD` - `02f7a7f` — `Validate local Guile fix on FreeBSD` Next recommended step: 1. extend Phase 1.2 with at least one additional representative GNU/autotools package build on FreeBSD, or 2. prototype a tiny Scheme-based `gnu-build-system`-like phase runner using the known-good local Guile path, starting from the GNU Hello flow 3. continue keeping `~/repos/bdwgc` in reserve if later FreeBSD-specific GC/thread issues appear ## 2026-04-01 — Phase 1.2 follow-up: Guix builder-side GNU Hello phase runner validated Completed work: - added a Scheme-driven GNU Hello build prototype: - `tests/native-build/gnu-hello-guix-phase-runner.scm` - `tests/native-build/run-gnu-hello-guix-phase-runner.sh` - required the previously validated fixed local Guile build for this harness because it depends on subprocess-heavy Scheme operations - used Guix modules directly from `~/repos/guix`, including: - `(guix base32)` - `(guix build gnu-build-system)` - `(guix build utils)` - fetched and hash-verified GNU Hello `2.12.3` again against the Guix package hash: - nix-base32: `183a6rxnhixiyykd7qis0y9g9cfqhpkk872a245y3zl28can0pqd` - SHA256: `0d5f60154382fee10b114a1c34e785d8b1f492073ae2d3a6f7b147687b366aa0` - successfully executed a subset of Guix builder-side `%standard-phases` on FreeBSD: - `set-SOURCE-DATE-EPOCH` - `unpack` - `configure` - `build` - `check` - `install` - installed GNU Hello into a store-like output path under the temporary work directory rather than using a `/usr/local` `DESTDIR` staging layout - executed the resulting binary successfully and confirmed output: - `Hello, world!` - captured metadata including: - host triplet - selected phase list - runtime dependencies - test-suite summary - wrote the results to `docs/reports/phase1-guix-gnu-hello-phase-runner.md` Important findings: - this is the first validation step in the repo that successfully exercised actual Guix builder-side GNU build logic on FreeBSD instead of only a shell approximation - the harness works when driven by the fixed local Guile build, confirming that the earlier Guile subprocess-fix validation is directly useful for FreeBSD Guix build orchestration - GNU Hello's `make check` test suite also passed in this mode: - total: `7` - pass: `7` - fail: `0` - the resulting binary's runtime dependencies differ from the earlier `/usr/local`-prefixed native shell harness; in this store-like output layout it only showed: - `libc.so.7` - `libsys.so.7` - that difference is a useful clue that Guix-style output layout/build invocation can materially affect FreeBSD runtime linkage behavior Current assessment: - Phase 1.2 now has both: - a shell-driven native GNU Hello build harness, and - a Scheme-driven prototype that uses real Guix builder-side GNU phases - this is still short of a true Guix package/derivation build, but it significantly narrows the gap between host validation and real `gnu-build-system` execution on FreeBSD - the known-good local Guile path is now validated as part of a practical Guix-adjacent build workflow, not just standalone subprocess diagnostics Recent commits: - `e380e88` — `Add FreeBSD Guile verification harness` - `cd721b1` — `Update progress after Guile verification` - `27916cb` — `Diagnose Guile subprocess crash on FreeBSD` - `02f7a7f` — `Validate local Guile fix on FreeBSD` - `4aebea4` — `Add native GNU Hello FreeBSD build harness` Next recommended step: 1. run the Scheme-driven phase-runner pattern against at least one more small GNU/autotools package on FreeBSD, or 2. document the concrete gaps between this prototype and a real Guix package/derivation build, especially around store management and build isolation 3. continue keeping `~/repos/bdwgc` in reserve if later FreeBSD-specific GC/thread issues appear ## 2026-04-01 — Phase 1.2 follow-up: second Scheme-driven GNU package build validated with GNU which Completed work: - added a second Scheme-driven GNU package harness: - `tests/native-build/gnu-which-guix-phase-runner.scm` - `tests/native-build/run-gnu-which-guix-phase-runner.sh` - again used the previously validated fixed local Guile build because this harness depends on subprocess-heavy Guix/Scheme builder logic - used the current Guix package definition in `~/repos/guix/gnu/packages/base.scm` as the source of truth for: - GNU which version `2.21` - expected Guix nix-base32 source hash `1bgafvy3ypbhhfznwjv1lxmd6mci3x1byilnnkc7gcr486wlb8pl` - verified the downloaded tarball against the translated SHA256: - `f4a245b94124b377d8b49646bf421f9155d36aa7614b6ebf83705d3ffc76eaad` - successfully executed the same subset of Guix builder-side `%standard-phases` on FreeBSD as used for GNU Hello: - `set-SOURCE-DATE-EPOCH` - `unpack` - `configure` - `build` - `check` - `install` - executed the resulting `which` binary successfully with a deterministic command: - `PATH=/bin:/usr/bin ./which sh` - confirmed output: - `/bin/sh` - captured metadata including: - host triplet - phase list - runtime dependencies - check-phase success status - executed command output - wrote the results to `docs/reports/phase1-guix-which-phase-runner.md` Important findings: - this confirms the Scheme-driven Guix builder-side phase-runner pattern is not limited to GNU Hello; a second small GNU/autotools package also succeeds on FreeBSD - GNU which's `check` phase passed, but it did not leave behind an Automake-style `test-suite.log` or `testsuite.log` - GNU which emitted a non-fatal `configure` warning about Guix's standard `--enable-fast-install` flag being unrecognized - the source also emitted several clang warnings about deprecated non-prototype C declarations/definitions, but the build still completed successfully - the resulting `which` binary again showed a minimal store-like runtime linkage profile: - `libc.so.7` - `libsys.so.7` - unlike GNU Hello, the source tree did not present an obvious shipped `config.guess`, so the harness used `cc -dumpmachine` as a fallback for host-triplet metadata Current assessment: - Phase 1.2 now has two successful Scheme-driven Guix builder-side GNU package validations on FreeBSD: - GNU Hello - GNU which - this increases confidence that a narrow but real subset of `gnu-build-system` builder-side execution already works on FreeBSD when paired with the fixed local Guile build - the next uncertainty is now less about whether basic builder phases run at all, and more about where real Guix package/derivation/store integration and isolation will first require FreeBSD-specific adaptation Recent commits: - `e380e88` — `Add FreeBSD Guile verification harness` - `cd721b1` — `Update progress after Guile verification` - `27916cb` — `Diagnose Guile subprocess crash on FreeBSD` - `02f7a7f` — `Validate local Guile fix on FreeBSD` - `4aebea4` — `Add native GNU Hello FreeBSD build harness` - `c944cdb` — `Validate Guix builder phases on FreeBSD` Next recommended step: 1. document the concrete remaining gap between these Scheme-driven phase-runner prototypes and a true Guix package/derivation/store-daemon build on FreeBSD, especially around store management, implicit inputs, and build isolation 2. or choose a somewhat more demanding GNU package with non-trivial declared inputs to identify the first builder-side FreeBSD adaptation points 3. continue keeping `~/repos/bdwgc` in reserve if later FreeBSD-specific GC/thread issues appear ## 2026-04-01 — Phase 1.2 follow-up: documented the gap to a real Guix package build Completed work: - analyzed the concrete remaining gap between the current FreeBSD validation harnesses and a real Guix package/derivation/store-daemon build - wrote the analysis to: - `docs/reports/phase1-guix-build-gap-analysis.md` - based the analysis on the current local Guix source tree, including the relevant host-side and daemon-side code paths in: - `guix/packages.scm` - `guix/build-system/gnu.scm` - `guix/gexp.scm` - `guix/store.scm` - `guix/derivations.scm` - `gnu/packages/commencement.scm` - `doc/guix.texi` - `nix/libstore/build.cc` - compared those real Guix layers against the currently validated FreeBSD prototypes: - shell-driven native GNU Hello harness - Scheme-driven GNU Hello builder-phase runner - Scheme-driven GNU which builder-phase runner Main conclusions recorded: - the current FreeBSD work has validated a narrow but real builder-side slice of Guix execution: - Guile can run the needed Scheme code when using the fixed local build - `(guix build gnu-build-system)` phases can build small GNU packages on FreeBSD - however, the current prototypes still bypass several critical layers of a real Guix build: - package -> bag lowering - bag -> derivation lowering - imported module closure/store materialization - real daemon RPC and build submission - canonical `/gnu/store` management and metadata - build users, chroot/container or jail-style isolation - substitute/graft/offload handling - documented that the current phase runners rely on host tools already present on FreeBSD, whereas real `gnu-build-system` uses implicit inputs drawn from `%final-inputs` - identified the most actionable next milestone as a derivation-generation investigation for a tiny package, to locate the first failure boundary among: - host-side lowering - store interaction - derivation emission - daemon availability - daemon-side execution Current assessment: - Phase 1.2 now has both practical build validation and a clearer architectural map of what remains before a true Guix package build can work on FreeBSD - the project has reduced uncertainty around builder-side GNU phase portability - the next uncertainty is now specifically the host-side lowering/store/daemon boundary, not the builder-phase boundary Recent commits: - `e380e88` — `Add FreeBSD Guile verification harness` - `cd721b1` — `Update progress after Guile verification` - `27916cb` — `Diagnose Guile subprocess crash on FreeBSD` - `02f7a7f` — `Validate local Guile fix on FreeBSD` - `4aebea4` — `Add native GNU Hello FreeBSD build harness` - `c944cdb` — `Validate Guix builder phases on FreeBSD` - `0a2e48e` — `Validate GNU which builder phases on FreeBSD` Next recommended step: 1. investigate whether a tiny package can be lowered far enough on FreeBSD to produce a real derivation, and capture the exact first failure point 2. if derivation generation proves immediately blocked, document whether the blocker is generated Guix modules/configuration, store connectivity, or daemon assumptions 3. continue keeping `~/repos/bdwgc` in reserve if later FreeBSD-specific GC/thread issues appear ## 2026-04-01 — Phase 1.2 follow-up: derivation-generation investigation identified the first real checkout blockers Completed work: - added a reproducible checkout/bootstrap/configure investigation harness: - `tests/guix/run-derivation-generation-investigation.sh` - used the previously validated fixed local Guile build for the investigation: - `/tmp/guile-freebsd-validate-install/bin/guile` - followed the operator instruction for future store setup by parameterizing the checkout attempts to use: - store directory: `/frx/store` - local state directory: `/frx/var` - sysconf directory: `/frx/etc` - created a disposable shared clone of `~/repos/guix` - successfully ran `./bootstrap` from that disposable checkout on FreeBSD - attempted `configure` without `--with-courage` - attempted `configure` again with `--with-courage` - confirmed directly that the local fixed Guile build currently cannot load: - `(gnutls)` - wrote the results to: - `docs/reports/phase1-guix-derivation-generation-investigation.md` Important findings: - a stock Guix checkout currently fails configuration on FreeBSD before any derivation/store/daemon work is reached, due to the explicit unsupported-platform gate: - ``configure: error: `x86_64-freebsd15.0' is not a supported platform.`` - re-running `configure` with `--with-courage` gets past that gate, but then stops on a second blocker: - `configure: error: The Guile bindings of GnuTLS are missing; please install them.` - a direct module-load test with the same local Guile confirms the problem more concretely: - `(use-modules (gnutls))` fails with `no code for module (gnutls)` - this means the current effort is still blocked before reaching: - usable `pre-inst-env` generation for Guix commands - package -> bag lowering in a live checkout - bag -> derivation lowering - daemon connectivity - actual `/frx/store` population Current assessment: - the first practical boundary between the earlier FreeBSD builder-phase prototypes and a real Guix checkout has now been located more precisely - the project is no longer blocked by vague uncertainty at this stage; it is blocked by two concrete checkout-preparation issues: 1. unsupported-platform configure gating 2. missing Guile `(gnutls)` bindings - importantly, the derivation-generation investigation has not yet reached the store/daemon boundary, so the next step must first clear the `(gnutls)` dependency issue Recent commits: - `e380e88` — `Add FreeBSD Guile verification harness` - `cd721b1` — `Update progress after Guile verification` - `27916cb` — `Diagnose Guile subprocess crash on FreeBSD` - `02f7a7f` — `Validate local Guile fix on FreeBSD` - `4aebea4` — `Add native GNU Hello FreeBSD build harness` - `c944cdb` — `Validate Guix builder phases on FreeBSD` - `0a2e48e` — `Validate GNU which builder phases on FreeBSD` - `245a47d` — `Document gaps to real Guix FreeBSD builds` Next recommended step: 1. obtain working Guile `(gnutls)` bindings compatible with the fixed local Guile build and re-run the derivation-generation investigation 2. once configuration succeeds, continue until the next failure boundary is identified among: - `pre-inst-env` usability - derivation emission - daemon connectivity - daemon-side `/frx/store` assumptions 3. continue keeping `~/repos/bdwgc` in reserve if later FreeBSD-specific GC/thread issues appear ## 2026-04-01 — Phase 1.2 follow-up: local Guile-GnuTLS built on FreeBSD; next blocker is Guile-Git Completed work: - installed the host-side C GnuTLS stack needed for Guile-GnuTLS builds: - `gnutls` - `libtasn1` - `nettle` - `p11-kit` - added a reproducible local Guile-GnuTLS build harness: - `tests/guix/build-local-guile-gnutls.sh` - updated the derivation-generation investigation harness so it can consume extra Guile module prefixes through: - `GUILE_EXTRA_PREFIX` - used the current Guix package definition in `~/repos/guix/gnu/packages/tls.scm` as the source of truth for: - `guile-gnutls` version `5.0.1` - expected Guix nix-base32 source hash `0kqngyx4520gjk49l6whjd2ss994kaj9rm78lli6p3q6xry0945i` - verified the downloaded Guile-GnuTLS tarball against the translated SHA256: - `b190047cee068f6b22a5e8d49ca49a2425ad4593901b9ac8940f8842ba7f164f` - built and installed a local Guile-GnuTLS validation copy against the previously validated fixed local Guile build under: - `/tmp/guile-gnutls-freebsd-validate-install` - validated successfully that the fixed local Guile can now load: - `(gnutls)` - re-ran the checkout derivation-generation investigation with: - `GUILE_EXTRA_PREFIX=/tmp/guile-gnutls-freebsd-validate-install` - store directory still set to `/frx/store` - wrote the results to: - `docs/reports/phase1-guile-gnutls-freebsd.md` Important findings: - Guile-GnuTLS does not build with FreeBSD base `make`; it requires GNU `gmake` - a FreeBSD-specific source compatibility issue surfaced in `guile/src/core.c`: - it includes `` unconditionally - on this host, `alloca` is available through `` instead - for local validation, the harness applies a small disposable-tree patch that uses `` on `__FreeBSD__` - after that fix, the local Guile-GnuTLS build succeeded and `(use-modules (gnutls))` worked with the fixed local Guile build - re-running the Guix checkout investigation confirms the earlier `(gnutls)` blocker is genuinely cleared - the next configure-time blocker is now: - `configure: error: Guile-Git is missing; please install it.` Current assessment: - the first checkout-preparation blocker after unsupported-platform gating has advanced from missing `(gnutls)` to missing `Guile-Git` - this is meaningful progress because the project is now moving farther into the dependency chain required for a real Guix checkout on FreeBSD - the requested experimental store path remains `/frx/store`, but the effort still has not yet reached actual store population or daemon interaction Recent commits: - `e380e88` — `Add FreeBSD Guile verification harness` - `cd721b1` — `Update progress after Guile verification` - `27916cb` — `Diagnose Guile subprocess crash on FreeBSD` - `02f7a7f` — `Validate local Guile fix on FreeBSD` - `4aebea4` — `Add native GNU Hello FreeBSD build harness` - `c944cdb` — `Validate Guix builder phases on FreeBSD` - `0a2e48e` — `Validate GNU which builder phases on FreeBSD` - `245a47d` — `Document gaps to real Guix FreeBSD builds` - `d62e9b0` — `Investigate Guix derivation generation on FreeBSD` Next recommended step: 1. obtain `Guile-Git` compatible with the fixed local Guile build and re-run the derivation-generation investigation again 2. once checkout configuration succeeds, continue until the next failure boundary is identified among: - `pre-inst-env` usability - derivation emission - daemon connectivity - daemon-side `/frx/store` assumptions 3. continue keeping `~/repos/bdwgc` in reserve if later FreeBSD-specific GC/thread issues appear ## 2026-04-01 — Phase 1.2 follow-up: local Guile-Git stack built on FreeBSD; next blocker is Guile-JSON Completed work: - added a reproducible local Guile-Git dependency-stack build harness: - `tests/guix/build-local-guile-git.sh` - updated the derivation-generation investigation harness to probe and record both: - local `(gnutls)` availability - local `(git)` / `graph-descendant?` availability - used the current Guix package definitions in `~/repos/guix/gnu/packages/guile.scm` as the source of truth for: - `guile-bytestructures` version `1.0.10` - `guile-git` version `0.10.0` - built `guile-bytestructures` from the matching upstream tag and recorded resolved commit: - `27cadba6b69a01b38b33bb39b9766d713eb90c1b` - built `guile-git` from the matching upstream tag and recorded resolved commit: - `05d4a48c811f29c8db80ee6697fe658950fb503e` - installed both into the same local dependency prefix already used for the earlier Guile-GnuTLS validation: - `/tmp/guile-gnutls-freebsd-validate-install` - validated successfully that the fixed local Guile can now load: - `(bytestructures guile)` - `(git)` - validated specifically that the Guile-Git export required by Guix `configure.ac` is present: - `graph-descendant?` - confirmed the host `libgit2` dependency used for the build is: - `1.9.2` - re-ran the checkout derivation-generation investigation with: - `GUILE_EXTRA_PREFIX=/tmp/guile-gnutls-freebsd-validate-install` - store directory still set to `/frx/store` - wrote the results to: - `docs/reports/phase1-guile-git-freebsd.md` Important findings: - both `guile-bytestructures` and `guile-git` were built from Git source layouts, so autotools regeneration was required: - `guile-bytestructures`: `autoreconf -vfi` - `guile-git`: `autoreconf -vfi` via harness fallback - unlike the earlier Guile-GnuTLS step, no additional FreeBSD-specific source patch was needed for either package in this validation pass - the Guix checkout now gets past both previously cleared dependency gates: - `(gnutls)` - `Guile-Git` - after clearing those, the next configure-time blocker is now: - `configure: error: Guile-JSON is missing; please install it.` Current assessment: - the checkout-preparation path on FreeBSD has progressed one dependency layer deeper - the local validation prefix under `/tmp/guile-gnutls-freebsd-validate-install` now contains at least: - Guile-GnuTLS - Guile bytestructures - Guile-Git - despite that progress, the work still has not yet reached derivation emission, daemon connectivity, or actual `/frx/store` population - the next concrete blocker is now `Guile-JSON`, as reported directly by the real Guix checkout configure step Recent commits: - `e380e88` — `Add FreeBSD Guile verification harness` - `cd721b1` — `Update progress after Guile verification` - `27916cb` — `Diagnose Guile subprocess crash on FreeBSD` - `02f7a7f` — `Validate local Guile fix on FreeBSD` - `4aebea4` — `Add native GNU Hello FreeBSD build harness` - `c944cdb` — `Validate Guix builder phases on FreeBSD` - `0a2e48e` — `Validate GNU which builder phases on FreeBSD` - `245a47d` — `Document gaps to real Guix FreeBSD builds` - `d62e9b0` — `Investigate Guix derivation generation on FreeBSD` - `c0a85ed` — `Build local Guile-GnuTLS on FreeBSD` Next recommended step: 1. obtain `Guile-JSON` compatible with the fixed local Guile build and install it into the same local dependency prefix 2. re-run the derivation-generation investigation again to identify the next configure-time or checkout-time blocker after `Guile-JSON` 3. continue keeping `/frx/store` as the intended experimental store root and keep `~/repos/bdwgc` in reserve if later FreeBSD-specific GC/thread issues appear ## 2026-04-01 — Phase 1.2 follow-up: local Guile-JSON built on FreeBSD; next blocker is Guile-SQLite3 Completed work: - added a reproducible local Guile-JSON build harness: - `tests/guix/build-local-guile-json.sh` - updated the derivation-generation investigation harness to probe and record local recent-enough `(json)` availability in addition to the earlier `(gnutls)` and `(git)` checks - used the current Guix package definition in `~/repos/guix/gnu/packages/guile.scm` as the source of truth for: - `guile-json` version `4.7.3` - expected Guix nix-base32 source hash `127k2xc07w1gnyqs40z4865l8p3ra5xgpcn569dz04lxsa709fiq` - verified the downloaded Guile-JSON tarball against the translated SHA256: - `38ba048ed29d12f05b32c5b2fb7a51795c448b41e403a2b1b72ff0035817f388` - built and installed a local Guile-JSON validation copy into the same local dependency prefix already used for checkout prerequisites: - `/tmp/guile-gnutls-freebsd-validate-install` - validated successfully that the fixed local Guile now satisfies the Guix configure-time JSON requirement by: - loading `(json)` - using `define-json-mapping` - decoding a small JSON object successfully - re-ran the checkout derivation-generation investigation with: - `GUILE_EXTRA_PREFIX=/tmp/guile-gnutls-freebsd-validate-install` - store directory still set to `/frx/store` - wrote the results to: - `docs/reports/phase1-guile-json-freebsd.md` Important findings: - unlike the earlier Guile-Git step, Guile-JSON built cleanly from the release tarball and did not require autotools regeneration in this validation pass - unlike the earlier Guile-GnuTLS step, no FreeBSD-specific source patch was needed here - the shared local validation prefix now contains at least: - Guile-GnuTLS - Guile bytestructures - Guile-Git - Guile-JSON - the Guix checkout now gets past the previously cleared dependency gates for: - `(gnutls)` - `Guile-Git` - `Guile-JSON` - after clearing those, the next configure-time blocker is now: - `configure: error: A recent Guile-SQLite3 could not be found; please install it.` Current assessment: - the checkout-preparation path on FreeBSD has progressed another dependency layer deeper - the project still has not yet reached derivation emission, daemon connectivity, or actual `/frx/store` population - the next concrete blocker is now recent `Guile-SQLite3`, as reported directly by the real Guix checkout configure step Recent commits: - `e380e88` — `Add FreeBSD Guile verification harness` - `cd721b1` — `Update progress after Guile verification` - `27916cb` — `Diagnose Guile subprocess crash on FreeBSD` - `02f7a7f` — `Validate local Guile fix on FreeBSD` - `4aebea4` — `Add native GNU Hello FreeBSD build harness` - `c944cdb` — `Validate Guix builder phases on FreeBSD` - `0a2e48e` — `Validate GNU which builder phases on FreeBSD` - `245a47d` — `Document gaps to real Guix FreeBSD builds` - `d62e9b0` — `Investigate Guix derivation generation on FreeBSD` - `c0a85ed` — `Build local Guile-GnuTLS on FreeBSD` - `15b9037` — `Build local Guile-Git on FreeBSD` Next recommended step: 1. obtain recent `Guile-SQLite3` compatible with the fixed local Guile build and install it into the same local dependency prefix 2. re-run the derivation-generation investigation again to identify the next configure-time or checkout-time blocker after `Guile-SQLite3` 3. continue keeping `/frx/store` as the intended experimental store root and keep `~/repos/bdwgc` in reserve if later FreeBSD-specific GC/thread issues appear ## 2026-04-01 — Phase 1.2 follow-up: remaining checkout Guile prerequisites built; next blocker is `./pre-inst-env guix --version` Completed work: - installed the remaining missing host C library dependencies required for the next Guile extension stack: - `libgcrypt` - `libgpg-error` - `lzlib` - added a reproducible build harness for the remaining mandatory Guix checkout Guile modules: - `tests/guix/build-local-guile-configure-deps.sh` - extended the derivation-generation investigation harness to: - probe local recent-enough availability for: - `(sqlite3)` - `(gcrypt hash)` - `(zlib)` - `(lzlib)` - `(semver)` - run checkout `configure` with: - `MAKE=gmake` - continue past successful configuration into: - `gmake scripts/guix` - `./pre-inst-env guix --version` - used the current Guix package definitions as source of truth for the following additional module stack: - `guile-sqlite3` `0.1.3` - `guile-gcrypt` `0.5.0` - `guile-zlib` `0.2.2` - `guile-lzlib` `0.3.0` - `guile-semver` `0.2.0` - built and installed those modules into the same shared local dependency prefix already used for prior checkout prerequisites: - `/tmp/guile-gnutls-freebsd-validate-install` - validated successfully that the fixed local Guile can now satisfy all of the remaining configure-time Guix module checks encountered so far: - `(sqlite3)` with `sqlite-bind-arguments` - `(gcrypt hash)` with `hash-algorithm` lookup - `(zlib)` with `make-zlib-input-port` - `(lzlib)` - `(semver)` - re-ran the checkout derivation-generation investigation with: - `GUILE_EXTRA_PREFIX=/tmp/guile-gnutls-freebsd-validate-install` - store directory still set to `/frx/store` - wrote the results to: - `docs/reports/phase1-guix-checkout-configure-stack-freebsd.md` Important findings: - `guile-gcrypt` required an explicit configure workaround on this host: - `--with-libgcrypt-prefix=/usr/local` - without it, the package's `libgcrypt-config --libs` parsing produced an unusable shared-library name on FreeBSD - the currently served upstream `guile-lzlib` `0.3.0` tarball no longer matches the Guix-recorded hash: - expected from Guix: `a7f99c8d2a143e05ea22db2dc8b9ce6c27cae942162b45ee3015ed9027af0ff2` - observed from current source URL: `6a2847a303a141bb95b1b5d1a4b975b4dbff9cc590eba377cc8072682e7637ec` - for local validation, the harness fell back to the matching upstream Git tag and recorded commit: - `474cee42116295bc0bd2acf12d4d6a766043090e` - once the remaining Guile modules were present, checkout `configure --with-courage` stopped failing on missing modules - however, the checkout still needed: - `MAKE=gmake` to complete configuration successfully on FreeBSD - after that, `gmake scripts/guix` succeeded as well - the next concrete blocker has moved from configuration-time prerequisites to runtime behavior of the uninstalled Guix command path: - `./pre-inst-env guix --version` prints the version banner, then exits with: - `Wrong type to apply: #` Current assessment: - the checkout-preparation path on FreeBSD has now progressed beyond the missing mandatory Guile module stack that previously blocked configuration - the current local validation prefix now contains the required configure-time modules encountered so far for a real Guix checkout - the first blocker after successful checkout configuration and `scripts/guix` generation is now a runtime Scheme failure in the uninstalled `guix` command path itself - the work is therefore now meaningfully past “cannot configure” and into “configures, builds `scripts/guix`, but fails at `./pre-inst-env guix --version`” Recent commits: - `e380e88` — `Add FreeBSD Guile verification harness` - `cd721b1` — `Update progress after Guile verification` - `27916cb` — `Diagnose Guile subprocess crash on FreeBSD` - `02f7a7f` — `Validate local Guile fix on FreeBSD` - `4aebea4` — `Add native GNU Hello FreeBSD build harness` - `c944cdb` — `Validate Guix builder phases on FreeBSD` - `0a2e48e` — `Validate GNU which builder phases on FreeBSD` - `245a47d` — `Document gaps to real Guix FreeBSD builds` - `d62e9b0` — `Investigate Guix derivation generation on FreeBSD` - `c0a85ed` — `Build local Guile-GnuTLS on FreeBSD` - `15b9037` — `Build local Guile-Git on FreeBSD` - `47d31e8` — `Build local Guile-JSON on FreeBSD` Next recommended step: 1. investigate the `leave-on-EPIPE` runtime failure now blocking `./pre-inst-env guix --version` 2. complete the remaining Phase 1.3 FreeBSD system-call mapping/documentation deliverable so Phase 1 foundations can be closed out cleanly 3. continue keeping `/frx/store` as the intended experimental store root and keep `~/repos/bdwgc` in reserve if later FreeBSD-specific GC/thread issues appear ## 2026-04-01 — Phase 1.3 completed: FreeBSD syscall/interface mapping documented and exercised Completed work: - added a runnable C syscall/interface mapping harness: - `tests/system/freebsd-syscall-mapping.c` - added a shell runner for the mapping harness: - `tests/system/run-freebsd-syscall-mapping.sh` - inspected current Guix/Linux-oriented source paths relevant to daemon/build isolation and host behavior, especially: - `~/repos/guix/nix/libstore/build.cc` - `~/repos/guix/configure.ac` - inspected the relevant FreeBSD interfaces/documentation available on the host, including: - `jail(2)` - `chroot(2)` - `closefrom(2)` / `close_range(2)` - `mount(2)` / `nmount(2)` - `mount_nullfs(8)` - `cap_enter(2)` - `cap_rights_limit(2)` - `lutimes(2)` - `lchown(2)` - `posix_fallocate(2)` - `pdfork(2)` - ran the new syscall mapping harness successfully and captured metadata under: - `/tmp/freebsd-syscall-mapping-metadata.txt` - wrote the Phase 1.3 report to: - `docs/reports/phase1-freebsd-syscall-mapping.md` Important findings: - the current FreeBSD host provides and the harness successfully exercised: - `fork` / `waitpid` - `posix_spawn_file_actions_addclosefrom_np` - `close_range` - `lutimes` - `statvfs` - `chroot` (root test) - `jail(2)` (root test) - `lchown` (root test) - the same harness confirmed the absence of the key Linux namespace-oriented interfaces that current Guix daemon code depends on: - `clone` - `unshare` - `setns` - `pivot_root` - `sys/prctl.h` - FreeBSD Capsicum headers are present, which is useful context for later security design, but Capsicum is not a direct replacement for Linux namespaces or Linux capabilities - `posix_fallocate` is present but returned `EOPNOTSUPP` on the tested filesystems, so a successful configure/link probe does not guarantee useful runtime semantics - the mapping strongly confirms that the correct Phase 2 direction is not syscall emulation but a jail-first redesign using: - jails - `chroot` - `nullfs` - traditional build-user privilege separation Current assessment: - the Phase 1.3 deliverable is now satisfied with both: - a technical mapping document, and - a runnable validation harness - the main architectural conclusion is now concrete rather than speculative: - Linux namespace code paths in current Guix daemon/build isolation cannot be ported directly to FreeBSD - the FreeBSD implementation must instead be designed around jails and explicit mount/layout control ## 2026-04-01 — Phase 1 completed on the current FreeBSD amd64 porting track Phase 1 is now considered complete for the active amd64 FreeBSD host path. Why this milestone is satisfied: - **Phase 1.1** success criteria were met on the current host: - Guile executes Guix bootstrap-related code - deterministic/module/FFI/socket/process validation succeeded - the FreeBSD subprocess crash was root-caused and a working fixed local Guile path was validated - **Phase 1.2** success criteria were exceeded: - native GNU Hello build success was demonstrated - multiple Guix builder-side GNU phase validations succeeded - a real Guix checkout now configures on FreeBSD with local dependency supplementation, builds `scripts/guix`, and reaches a concrete runtime blocker at: - `./pre-inst-env guix --version` - **Phase 1.3** is now completed with the syscall/interface mapping document and runnable harness Important scope note: - the original Phase 1.1 narrative mentioned `i386` as additional target coverage, but the explicit success criteria used to gate progression have been satisfied on the active amd64 FreeBSD host - full i386 Guile validation remains useful future coverage work, but it is no longer the blocker for moving into Phase 2 design/prototyping on this machine Recent commits: - `e380e88` — `Add FreeBSD Guile verification harness` - `cd721b1` — `Update progress after Guile verification` - `27916cb` — `Diagnose Guile subprocess crash on FreeBSD` - `02f7a7f` — `Validate local Guile fix on FreeBSD` - `4aebea4` — `Add native GNU Hello FreeBSD build harness` - `c944cdb` — `Validate Guix builder phases on FreeBSD` - `0a2e48e` — `Validate GNU which builder phases on FreeBSD` - `245a47d` — `Document gaps to real Guix FreeBSD builds` - `d62e9b0` — `Investigate Guix derivation generation on FreeBSD` - `c0a85ed` — `Build local Guile-GnuTLS on FreeBSD` - `15b9037` — `Build local Guile-Git on FreeBSD` - `47d31e8` — `Build local Guile-JSON on FreeBSD` - `d82195b` — `Advance Guix checkout on FreeBSD` Next recommended step: 1. begin Phase 2.1 by turning the new syscall mapping into a concrete FreeBSD jail-based build-isolation design/prototype 2. carry forward the current concrete runtime blocker from Phase 1.2: - investigate the `leave-on-EPIPE` failure in `./pre-inst-env guix --version` 3. continue keeping `/frx/store` as the intended experimental store root and keep `~/repos/bdwgc` in reserve if later FreeBSD-specific GC/thread issues appear ## 2026-04-01 — Phase 2.1 completed: jail-first build isolation design validated on FreeBSD Completed work: - added a runnable jail-based build isolation prototype: - `tests/daemon/run-freebsd-jail-build-prototype.sh` - wrote the Phase 2.1 design/prototype report: - `docs/reports/phase2-freebsd-jail-build-isolation.md` - translated the earlier Phase 1 syscall mapping into a concrete FreeBSD Guix-daemon isolation design centered on: - thin jails - one jail per build - explicit `nullfs` mount plans - networking disabled by default - separate build-user credentials inside the jail envelope - ran the jail prototype successfully and captured metadata under: - `/tmp/jail-build-metadata.txt` Important findings: - a thin-jail approach is the right match for Guix's declared-input model; thick jails would overexpose ambient host state and add unnecessary duplication - a per-build jail root assembled from explicit read-only `nullfs` mounts is a practical replacement for the Linux bind-mount + mount-namespace model in current Guix daemon code - a basic build operation can already be executed successfully inside a FreeBSD jail with a restricted filesystem view consisting only of: - selected read-only host toolchain paths - a read-only declared input directory - a writable declared output directory - a writable `/tmp` - a host sentinel file left outside the jail root is not visible inside the build environment, confirming the prototype is exercising real visibility restriction rather than a mere chroot-like shell wrapper - the prototype jail ran with: - `ip4=disable` - `ip6=disable` which matches the intended default for hermetic builds Current assessment: - Phase 2.1 is now satisfied on the current FreeBSD prototype track - the main design decision is now concrete rather than speculative: - the Guix FreeBSD daemon path should be jail-first, not Linux-namespace emulation - the next step is to add a build-user privilege-dropping prototype inside or alongside this jail model so the design covers both containment and user-level isolation Recent commits: - `e380e88` — `Add FreeBSD Guile verification harness` - `cd721b1` — `Update progress after Guile verification` - `27916cb` — `Diagnose Guile subprocess crash on FreeBSD` - `02f7a7f` — `Validate local Guile fix on FreeBSD` - `4aebea4` — `Add native GNU Hello FreeBSD build harness` - `c944cdb` — `Validate Guix builder phases on FreeBSD` - `0a2e48e` — `Validate GNU which builder phases on FreeBSD` - `245a47d` — `Document gaps to real Guix FreeBSD builds` - `d62e9b0` — `Investigate Guix derivation generation on FreeBSD` - `c0a85ed` — `Build local Guile-GnuTLS on FreeBSD` - `15b9037` — `Build local Guile-Git on FreeBSD` - `47d31e8` — `Build local Guile-JSON on FreeBSD` - `d82195b` — `Advance Guix checkout on FreeBSD` - `9bf3d30` — `Document FreeBSD syscall mapping` Next recommended step: 1. implement the Phase 2.2 privilege-dropping/build-user prototype for FreeBSD, ideally combined with the new jail execution model 2. then establish a `/frx/store`-based store-management prototype covering permissions, package readability, and garbage-collection behavior 3. continue carrying the separate Guix checkout runtime blocker: - investigate the `leave-on-EPIPE` failure in `./pre-inst-env guix --version` ## 2026-04-01 — Phase 2.2 completed: privilege dropping and concurrent build-user isolation validated Completed work: - added a C helper implementing the core daemon-side privilege drop mechanics: - `tests/daemon/freebsd-build-user-helper.c` - added a harness that combines that helper with the new jail model and runs two jobs concurrently: - `tests/daemon/run-freebsd-privilege-drop-prototype.sh` - wrote the Phase 2.2 report: - `docs/reports/phase2-freebsd-privilege-drop.md` - ran the concurrent build-user prototype successfully and captured metadata under: - `/tmp/freebsd-privdrop-metadata.txt` Important findings: - a root-launched FreeBSD helper can successfully perform the expected daemon-side transition: - `setgroups` - `setgid` - `setuid` into a dedicated build identity - once dropped, the helper cannot regain root with `setuid(0)`: - `Operation not permitted` - each build job can create files in its own writable directory and those files end up owned by the dropped build UID/GID rather than by root - two concurrent jobs using distinct numeric build identities succeeded with: - job 1 UID/GID `35001:35001` - job 2 UID/GID `35002:35002` - host-side result files were observed with the matching ownership and restrictive permissions: - `0600` - the two jobs were deliberately held for two seconds each and the measured wall-clock elapsed time was also about two seconds, demonstrating actual concurrent execution rather than serialized execution - two complementary denial modes were validated at the same time: - peer build files mounted but blocked by permissions: `Permission denied` - host path not mounted into the jail at all: `No such file or directory` - the dropped build user also could not: - create files in a protected root-owned directory - `chown` its own output back to root Current assessment: - Phase 2.2 is now satisfied on the current FreeBSD prototype track - the combined jail + build-user model now has practical validation for the most important security properties required by a future FreeBSD Guix daemon: - root-controlled setup - permanent drop to build credentials - per-build writable areas - cross-build isolation - concurrent execution under distinct identities - the remaining Phase 2 work is now centered on the store itself: permissions, readability, content-addressed layout, and garbage-collection behavior under `/frx/store` Recent commits: - `e380e88` — `Add FreeBSD Guile verification harness` - `cd721b1` — `Update progress after Guile verification` - `27916cb` — `Diagnose Guile subprocess crash on FreeBSD` - `02f7a7f` — `Validate local Guile fix on FreeBSD` - `4aebea4` — `Add native GNU Hello FreeBSD build harness` - `c944cdb` — `Validate Guix builder phases on FreeBSD` - `0a2e48e` — `Validate GNU which builder phases on FreeBSD` - `245a47d` — `Document gaps to real Guix FreeBSD builds` - `d62e9b0` — `Investigate Guix derivation generation on FreeBSD` - `c0a85ed` — `Build local Guile-GnuTLS on FreeBSD` - `15b9037` — `Build local Guile-Git on FreeBSD` - `47d31e8` — `Build local Guile-JSON on FreeBSD` - `d82195b` — `Advance Guix checkout on FreeBSD` - `9bf3d30` — `Document FreeBSD syscall mapping` - `7621798` — `Prototype FreeBSD jail build isolation` Next recommended step: 1. complete Phase 2.3 by establishing a `/frx/store`-based store prototype with: - correct root/daemon write restrictions - unprivileged read access - content-addressed path naming - garbage-collection behavior 2. if possible, use outputs or dependency relationships realistic enough to model how a future FreeBSD Guix daemon would retain referenced store items 3. continue carrying the separate Guix checkout runtime blocker: - investigate the `leave-on-EPIPE` failure in `./pre-inst-env guix --version` ## 2026-04-01 — Phase 2.3 completed: `/frx/store` prototype validated on FreeBSD Completed work: - added a runnable `/frx/store` prototype harness: - `tests/store/run-freebsd-store-prototype.sh` - wrote the Phase 2.3 report: - `docs/reports/phase2-freebsd-store-prototype.md` - created and exercised the operator-requested `/frx` layout on-host: - `/frx/store` - `/frx/var` - `/frx/etc` - `/frx/var/fruix/gcroots` - created a store group for the prototype path: - `fruixbuild` - ran the store prototype successfully and captured metadata under: - `/tmp/freebsd-store-prototype-metadata.txt` Important findings: - the current host now has a working `/frx/store` prototype owned as: - `root:fruixbuild` with mode: - `drwxrwxr-t` - the prototype successfully created content-addressed demo store items under `/frx/store` using hash-based names - the demo item set included: - rooted greeting data - a rooted app referencing that data through an absolute store path - an unrooted orphan item intended for collection - an unprivileged user (`nobody`) could: - read store data - execute the demo app from the store - the same unprivileged user could not: - create files directly in `/frx/store` and the observed failure was: - `Permission denied` - the prototype GC logic followed rooted references successfully: - with a GC root present, the app and its referenced data survived while the orphan item was collected - after removing the GC root, the remaining demo items were collected as well - the demo store returned to an empty state after the second GC pass, so the host is left with the `/frx` skeleton but without lingering prototype payloads Current assessment: - Phase 2.3 is now satisfied on the current FreeBSD prototype track - the core store assumptions needed for a FreeBSD Guix-daemon design have practical validation now: - `/frx/store` path viability - root-controlled mutation - unprivileged read access - immutable absolute store references - root-managed GC roots and mark/sweep retention behavior - remaining gaps are now above this architectural layer rather than below it: - real derivation registration - SQLite-backed store metadata - daemon RPC integration - actual package lowering/build submission using these mechanisms ## 2026-04-01 — Phase 2 completed on the current FreeBSD prototype track Phase 2 is now considered complete for the active FreeBSD amd64 prototype path. Why this milestone is satisfied: - **Phase 2.1** success criteria were met: - a detailed jail-first build-isolation design was produced - a runnable prototype successfully executed a build command in a restricted FreeBSD jail - **Phase 2.2** success criteria were met: - a concrete C privilege-dropping implementation was added - build-user credential drop, inability to regain root, and concurrent cross-build isolation were demonstrated - **Phase 2.3** success criteria were met on the prototype track: - a working `/frx/store` equivalent was established - content-addressed demo store items were created and consumed - unprivileged read vs. privileged write behavior was validated - garbage-collection behavior over rooted references was demonstrated Important scope note: - this completes the **core daemon architecture adaptation** milestone, not a full Guix-daemon port - the separate real-checkout blocker from Phase 1 remains relevant for later integration work: - `./pre-inst-env guix --version` still fails with `Wrong type to apply: #` - however, that runtime issue no longer blocks the specific Phase 2 architectural deliverables because the jail, privilege, and store assumptions have now been validated independently on FreeBSD Recent commits: - `e380e88` — `Add FreeBSD Guile verification harness` - `cd721b1` — `Update progress after Guile verification` - `27916cb` — `Diagnose Guile subprocess crash on FreeBSD` - `02f7a7f` — `Validate local Guile fix on FreeBSD` - `4aebea4` — `Add native GNU Hello FreeBSD build harness` - `c944cdb` — `Validate Guix builder phases on FreeBSD` - `0a2e48e` — `Validate GNU which builder phases on FreeBSD` - `245a47d` — `Document gaps to real Guix FreeBSD builds` - `d62e9b0` — `Investigate Guix derivation generation on FreeBSD` - `c0a85ed` — `Build local Guile-GnuTLS on FreeBSD` - `15b9037` — `Build local Guile-Git on FreeBSD` - `47d31e8` — `Build local Guile-JSON on FreeBSD` - `d82195b` — `Advance Guix checkout on FreeBSD` - `9bf3d30` — `Document FreeBSD syscall mapping` - `7621798` — `Prototype FreeBSD jail build isolation` - `d65b2af` — `Prototype FreeBSD build user isolation` Next recommended step: 1. begin Phase 3.1 by adapting Guix build-system expectations to the now-validated jail/privilege/store model on FreeBSD 2. carry forward the concrete real-checkout runtime blocker for later integration work: - investigate the `leave-on-EPIPE` failure in `./pre-inst-env guix --version` 3. continue using `/frx/store` rather than `/gnu/store` for FreeBSD store experiments ## 2026-04-01 — Phase 3.1 completed: reusable FreeBSD GNU build-system adaptation validated across five packages Completed work: - added a reusable Scheme runner for FreeBSD-adapted GNU package builds: - `tests/build-system/gnu-package-freebsd-phase-runner.scm` - added a shell wrapper for the generic runner: - `tests/build-system/run-gnu-package-freebsd-phase-runner.sh` - added a five-package validation matrix: - `tests/build-system/run-freebsd-gnu-package-matrix.sh` - wrote the Phase 3.1 report: - `docs/reports/phase3-freebsd-gnu-build-system.md` - ran the matrix successfully and captured summary metadata under: - `/tmp/freebsd-gnu-package-matrix-summary.txt` Important findings: - the build adaptation is now centralized rather than package-specific and is applied through a dedicated pre-configure FreeBSD environment phase - the adaptation consistently uses: - GNU `gmake` via a `make` path shim - FreeBSD Clang via `cc`/`gcc` and `c++`/`g++` tool shims - `CONFIG_SHELL=/bin/sh` - `/usr/local` include/library/pkg-config search paths - five representative GNU packages from current Guix package definitions now build successfully through the adapted runner on the current FreeBSD amd64 host: - `hello` `2.12.3` - `which` `2.21` - `time` `1.9` - `patch` `2.8` - `nano` `8.7.1` - the resulting binaries executed correctly with deterministic checks appropriate to each package: - `hello` -> `Hello, world!` - `which` -> `/bin/sh` - `time` -> `time (GNU Time) 1.9` - `patch` -> `GNU patch 2.8` - `nano` -> `GNU nano, version 8.7.1` - the matrix also validated a package with meaningful runtime dependencies: - `nano` linked against FreeBSD/base and `/usr/local` libraries including `libintl`, `libmagic`, `libncursesw`, `libtinfow`, and `libz` - one package-specific FreeBSD test boundary was recorded explicitly instead of being hidden: - `time` required `RUN_TESTS=0` because the upstream `time-max-rss` test was not reliable on this host Current assessment: - Phase 3.1 is now satisfied on the current prototype track - the main question has shifted from “can adapted GNU builder phases run on FreeBSD?” to “how should FreeBSD system components themselves be described and installed as profile-usable packages?” - the next step is therefore Phase 3.2: define a minimal FreeBSD package set with explicit dependencies and validate profile-style installation/usability Recent commits: - `e380e88` — `Add FreeBSD Guile verification harness` - `cd721b1` — `Update progress after Guile verification` - `27916cb` — `Diagnose Guile subprocess crash on FreeBSD` - `02f7a7f` — `Validate local Guile fix on FreeBSD` - `4aebea4` — `Add native GNU Hello FreeBSD build harness` - `c944cdb` — `Validate Guix builder phases on FreeBSD` - `0a2e48e` — `Validate GNU which builder phases on FreeBSD` - `245a47d` — `Document gaps to real Guix FreeBSD builds` - `d62e9b0` — `Investigate Guix derivation generation on FreeBSD` - `c0a85ed` — `Build local Guile-GnuTLS on FreeBSD` - `15b9037` — `Build local Guile-Git on FreeBSD` - `47d31e8` — `Build local Guile-JSON on FreeBSD` - `d82195b` — `Advance Guix checkout on FreeBSD` - `9bf3d30` — `Document FreeBSD syscall mapping` - `7621798` — `Prototype FreeBSD jail build isolation` - `d65b2af` — `Prototype FreeBSD build user isolation` - `e404e2e` — `Prototype FreeBSD store management` Next recommended step: 1. complete Phase 3.2 by defining a minimal FreeBSD system package set with explicit dependency relationships and profile-style installation validation 2. carry forward the concrete real-checkout runtime blocker for later integration work: - investigate the `leave-on-EPIPE` failure in `./pre-inst-env guix --version` 3. continue using `/frx/store` rather than `/gnu/store` for future FreeBSD store experiments when the prototype work needs a persistent store root ## 2026-04-01 — Phase 3.2 completed: FreeBSD system package-definition prototype and profile validation added Completed work: - added a Guix-style FreeBSD system package-definition prototype module: - `modules/fruix/packages/freebsd.scm` - added a Scheme harness to materialize those package definitions into store-like outputs and a merged profile: - `tests/packages/freebsd-package-profile-prototype.scm` - added a shell wrapper for that harness: - `tests/packages/run-freebsd-package-profile-prototype.sh` - installed the missing host shell dependency needed to satisfy the requested package set: - `bash` - wrote the Phase 3.2 report: - `docs/reports/phase3-freebsd-package-definitions.md` - ran the profile prototype successfully and captured metadata under: - `/tmp/freebsd-package-profile-prototype-metadata.txt` Important findings: - the prototype now defines a minimal FreeBSD core package set covering the categories requested by Phase 3.2: - kernel - kernel headers - libc - userland utilities - development tools (`clang`, `make`, autotools) - minimum system libraries (`openssl`, `zlib`) - shells (`sh`, `bash`) - the current package-definition layer uses an explicit Guix-like record shape with fields for: - name - version - build system - inputs - synopsis/description/home-page/license - install plan - explicit dependency relationships are now encoded and resolved recursively during materialization, including examples such as: - `freebsd-libc` -> `freebsd-kernel-headers` - `freebsd-userland` -> `freebsd-libc`, `freebsd-sh` - `freebsd-clang-toolchain` -> `freebsd-libc`, `freebsd-kernel-headers`, `freebsd-sh` - `freebsd-autotools` -> `freebsd-gmake`, `freebsd-bash`, `freebsd-libc` - the harness successfully materialized: - `11` core package outputs into a store-like directory tree under the work directory - it then merged those outputs into a development profile and validated that the profile contains working: - `bash` - `make` - `autoconf` - `cc` - kernel image path - kernel-header path - core shared-library paths - the generated profile compiled and ran a C test program successfully, with observed output: - `hello-from-freebsd-profile` - for executables installed under `bin/`, the prototype uses wrappers that `exec` the host tool by absolute path; this preserved correct behavior for prefix-sensitive tools such as `autoconf` Current assessment: - Phase 3.2 is now satisfied on the current prototype track - Phase 3 as a whole is now completed on the current FreeBSD amd64 path because both: - adapted GNU build-system execution, and - minimal FreeBSD system package-definition/profile validation have been demonstrated successfully - the next remaining project milestone is now Phase 4, centered on Shepherd rather than package-building foundations ## 2026-04-01 — Phase 3 completed on the current FreeBSD prototype track Phase 3 is now considered complete for the active FreeBSD amd64 prototype path. Why this milestone is satisfied: - **Phase 3.1** success criteria were met on the prototype track: - a reusable FreeBSD adaptation layer for GNU builder phases was added - five representative GNU packages built successfully through that adapted runner - the resulting binaries executed correctly on the host - **Phase 3.2** success criteria were met on the prototype track: - a minimal FreeBSD system package-definition layer was added - explicit dependency relationships were modeled and resolved - the package outputs installed into a merged profile successfully - the generated profile was validated by compiling and running a test program with the staged toolchain Important scope note: - this completes the **build-system adaptation milestone** in prototype form, not the full Guix package-lowering/daemon integration path - the earlier concrete upstream/runtime blocker still exists for later integration work: - `./pre-inst-env guix --version` fails with `Wrong type to apply: #` - however, that blocker no longer prevents Phase 4 work because the core build-system and package-definition assumptions have now been validated independently Recent commits: - `e380e88` — `Add FreeBSD Guile verification harness` - `cd721b1` — `Update progress after Guile verification` - `27916cb` — `Diagnose Guile subprocess crash on FreeBSD` - `02f7a7f` — `Validate local Guile fix on FreeBSD` - `4aebea4` — `Add native GNU Hello FreeBSD build harness` - `c944cdb` — `Validate Guix builder phases on FreeBSD` - `0a2e48e` — `Validate GNU which builder phases on FreeBSD` - `245a47d` — `Document gaps to real Guix FreeBSD builds` - `d62e9b0` — `Investigate Guix derivation generation on FreeBSD` - `c0a85ed` — `Build local Guile-GnuTLS on FreeBSD` - `15b9037` — `Build local Guile-Git on FreeBSD` - `47d31e8` — `Build local Guile-JSON on FreeBSD` - `d82195b` — `Advance Guix checkout on FreeBSD` - `9bf3d30` — `Document FreeBSD syscall mapping` - `7621798` — `Prototype FreeBSD jail build isolation` - `d65b2af` — `Prototype FreeBSD build user isolation` - `e404e2e` — `Prototype FreeBSD store management` - `eb0d77c` — `Adapt GNU build phases for FreeBSD` Next recommended step: 1. begin Phase 4.1 by validating whether Shepherd itself now builds and runs as a regular service on FreeBSD with the fixed local Guile path 2. carry forward the separate real-checkout runtime blocker for later integration work: - investigate the `leave-on-EPIPE` failure in `./pre-inst-env guix --version` 3. continue using `/frx/store` rather than `/gnu/store` for future FreeBSD integration experiments when a persistent store root is required ## 2026-04-01 — Phase 4.1 completed: Shepherd built and validated as a regular FreeBSD service manager Completed work: - added a reproducible local Guile Fibers build harness: - `tests/shepherd/build-local-guile-fibers.sh` - added a reproducible local Shepherd build harness: - `tests/shepherd/build-local-shepherd.sh` - added a runnable multi-service Shepherd validation harness for FreeBSD: - `tests/shepherd/run-freebsd-shepherd-service-prototype.sh` - wrote the Phase 4.1 report: - `docs/reports/phase4-freebsd-shepherd-service.md` - ran the service-management prototype successfully and captured metadata under: - `/tmp/freebsd-shepherd-service-metadata.txt` Important findings: - the current FreeBSD path now has a working local Shepherd build based on: - local fixed Guile - locally installed Guile Fibers `1.4.2` - Shepherd `1.0.9` - Shepherd build/install required one concrete FreeBSD-specific toolchain adaptation: - `SED=/usr/local/bin/gsed` because the install phase edits wrapper scripts using GNU `sed -i` syntax that base FreeBSD `sed` does not accept - at runtime, Shepherd reports: - `System lacks support for 'signalfd'; using fallback mechanism.` but the fallback path works correctly for supervision on this host - the prototype successfully validated all requested regular-service capabilities: - start/stop via `herd` - dependency handling - status monitoring - crash/respawn behavior - privilege-aware execution - the concrete service set used for validation included: - an unprivileged heartbeat logger - a loopback HTTP service - a dependent file-monitor service - a crash-once respawn test service - observed metadata confirmed: - `logger_running=yes` - `web_running=yes` - `monitor_running=yes` - `crashy_running=yes` - `logger_uid=65534` (`nobody`) - `http_response=shepherd-freebsd-ok` - `monitor_detected=detected` - `crashy_counter=2` Current assessment: - Phase 4.1 is now satisfied on the current FreeBSD prototype track - Shepherd is no longer just a theoretical later step; it now builds and supervises multiple services correctly on the host when paired with the fixed local Guile stack - the next question is no longer “can Shepherd run on FreeBSD at all?” but “what is the best FreeBSD init-integration strategy for it on this prototype path?” Recent commits: - `e380e88` — `Add FreeBSD Guile verification harness` - `cd721b1` — `Update progress after Guile verification` - `27916cb` — `Diagnose Guile subprocess crash on FreeBSD` - `02f7a7f` — `Validate local Guile fix on FreeBSD` - `4aebea4` — `Add native GNU Hello FreeBSD build harness` - `c944cdb` — `Validate Guix builder phases on FreeBSD` - `0a2e48e` — `Validate GNU which builder phases on FreeBSD` - `245a47d` — `Document gaps to real Guix FreeBSD builds` - `d62e9b0` — `Investigate Guix derivation generation on FreeBSD` - `c0a85ed` — `Build local Guile-GnuTLS on FreeBSD` - `15b9037` — `Build local Guile-Git on FreeBSD` - `47d31e8` — `Build local Guile-JSON on FreeBSD` - `d82195b` — `Advance Guix checkout on FreeBSD` - `9bf3d30` — `Document FreeBSD syscall mapping` - `7621798` — `Prototype FreeBSD jail build isolation` - `d65b2af` — `Prototype FreeBSD build user isolation` - `e404e2e` — `Prototype FreeBSD store management` - `eb0d77c` — `Adapt GNU build phases for FreeBSD` - `d47dc9b` — `Prototype FreeBSD package definitions` Next recommended step: 1. complete Phase 4.2 by prototyping how Shepherd should be launched and stopped through FreeBSD init conventions while validating boot/shutdown dependency ordering for essential services 2. after that, bridge Shepherd to key FreeBSD service concepts such as rc.d management, loopback/network configuration, filesystem setup, and temporary user/group administration 3. continue carrying the separate real-checkout runtime blocker for later integration work: - investigate the `leave-on-EPIPE` failure in `./pre-inst-env guix --version` ## 2026-04-01 — Phase 4.2 completed: FreeBSD rc.d init-integration prototype validated for Shepherd Completed work: - added a runnable FreeBSD init-integration prototype harness: - `tests/shepherd/run-freebsd-shepherd-init-prototype.sh` - wrote the Phase 4.2 report: - `docs/reports/phase4-freebsd-shepherd-init-integration.md` - ran the init-integration prototype successfully and captured metadata under: - `/tmp/freebsd-shepherd-init-metadata.txt` Important findings: - a real temporary FreeBSD `rc.d` script can successfully launch the locally built Shepherd daemon through the standard: - `service onestart` path - the same wrapper can stop it cleanly through: - `service onestop` using `herd ... stop root` under the hood - the prototype automatically started a minimal essential-service graph at daemon launch consisting of: - `filesystems` - `system-log` - `networking` - `login` - observed startup order matched the declared dependency chain exactly: - `start:filesystems` - `start:system-log` - `start:networking` - `start:login` - observed shutdown order matched the expected reverse dependency order exactly: - `stop:login` - `stop:networking` - `stop:system-log` - `stop:filesystems` - the rc.d wrapper reported the Shepherd instance as running while active: - `rc_status=running` - the prototype again observed the expected FreeBSD runtime note: - `System lacks support for 'signalfd'; using fallback mechanism.` and confirmed that it does not prevent correct boot/shutdown ordering behavior Current assessment: - Phase 4.2 is now satisfied on the current prototype track as an init-integration prototype - the key result is that Shepherd can already be launched and stopped through native FreeBSD service-management conventions while preserving dependency-based startup and shutdown semantics - the remaining Phase 4 work is now specifically about bridging Shepherd services to concrete FreeBSD host-management concepts rather than basic daemon launch or service ordering Recent commits: - `e380e88` — `Add FreeBSD Guile verification harness` - `cd721b1` — `Update progress after Guile verification` - `27916cb` — `Diagnose Guile subprocess crash on FreeBSD` - `02f7a7f` — `Validate local Guile fix on FreeBSD` - `4aebea4` — `Add native GNU Hello FreeBSD build harness` - `c944cdb` — `Validate Guix builder phases on FreeBSD` - `0a2e48e` — `Validate GNU which builder phases on FreeBSD` - `245a47d` — `Document gaps to real Guix FreeBSD builds` - `d62e9b0` — `Investigate Guix derivation generation on FreeBSD` - `c0a85ed` — `Build local Guile-GnuTLS on FreeBSD` - `15b9037` — `Build local Guile-Git on FreeBSD` - `47d31e8` — `Build local Guile-JSON on FreeBSD` - `d82195b` — `Advance Guix checkout on FreeBSD` - `9bf3d30` — `Document FreeBSD syscall mapping` - `7621798` — `Prototype FreeBSD jail build isolation` - `d65b2af` — `Prototype FreeBSD build user isolation` - `e404e2e` — `Prototype FreeBSD store management` - `eb0d77c` — `Adapt GNU build phases for FreeBSD` - `d47dc9b` — `Prototype FreeBSD package definitions` - `b36746f` — `Validate Shepherd services on FreeBSD` Next recommended step: 1. complete Phase 4.3 by adding a small FreeBSD Shepherd bridge layer for rc.d-style services, loopback/network configuration, filesystem setup, and temporary user/group administration 2. use that bridge layer in a runnable integration harness that validates both activation and cleanup of those FreeBSD concepts 3. continue carrying the separate real-checkout runtime blocker for later integration work: - investigate the `leave-on-EPIPE` failure in `./pre-inst-env guix --version` ## 2026-04-01 — Phase 4.3 completed: FreeBSD Shepherd bridge layer validated across rc.d, network, filesystem, and account management Completed work: - added a reusable FreeBSD Shepherd bridge module: - `modules/fruix/shepherd/freebsd.scm` - added a runnable integration harness exercising that bridge layer: - `tests/shepherd/run-freebsd-shepherd-bridge-prototype.sh` - wrote the Phase 4.3 report: - `docs/reports/phase4-freebsd-shepherd-bridge.md` - ran the bridge prototype successfully and captured metadata under: - `/tmp/freebsd-shepherd-bridge-metadata.txt` Important findings: - the new module now exports concrete helper constructors for four FreeBSD integration categories: - `freebsd-rc-service` - `freebsd-loopback-alias-service` - `freebsd-tmpfs-service` - `freebsd-user-group-service` - the integration harness used those helpers to manage a real chained host-side service graph under Shepherd covering: - a temporary rc.d script in `/usr/local/etc/rc.d/` - loopback alias configuration on `lo0` - tmpfs mount/unmount with mode validation - temporary user/group creation and removal via `pw` - observed activation metadata confirmed all of those operations succeeded under Shepherd control: - `target_running=yes` - `rc_started=yes` - `alias_present=yes` - `tmpfs_mounted=yes` - `tmpfs_mode=drwxr-x---` - `user_present=yes` - `group_present=yes` - observed cleanup metadata confirmed that `stop root` also reversed all of those host-side effects successfully: - `rc_stopped=yes` - `alias_removed=yes` - `tmpfs_unmounted=yes` - `user_removed=yes` - `group_removed=yes` - the same expected FreeBSD runtime note remained true here as well: - `System lacks support for 'signalfd'; using fallback mechanism.` and again it did not prevent the prototype from working correctly Current assessment: - Phase 4.3 is now satisfied on the current prototype track - Shepherd now has a concrete FreeBSD bridge layer in-repo rather than only ad hoc validation scripts - with service supervision, rc.d integration, and FreeBSD host-concept bridging now all validated, Phase 4 is complete on the current FreeBSD amd64 prototype path ## 2026-04-01 — Phase 4 completed on the current FreeBSD prototype track Phase 4 is now considered complete for the active FreeBSD amd64 prototype path. Why this milestone is satisfied: - **Phase 4.1** success criteria were met on the prototype track: - Shepherd built successfully on FreeBSD with the fixed local Guile stack - regular multi-service supervision worked - dependency handling, status monitoring, privilege-aware execution, and respawn behavior were all validated - **Phase 4.2** success criteria were met in init-integration prototype form: - a real FreeBSD `rc.d` wrapper launched Shepherd successfully - a minimal essential-service graph started automatically in correct dependency order - orderly reverse shutdown through native FreeBSD service entry points was validated - **Phase 4.3** success criteria were met on the prototype track: - a reusable FreeBSD Shepherd bridge layer was added - Shepherd services successfully bridged to rc.d service control, loopback/network configuration, filesystem mounting/permissions, and temporary user/group administration - both activation and cleanup were validated Important scope note: - this completes the **Shepherd porting milestone** on the current prototype track, not a literal replacement of `/sbin/init` on the live host - however, the core Shepherd questions have now been answered positively on FreeBSD: - it builds - it runs - it supervises services - it integrates with FreeBSD service-management conventions - it can express concrete FreeBSD host-management tasks through Shepherd services - the separate real-Guix-checkout runtime blocker still exists for later integration work: - `./pre-inst-env guix --version` fails with `Wrong type to apply: #` but that is now clearly outside the scope of the completed Phase 4 Shepherd milestone Recent commits: - `e380e88` — `Add FreeBSD Guile verification harness` - `cd721b1` — `Update progress after Guile verification` - `27916cb` — `Diagnose Guile subprocess crash on FreeBSD` - `02f7a7f` — `Validate local Guile fix on FreeBSD` - `4aebea4` — `Add native GNU Hello FreeBSD build harness` - `c944cdb` — `Validate Guix builder phases on FreeBSD` - `0a2e48e` — `Validate GNU which builder phases on FreeBSD` - `245a47d` — `Document gaps to real Guix FreeBSD builds` - `d62e9b0` — `Investigate Guix derivation generation on FreeBSD` - `c0a85ed` — `Build local Guile-GnuTLS on FreeBSD` - `15b9037` — `Build local Guile-Git on FreeBSD` - `47d31e8` — `Build local Guile-JSON on FreeBSD` - `d82195b` — `Advance Guix checkout on FreeBSD` - `9bf3d30` — `Document FreeBSD syscall mapping` - `7621798` — `Prototype FreeBSD jail build isolation` - `d65b2af` — `Prototype FreeBSD build user isolation` - `e404e2e` — `Prototype FreeBSD store management` - `eb0d77c` — `Adapt GNU build phases for FreeBSD` - `d47dc9b` — `Prototype FreeBSD package definitions` - `b36746f` — `Validate Shepherd services on FreeBSD` - `83715f0` — `Prototype Shepherd rc.d integration` Next recommended step: 1. return to the remaining real Guix checkout/runtime blocker and investigate the `leave-on-EPIPE` failure in `./pre-inst-env guix --version` 2. begin the next post-Phase-4 integration milestone by connecting the now-validated daemon/build/store/Shepherd prototypes more directly to real Guix checkout behavior on FreeBSD 3. continue using `/frx/store` rather than `/gnu/store` whenever future integration experiments need a persistent store root ## 2026-04-01 — Planning update: Fruix naming policy clarified for post-Phase-4 work Completed work: - added a new post-Phase-4 planning document: - `docs/PLAN_2.md` - updated that plan to clarify the naming policy for the fork going forward Key planning decision: - **Fruix** is now the intended user-facing product identity - the user-facing CLI should become: - `fruix` - `/frx` remains the canonical store/state/config root on the FreeBSD path - however, the plan explicitly avoids a blanket rename of all upstream-derived internal identifiers - in particular: - internal `guix` namespaces may remain temporarily where needed for compatibility and maintenance - `gnu` names are preserved where they refer to real GNU concepts or components such as GNU packages, GNU Shepherd, or `gnu-build-system` - new fork-specific modules and user-facing surfaces should prefer `fruix` naming Current assessment: - the naming direction is now clearer for the next integration batch - Phase 5 and beyond should aim to: - first make the upstream-derived checkout runnable on FreeBSD, - then introduce a deliberate `fruix` command boundary, - rather than destabilizing the codebase with a whole-tree `guix`/`gnu` rename too early ## 2026-04-01 — Phase 5.1 completed: checkout runtime unblocked and first `fruix` frontend boundary established Completed work: - added a reusable phase-5 checkout setup helper: - `tests/guix/setup-phase5-checkout.sh` - added a checkout runtime patch queue for the upstream-derived source tree: - `tests/guix/patches/phase5-checkout-runtime.patch` - added a FreeBSD daemon/build patch queue needed for later phase-5 work: - `tests/guix/patches/phase5-guix-daemon-freebsd.patch` - added a runtime validation harness: - `tests/guix/run-phase5-checkout-runtime.sh` - wrote the Phase 5.1 report: - `docs/reports/phase5-checkout-runtime-freebsd.md` - ran the runtime harness successfully and captured metadata under: - `/tmp/phase5-runtime-metadata.txt` Important findings: - the earlier checkout blocker - `./pre-inst-env guix --version` - `Wrong type to apply: #` is now explained by top-level definition ordering in `guix/ui.scm`: - `show-version-and-exit` called `leave-on-EPIPE` before the syntax transformer was defined later in the file - on this FreeBSD path, that became a runtime application of a syntax-transformer object instead of a macro expansion site - the phase-5 runtime patch fixes this by: - making `(guix ui)` explicitly non-declarative - rewriting `show-version-and-exit` to use direct `catch 'system-error` handling - parameterizing `program-name` in `guix-main` - deriving the top-level version banner name from `program-name` - making `(guix scripts repl)` explicitly non-declarative as well - the checkout now successfully runs the following commands on FreeBSD: - `./pre-inst-env guix --version` - `./pre-inst-env guix repl --help` - `./pre-inst-env guix build --help` - the first user-facing Fruix command boundary is now implemented in the checkout setup via: - `scripts/fruix` as a front-end alias next to `scripts/guix` - observed runtime metadata confirmed: - `first_guix_version_line=guix (GNU Guix) ...` - `first_fruix_version_line=fruix (GNU Guix) ...` - this matches the agreed naming policy: - Fruix at the user-facing boundary - stable upstream-derived internal `guix`/`gnu` names unless there is a concrete reason to rename them Current assessment: - Phase 5.1 is now satisfied on the current FreeBSD prototype track - the key boundary has shifted from “the checkout still crashes immediately” to “the checkout runs, and can now be used as the basis for real derivation/store experiments” - the next step is to prove that a real derivation can be emitted against `/frx/store` from the now-runnable checkout ## 2026-04-01 — Phase 5.2 completed: real derivation generation validated against `/frx/store` Completed work: - added a runnable derivation-generation harness: - `tests/guix/run-phase5-derivation-generation.sh` - wrote the Phase 5.2 report: - `docs/reports/phase5-derivation-generation-freebsd.md` - ran the derivation-generation harness successfully and captured metadata under: - `/tmp/phase5-derivation-metadata.txt` Important findings: - the now-runnable checkout can successfully use a real daemon/store connection on FreeBSD to lower a package through: - `package->bag` - `bag->derivation` - the emitted derivation is a real `/frx/store` derivation path rather than an ad hoc placeholder or shell metadata artifact - the validation used a deliberately minimal custom package with a custom low-level build system so that this subphase isolates the real lowering/store boundary without being dominated by still-unresolved upstream bootstrap assumptions for full native FreeBSD package graphs - observed metadata confirmed: - `bag_name=phase5-freebsd-lowering-0` - `bag_host_inputs=("source")` - `drv_path=/frx/store/...-phase5-freebsd-lowering-0.drv` - `out_path=/frx/store/...-phase5-freebsd-lowering-0` - this means the key architectural step is now real and no longer hypothetical: - a package object in the checkout can be lowered to a real derivation targeting `/frx/store` on FreeBSD Current assessment: - Phase 5.2 is now satisfied on the current FreeBSD prototype track - the next step is no longer “can we emit a derivation at all?” but “can the same daemon/store path accept and execute a derivation-backed build request successfully?” ## 2026-04-01 — Phase 5.3 completed: minimal daemon/store RPC integration validated on FreeBSD Completed work: - added a runnable daemon/store RPC validation harness: - `tests/guix/run-phase5-daemon-rpc.sh` - wrote the Phase 5.3 report: - `docs/reports/phase5-daemon-rpc-freebsd.md` - ran the daemon/store RPC harness successfully and captured metadata under: - `/tmp/phase5-daemon-rpc-metadata.txt` Important findings: - the patched checkout can now contact a real FreeBSD-aware daemon over a Unix socket and submit a derivation-backed build request successfully - the resulting build path is a real `/frx/store` output rather than a simulated prototype artifact - the successful metadata path now includes the full minimal chain needed for later system work: - checkout command path - daemon RPC - derivation submission - build execution - store output materialization - observed metadata confirmed: - `drv_path=/frx/store/...-phase5-freebsd-daemon-build-0.drv` - `out_path=/frx/store/...-phase5-freebsd-daemon-build-0` - `payload=phase5-daemon-build-source` - `source_path=/frx/store/...-phase5-source.txt` - this step was exercised through the Fruix-facing checkout boundary: - `./pre-inst-env fruix repl -- ...` which means the user-facing transition is now connected to actual daemon/store activity, not just to help text or version banners Current assessment: - Phase 5.3 is now satisfied on the current FreeBSD prototype track - the project now has a real but narrow end-to-end host-side execution path on FreeBSD: - runnable checkout - Fruix front-end boundary - real derivation emission - daemon/store RPC - successful derivation-backed build into `/frx/store` ## 2026-04-01 — Phase 5 completed on the current FreeBSD prototype track Phase 5 is now considered complete for the active FreeBSD amd64 prototype path. Why this milestone is satisfied: - **Phase 5.1** success criteria were met on the prototype track: - the checkout runtime blocker around `leave-on-EPIPE` was root-caused and fixed in the patch queue - the uninstalled checkout command path now runs on FreeBSD - a first user-facing `fruix` command boundary was established - **Phase 5.2** success criteria were met on the prototype track: - a real package object was lowered through `package->bag` and `bag->derivation` - a real derivation was emitted targeting `/frx/store` - **Phase 5.3** success criteria were met on the prototype track: - a real checkout command path contacted a FreeBSD-aware daemon/store path - that path accepted and executed a derivation-backed build request - the resulting output was materialized successfully in `/frx/store` Important scope note: - this completes the **real checkout and host runtime unblocking milestone** on the current prototype track, not full upstream-package-graph support for arbitrary native FreeBSD package builds yet - the successful derivation/build path currently uses a deliberately minimal custom package/build-system path to isolate real daemon/store viability from still-unresolved upstream bootstrap and package-graph assumptions for native FreeBSD - nevertheless, the core Phase 5 question has now been answered positively: - the checkout runs - real derivations can be emitted - the daemon can be built far enough to serve store RPC - and derivation-backed builds can succeed into `/frx/store` Next recommended step: 1. begin Phase 6.1 by moving from the minimal custom derivation-backed package path to at least one real FreeBSD store-backed package build driven by Fruix/Guix mechanisms 2. then integrate the already validated jail/build-user model more directly into the live daemon build path 3. continue preserving the selective Fruix naming policy: - Fruix at the product boundary - `/frx` as the canonical store root - stable upstream-derived internal names unless there is strong architectural value in renaming them ## 2026-04-01 — Phase 6.1 completed: real package build validated into `/frx/store` Completed work: - added a runnable real-package harness: - `tests/guix/run-phase6-real-package-build.sh` - wrote the Phase 6.1 report: - `docs/reports/phase6-real-package-build-freebsd.md` - ran the real-package harness successfully and captured metadata under: - `/tmp/phase6-real-package-metadata.txt` Important findings: - the checkout can now build a real package definition derived from Guix's `hello` package through: - `./pre-inst-env fruix build -f ...` - the FreeBSD-aware daemon - `/frx/store` - this moves the project beyond the deliberately minimal Phase 5 custom derivation path and into a real package-definition flow - the current successful path still uses a prefetched local GNU Hello tarball as the package source because the built-in downloader path remains a separate unresolved FreeBSD/root-daemon issue - observed metadata confirmed: - `drv_path=/frx/store/...-hello-2.12.3.drv` - `out_path=/frx/store/...-hello-2.12.3` - `source_store_path=/frx/store/...-hello-2.12.3.tar.gz` - `runtime_output=Hello, world!` - a daemon-side references query confirmed that the built output preserved the declared source store item as a direct reference Current assessment: - Phase 6.1 is now satisfied on the current FreeBSD prototype track - the next step is to move the already validated jail/build-user model into this live package-build path rather than keeping it prototype-only ## 2026-04-01 — Phase 6.2 completed: jail/build-user isolation integrated into the real package path Completed work: - added a reusable UID/GID drop helper source: - `tests/daemon/freebsd-drop-exec.c` - added a runnable jail-integrated package harness: - `tests/guix/run-phase6-jail-package-build.sh` - wrote the Phase 6.2 report: - `docs/reports/phase6-jail-build-integration-freebsd.md` - ran the jail-integrated harness successfully and captured metadata under: - `/tmp/phase6-jail-package-metadata.txt` Important findings: - a real package build derived from Guix's `hello` definition now runs through the live daemon path inside a FreeBSD jail rather than only through the earlier prototype scripts - the actual build work inside the jail runs as dropped credentials: - UID `35001` - GID `35001` - the integrated build path required one additional FreeBSD-specific adjustment beyond the earlier prototype: - the daemon-side host `TMPDIR` path was not automatically valid inside the jail, so the jailed build environment must reset `TMPDIR=/tmp` - observed metadata confirmed: - `drv_path=/frx/store/...-hello-2.12.3.drv` - `out_path=/frx/store/...-hello-2.12.3` - `runtime_output=Hello, world!` - `build_uid=35001` - `build_gid=35001` - `jail_hostname=fruix-phase6-hello-...` - `build_mode=freebsd-jail` - `source_store_path=/frx/store/...-hello-2.12.3.tar.gz` - the GNU Hello test suite also passed inside the jail-integrated build path Current assessment: - Phase 6.2 is now satisfied on the current FreeBSD prototype track - the next step is to validate a minimal user-facing profile installation flow on top of these real store outputs ## 2026-04-01 — Phase 6.3 completed: minimal profile installation validated on real store outputs Completed work: - added a runnable real-store profile harness: - `tests/packages/run-phase6-real-store-profile-prototype.sh` - wrote the Phase 6.3 report: - `docs/reports/phase6-real-store-profile-freebsd.md` - updated the Phase 6 package-build harnesses so they can recover derivation paths even when the requested outputs are already present in `/frx/store` - ran the real-store profile harness successfully and captured metadata under: - `/tmp/phase6-real-store-profile-metadata.txt` Important findings: - the current FreeBSD track now has a minimal user-facing profile installation flow built on top of real Phase 6 store outputs rather than the earlier Phase 3 package/profile prototype inputs - the validated transaction semantics are intentionally small but real: - generation 1 is created from the Phase 6.1 host-built store item - generation 2 is created from the Phase 6.2 jail-built store item - the `profile` symlink switches to generation 2 - both generations remain addressable - observed metadata confirmed: - `profile_target=profile-2-link` - `generation1_store_path=/frx/store/...-hello-2.12.3` - `generation2_store_path=/frx/store/...-hello-2.12.3` - `current_store_path=/frx/store/...-hello-2.12.3` - `profile_hello_output=Hello, world!` - `clean_env_hello_output=Hello, world!` - the upstream-derived profile layer is still not fully usable on this FreeBSD track because the current `guix profiles` / `fruix package` path still reaches the unresolved bootstrap-platform blocker: - `dynamic linker name not known for this system "x86_64-freebsd15.0"` - despite that blocker, the minimal Fruix-owned profile path is now validated on top of real daemon-built store items Current assessment: - Phase 6.3 is now satisfied on the current FreeBSD prototype track - Phase 6 as a whole is now complete on the active FreeBSD amd64 prototype path ## 2026-04-01 — Phase 6 completed on the current FreeBSD prototype track Phase 6 is now considered complete for the active FreeBSD amd64 prototype path. Why this milestone is satisfied: - **Phase 6.1** success criteria were met on the prototype track: - a real package definition derived from Guix's `hello` package now builds through `fruix build` - the output lands in `/frx/store` - the package runs from the store and preserves a declared source reference - **Phase 6.2** success criteria were met on the prototype track: - a real package build now executes inside a FreeBSD jail - the build work runs under dropped numeric build credentials - the jailed build succeeds into `/frx/store` - **Phase 6.3** success criteria were met on the prototype track: - real Phase 6 store outputs can be installed into a minimal profile environment - generation switching works in a concrete form - package execution through the profile succeeds for the current user Important scope note: - this completes the **real FreeBSD-backed store-build milestone** on the current prototype track, not full upstream-package-graph support or full upstream profile-layer parity yet - the current package path still relies on a prefetched local source tarball for GNU Hello because the built-in downloader/root-daemon path remains a separate FreeBSD issue - the current profile-installation path is a Fruix-owned minimal layer over real store outputs because the upstream-derived profile code still hits the unresolved FreeBSD bootstrap-platform mapping blocker - nevertheless, the core Phase 6 question has now been answered positively: - real package definitions can be built into `/frx/store` - those builds can run under integrated jail/build-user isolation - and the resulting store items can be exposed through a minimal user-facing profile flow Next recommended step: 1. begin Phase 7.1 by defining a minimal Fruix operating-system model for FreeBSD 2. carry forward the selective Fruix naming policy: - Fruix at the product boundary - `/frx` as the canonical store root - stable upstream-derived internal names unless there is strong architectural value in renaming them 3. keep the two remaining Phase 6 follow-up blockers visible but scoped: - built-in downloader/root-daemon integration for real package origins - upstream-derived profile/bootstrap-platform support for `x86_64-freebsd15.0` ## 2026-04-01 — Phase 7.1 completed: minimal Fruix operating-system model defined for FreeBSD Completed work: - added the first Fruix-owned FreeBSD system module: - `modules/fruix/system/freebsd.scm` - added the Phase 7.1 operating-system example and validation harnesses: - `tests/system/phase7-minimal-operating-system.scm` - `tests/system/validate-phase7-operating-system.scm` - `tests/system/run-phase7-operating-system-model.sh` - extended the FreeBSD package model with additional system-oriented prototype packages: - `freebsd-bootloader` - `freebsd-rc-scripts` - `freebsd-runtime` - `%freebsd-system-packages` - wrote the Phase 7.1 report: - `docs/reports/phase7-operating-system-model-freebsd.md` - ran the operating-system model harness successfully and captured metadata under: - `/tmp/phase7-os-model-metadata.txt` Important findings: - the FreeBSD track now has a concrete declarative operating-system object rather than only package/profile and service prototypes - the model currently covers: - host identity - kernel and bootloader assets - essential base packages - users/groups - file systems - generated `/etc` payloads - activation payload generation - generated Shepherd configuration - the selected first init strategy is now explicit in the model: - `freebsd-init+rc.d-shepherd` - observed metadata confirmed: - `host_name=fruix-freebsd` - `kernel_package=freebsd-kernel` - `bootloader_package=freebsd-bootloader` - `base_packages=freebsd-runtime,freebsd-userland,freebsd-libc,freebsd-rc-scripts,freebsd-sh,freebsd-bash` - `users=root,operator` - `groups=wheel,operator` - `generated_files=boot/loader.conf,etc/rc.conf,etc/fstab,etc/hosts,etc/passwd,etc/group,etc/shells,etc/motd,activate,shepherd/init.scm` - `init_mode=freebsd-init+rc.d-shepherd` Current assessment: - Phase 7.1 is now satisfied on the current FreeBSD prototype track - the next step is to materialize this operating-system description into a reproducible system closure under `/frx/store` ## 2026-04-01 — Phase 7.2 completed: minimal system closure generated under `/frx/store` Completed work: - added the Phase 7.2 closure materialization harnesses: - `tests/system/materialize-phase7-system-closure.scm` - `tests/system/run-phase7-system-closure.sh` - refined the minimal operating-system example so the generated system profile also contains `/bin/sh` - wrote the Phase 7.2 report: - `docs/reports/phase7-system-closure-freebsd.md` - ran the system-closure harness successfully and captured metadata under: - `/tmp/phase7-system-closure-metadata.txt` Important findings: - the declarative FreeBSD Fruix operating-system object now materializes into a real system closure under `/frx/store` - that closure contains: - boot assets - a merged system profile - generated `/etc` files - a generated activation script - a generated Shepherd configuration - a generated `rc.d` launcher for Shepherd - the closure now embeds the concrete first init integration choice for the FreeBSD track: - `freebsd-init+rc.d-shepherd` - rerunning the same materialization produced the same closure path, which is the current prototype proof of reproducible closure generation for this phase - observed metadata confirmed: - `closure_path=/frx/store/...-fruix-system-fruix-freebsd` - `closure_rebuild_path=/frx/store/...-fruix-system-fruix-freebsd` - `kernel_store=/frx/store/...-freebsd-kernel-15.0-STABLE` - `bootloader_store=/frx/store/...-freebsd-bootloader-15.0-STABLE` - `guile_store=/frx/store/...-fruix-guile-runtime-3.0` - `guile_extra_store=/frx/store/...-fruix-guile-extra-3.0` - `shepherd_store=/frx/store/...-fruix-shepherd-runtime-1.0.9` - `profile_bin_sh=/frx/store/...-fruix-system-fruix-freebsd/profile/bin/sh` - `profile_sbin_init=/frx/store/...-fruix-system-fruix-freebsd/profile/sbin/init` - `profile_rc=/frx/store/...-fruix-system-fruix-freebsd/profile/etc/rc` Current assessment: - Phase 7.2 is now satisfied on the current FreeBSD prototype track - the next step is to materialize and statically validate an installable root filesystem tree from this system closure ## 2026-04-01 — Phase 7.3 completed: installable rootfs tree validated from the system closure Completed work: - added the Phase 7.3 rootfs materialization harnesses: - `tests/system/materialize-phase7-rootfs.scm` - `tests/system/run-phase7-rootfs.sh` - wrote the Phase 7.3 report: - `docs/reports/phase7-rootfs-freebsd.md` - ran the rootfs harness successfully and captured metadata under: - `/tmp/phase7-rootfs-metadata.txt` Important findings: - the declarative Fruix FreeBSD system can now be materialized as a root filesystem tree rather than only as a store closure directory - the rootfs uses a Guix-like anchor: - `/run/current-system` so that boot assets, generated configuration, and system-profile content remain tied to the declarative system closure - static validation confirmed: - boot asset linkage - generated `/etc` linkage - activation payload presence - Shepherd `rc.d` launch integration - declared filesystem entries - declared user/group provisioning in the activation path - deterministic ready-state wiring through `/var/lib/fruix/ready` - observed metadata confirmed: - `rootfs=/tmp/.../rootfs` - `closure_path=/frx/store/...-fruix-system-fruix-freebsd` - `run_current_system_target=/frx/store/...-fruix-system-fruix-freebsd` - `activate_target=/run/current-system/activate` - `bin_target=/run/current-system/profile/bin` - `sbin_target=/run/current-system/profile/sbin` - `boot_kernel_target=/run/current-system/boot/kernel` - `boot_loader_target=/run/current-system/boot/loader` - `boot_loader_efi_target=/run/current-system/boot/loader.efi` - `rc_conf_target=/run/current-system/etc/rc.conf` - `rc_script_target=/run/current-system/usr/local/etc/rc.d/fruix-shepherd` - `ready_marker=/var/lib/fruix/ready` - `validation_mode=static-rootfs-check` Current assessment: - Phase 7.3 is now satisfied on the current FreeBSD prototype track - Phase 7 as a whole is now complete on the active FreeBSD amd64 prototype path ## 2026-04-01 — Phase 7 completed on the current FreeBSD prototype track Phase 7 is now considered complete for the active FreeBSD amd64 prototype path. Why this milestone is satisfied: - **Phase 7.1** success criteria were met on the prototype track: - a minimal Fruix operating-system object now exists for FreeBSD - it evaluates into a coherent system-closure specification - **Phase 7.2** success criteria were met on the prototype track: - that system model now materializes into a reproducible closure under `/frx/store` - the closure contains boot assets, generated `/etc` files, activation payloads, and Shepherd launch integration - **Phase 7.3** success criteria were met on the prototype track: - the closure now materializes into a concrete rootfs tree - the resulting rootfs passes static validation for later image-construction work Important scope note: - this completes the **declarative system-composition milestone** for the current prototype track, not a fully booted Fruix guest yet - the current output is a validated closure plus rootfs tree; Phase 8 still needs to turn that into a reproducible bhyve-friendly disk image - the chosen first system-init strategy remains: - FreeBSD init + `rc.d` launching Shepherd rather than Shepherd-as-PID-1 - the current system model remains Fruix-owned and FreeBSD-oriented rather than attempting full upstream Guix System integration prematurely Next recommended step: 1. begin Phase 8.1 by creating a reproducible disk-image build path from the generated Fruix rootfs tree 2. keep the current init decision explicit for the first boot target: - FreeBSD init + `rc.d` + Shepherd 3. continue preserving the selective Fruix naming policy: - Fruix at the product boundary - `/frx` as the canonical store root - stable upstream-derived internal names unless there is strong architectural value in renaming them ## 2026-04-01 — Phase 8.1 completed: reproducible bhyve-compatible raw disk image generated Completed work: - added the first Phase 8 image-generation harness: - `tests/system/run-phase8-bhyve-image.sh` - wrote the Phase 8.1 report: - `docs/reports/phase8-bhyve-image-freebsd.md` - ran the image-generation harness successfully and captured metadata under: - `/tmp/phase8-bhyve-image-metadata.txt` Important findings: - the current Fruix FreeBSD track now has a reproducible raw disk-image build path using: - GPT - UEFI boot - a FAT EFI system partition - a UFS root partition - serial-console-friendly loader settings - the earlier Phase 7 rootfs tree was not sufficient by itself for an installable image because it still referenced `/frx/store` content that only existed on the host; the image builder therefore had to stage the system closure and its recursively declared store references inside the image rootfs under `/frx/store` - rebuilding the same image a second time with fixed timestamps and explicit filesystem parameters produced the same SHA256, which is the current prototype proof of reproducible image generation on this host - observed metadata confirmed: - `raw_sha256=08605d738021cb6fb5b87c270e1eafde57e1acb5159d3a2257aad4c560e2efc5` - `image_size_bytes=335578624` - `esp_fstype=msdosfs` - `root_fstype=ufs` - `run_current_system_target=/frx/store/...-fruix-system-fruix-freebsd` - `boot_loader_target=/run/current-system/boot/loader` - `boot_loader_conf_target=/run/current-system/boot/loader.conf` - `rc_conf_target=/run/current-system/etc/rc.conf` - `rc_script_target=/run/current-system/usr/local/etc/rc.d/fruix-shepherd` - `store_item_count=13` - `boot_mode=uefi` - `image_format=raw` - `partition_scheme=gpt` - `serial_console=comconsole` Current assessment: - Phase 8.1 is now satisfied on the current FreeBSD prototype track - the next step is to integrate this image generation path into the declarative Fruix system-composition layer so that a single operating-system description can drive image generation end-to-end ## 2026-04-01 — Phase 8.2 completed: image generation integrated into the declarative system layer Completed work: - extended the FreeBSD system module with integrated image-generation operations: - `operating-system-image-spec` - `materialize-bhyve-image` - added the Phase 8.2 integration harnesses: - `tests/system/materialize-phase8-system-image.scm` - `tests/system/run-phase8-system-image.sh` - wrote the Phase 8.2 report: - `docs/reports/phase8-system-image-freebsd.md` - ran the integrated system-image harness successfully and captured metadata under: - `/tmp/phase8-system-image-metadata.txt` Important findings: - image generation is now a direct output of the Fruix FreeBSD system-definition layer rather than an external shell-only follow-up to Phase 7 - the integrated path now stores the resulting image artifact itself under `/frx/store`, preserving the store-centered Fruix composition story even at the VM-image layer - rerunning `materialize-bhyve-image` for the same operating-system description produced the same image store path, which is the current prototype proof that one declarative system object can drive image generation end-to-end - observed metadata confirmed: - `image_store_path=/frx/store/...-fruix-bhyve-image-fruix-freebsd` - `disk_image=/frx/store/...-fruix-bhyve-image-fruix-freebsd/disk.img` - `closure_path=/frx/store/...-fruix-system-fruix-freebsd` - `raw_sha256=ac57d4c694ea3cf6b1bd24be48982090a6cfcfa301d052c1f903636a46f2d56e` - `image_size_bytes=335578624` - `store_item_count=13` - `esp_fstype=msdosfs` - `root_fstype=ufs` - `run_current_system_target=/frx/store/...-fruix-system-fruix-freebsd` - `boot_loader_target=/run/current-system/boot/loader` - `rc_conf_target=/run/current-system/etc/rc.conf` - `rc_script_target=/run/current-system/usr/local/etc/rc.d/fruix-shepherd` - `image_generation_mode=declarative-system-layer` Current assessment: - Phase 8.2 is now satisfied on the current FreeBSD prototype track - Phase 8 as a whole is now complete on the active FreeBSD amd64 prototype path ## 2026-04-01 — Phase 8 completed on the current FreeBSD prototype track Phase 8 is now considered complete for the active FreeBSD amd64 prototype path. Why this milestone is satisfied: - **Phase 8.1** success criteria were met on the prototype track: - a reproducible raw GPT+UEFI+UFS image can now be generated from the Fruix system outputs - that image passes static boot-structure sanity checks - **Phase 8.2** success criteria were met on the prototype track: - the image builder is now integrated with the declarative Fruix system-definition layer - a single operating-system description now drives image generation end-to-end - the integrated output is itself a store-backed Fruix image artifact under `/frx/store` Important scope note: - this completes the **image-construction milestone** for the current prototype track, not the first successful bhyve boot yet - the generated image is now ready for the next phase’s VM-launch and serial-console validation work - the current first-boot strategy remains explicit and unchanged: - FreeBSD init + `rc.d` + Shepherd - the image path still reflects the current prototype system/runtime limitations, including the fact that deeper runtime closure completeness for locally copied Guile/Shepherd dependencies will be exercised more fully in Phase 9 boot validation Next recommended step: 1. begin Phase 9.1 by creating a bhyve launcher and serial-console validation harness for the generated image 2. keep the current deterministic ready-state target visible: - Shepherd startup leading to the generated `/var/lib/fruix/ready` marker path 3. continue preserving the selective Fruix naming policy: - Fruix at the product boundary - `/frx` as the canonical store root - stable upstream-derived internal names unless there is strong architectural value in renaming them ## 2026-04-02 — Phase 9 checkpoint: XCP-ng guest reached DHCP and SSH Completed work: - added a dedicated Phase 9 XCP-ng operating-system template: - `tests/system/phase9-minimal-operating-system.scm.in` - added an XCP-ng boot/import/validation harness: - `tests/system/run-phase9-xcpng-boot.sh` - extended the staged FreeBSD runtime and system-generation layers so the guest can complete enough of real boot for network access: - `modules/fruix/packages/freebsd.scm` - `modules/fruix/system/freebsd.scm` - updated the integrated image-generation path for Phase 9 use cases: - `tests/system/materialize-phase8-system-image.scm` - `tests/system/run-phase8-system-image.sh` - wrote the checkpoint report: - `docs/reports/phase9-xcpng-ssh-boot-freebsd.md` Important findings: - a decisive local QEMU/TCG serial-boot pass exposed the first real early-boot blocker: - the generated `fstab` was wrong for pseudo-filesystems, so `rc` tried to fsck `devfs` and aborted boot - after fixing `fstab`, later serial logs exposed additional FreeBSD base runtime gaps that only appear during real boot, including missing commands, runtime directories, and base config files used by `rc`, DHCP, logging, and service startup - the staged image now includes the minimum currently known set of FreeBSD runtime pieces needed to: - run `rc` - obtain DHCP - generate SSH host keys - start `sshd` - public-key SSH login initially still failed because the minimal guest did not stage a complete PAM runtime/config path; for the current Phase 9 prototype track, the generated `sshd_config` now uses: - `UsePAM no` - the current XCP-ng validation path succeeded against the operator-approved VM and existing VDI only: - VM `90490f2e-e8fc-4b7a-388e-5c26f0157289` - VDI `0f1f90d3-48ca-4fa2-91d8-fc6339b95743` - the successful XCP-ng boot obtained: - guest IP `192.168.213.62` - successful SSH validation on the real guest confirmed: - `hostname=fruix-freebsd` - `sshd` is reachable with the injected root key - networking is configured on the Xen NIC Current assessment: - this checkpoint establishes the first real network-reachable Fruix boot on the active FreeBSD/XCP-ng track - the generated image now boots far enough for DHCP and SSH, which closes the earlier uncertainty about whether the Phase 8 image could become a remotely usable guest at all - Phase 9 is still not complete because the Fruix-specific readiness path remains blocked: - `fruix-shepherd` does not start - `/var/lib/fruix/ready` is still missing - Guile still crashes in the guest with `signal 11` - therefore the current state is: - kernel boot: yes - root mount: yes - DHCP: yes - SSH: yes - Shepherd/ready marker: not yet Next recommended step: 1. continue the in-guest Guile crash investigation so `fruix-shepherd` can start on the booted guest 2. once Shepherd is stable, rerun `tests/system/run-phase9-xcpng-boot.sh` to validate the full ready-marker path end-to-end 3. then close Phase 9 with updated report/progress entries for: - deterministic boot readiness - in-guest Shepherd validation - minimal operator usability ## 2026-04-02 — Phase 9 completed on the active XCP-ng FreeBSD track Completed work: - resolved the in-guest Guile/Shepherd blocker that remained after the earlier DHCP+SSH checkpoint - wrote the completion report: - `docs/reports/phase9-xcpng-ready-boot-freebsd.md` - extended the staged runtime again in: - `modules/fruix/packages/freebsd.scm` - added `/usr/sbin/daemon` - added `/usr/share/locale/C.UTF-8/LC_CTYPE` - completed the guest runtime integration in: - `modules/fruix/system/freebsd.scm` - activation now recreates compatibility symlinks for the currently locally built Guile / guile-extra / Shepherd prefixes, but points them at the real `/frx/store` items in the guest - the rootfs now exposes `/usr/share/locale` - the generated Shepherd config no longer relies on missing `mkdir-p` or unsupported `call-with-output-file #:append` behavior - the Shepherd rc script now exports `LANG=C.UTF-8` / `LC_ALL=C.UTF-8` - the Shepherd rc script now exports explicit Guile system/site path variables - Shepherd is now started through FreeBSD `daemon(8)` so it remains alive after rc/session teardown - corrected the XCP-ng harness in: - `tests/system/run-phase9-xcpng-boot.sh` - it now uses a distinct SSH private key file for login instead of incorrectly trying to authenticate with the public key file Important findings: - the original guest Guile failure had multiple layers: - missing UTF-8 locale data in the image - baked-in temporary install-prefix references inside the copied Guile / guile-extra / Shepherd artifacts - and Shepherd process lifetime issues caused by a fragile shell-background startup path - reproducing the problem in a host-side chroot into the generated image root partition made the final debugging loop much tighter than repeated full VM imports alone - after locale staging and compatibility-prefix recreation, Guile and Shepherd became runnable in the guest, but Shepherd still exited too early on the real boot path until it was launched via `daemon(8)` - after those fixes, the full ready-marker path became reliable enough for end-to-end XCP-ng validation Final validation: - `tests/system/run-phase9-xcpng-boot.sh` now passes end-to-end against: - VM `90490f2e-e8fc-4b7a-388e-5c26f0157289` - VDI `0f1f90d3-48ca-4fa2-91d8-fc6339b95743` - passing run workdir: - `/tmp/phase9-xcpng-pass-1775113189` - passing real-guest metadata confirmed: - `ready_marker=ready` - `shepherd_status=running` - `sshd_status=running` - `run_current_system_target=/frx/store/0fe459ea22156510e64cea794b7a001151b59625bd5f12a488d6851e1c6d2198-fruix-system-fruix-freebsd` - `operator_home_listing=/home/operator` - `logger_log=fruix-shepherd-started` Current assessment: - Phase 9 is now complete for the active FreeBSD prototype track, using the XCP-ng replacement path adopted for this environment - the generated Fruix image now reaches all currently required first-boot milestones on the real VM: - kernel boot: yes - root mount: yes - DHCP: yes - SSH: yes - Shepherd: yes - ready marker: yes - minimal operator usability: yes - this establishes the first real Fruix-on-FreeBSD VM that: - boots from the declaratively generated image, - reaches the generated ready state, - keeps Shepherd running, - and remains inspectable over SSH as a minimally usable system Next recommended step: 1. begin the next post-Phase-9 cleanup/native-integration pass from `docs/PLAN_2.md` Optional Phase 10 2. prioritize replacing the current compatibility shims for locally built Guile / Shepherd prefixes with a more native store-path-aware Fruix runtime arrangement 3. clean up remaining non-fatal boot noise observed during Phase 9, such as: - login-class warnings around `daemon` - the `gpart: Unknown command: show` rc noise - residual syslog/cron/runtime polish issues where they still matter ## 2026-04-02 — Phase 10.1: added a real `fruix system` command Completed work: - started Optional Phase 10 with the first user-facing Fruix system-management command surface - wrote the subphase report: - `docs/reports/phase10-fruix-system-command-freebsd.md` - added a real CLI wrapper: - `bin/fruix` - added the corresponding Guile entry point: - `scripts/fruix.scm` - added a dedicated validation harness: - `tests/system/run-phase10-fruix-system-command.sh` What the new command does: - exposes declarative FreeBSD system artifact generation through a Fruix CLI instead of only phase-specific harness scripts - currently supports: - `fruix system build OS-FILE` - `fruix system image OS-FILE` - `fruix system rootfs OS-FILE ROOTFS-DIR` - currently supports options: - `--system NAME` - `--store DIR` - `--disk-capacity SIZE` - `--rootfs DIR` - `--help` - loads an operating-system object from a Scheme file, validates it, and dispatches to: - `materialize-operating-system` - `materialize-rootfs` - `materialize-bhyve-image` - emits machine-readable `key=value` metadata for the produced artifacts Important findings: - the project already had the core declarative system machinery by the end of Phase 9; the missing piece here was a direct Fruix operator interface to that machinery - a small dedicated wrapper in this repo is currently the most practical way to expose that functionality without waiting for deeper upstream command-framework integration - keeping the command aligned with the already validated local FreeBSD Guile / Fibers / Shepherd toolchain avoids introducing a second, divergent runtime path Validation: - `tests/system/run-phase10-fruix-system-command.sh` passes - passing run workdir: - `/tmp/phase10-fruix-cmd-1775117490` - the test validated that: - `fruix system build` materializes a closure under `/frx/store/*-fruix-system-fruix-freebsd` - the produced closure contains the activation path - `fruix system image` materializes a disk image under `/frx/store/*-fruix-bhyve-image-fruix-freebsd/disk.img` - the command returns expected metadata fields for both actions Current assessment: - Fruix now has a real user-facing system command in this repo, which is a concrete step from “prototype scripts” toward “OS tooling” - this does not replace all earlier harnesses yet, but it establishes `fruix system` as the new canonical interface for system closure/rootfs/image materialization work - system/image creation still typically requires `sudo` because the command writes into `/frx/store` and uses privileged image-building operations Next recommended step: 1. continue Phase 10 by making more of the existing system workflows call `bin/fruix` directly instead of bespoke phase scripts 2. reduce the current runtime compatibility shims for locally built Guile / Shepherd prefixes and move toward a more native store-path-aware Fruix runtime arrangement 3. consider adding the next operator-facing subcommand on top of the now-working image path, such as a `vm`/deploy-oriented flow for the active XCP-ng workflow ## 2026-04-02 — Phase 10 completed: canonical system workflows now use `fruix system` Completed work: - completed the current Optional Phase 10 track by making the existing FreeBSD system workflows use the real Fruix CLI as their canonical frontend - wrote the completion report: - `docs/reports/phase10-canonical-system-workflows-freebsd.md` - extended the `fruix system build` metadata in: - `scripts/fruix.scm` - added: - `ready_marker` - `base_package_store_count` - `base_package_stores` - refactored the main static system harnesses to call `bin/fruix` instead of invoking internal Scheme materializer runners directly: - `tests/system/run-phase7-system-closure.sh` - `tests/system/run-phase7-rootfs.sh` - `tests/system/run-phase8-system-image.sh` What changed in practice: - the closure path is now validated through: - `fruix system build` - the rootfs path is now validated through: - `fruix system rootfs` - the image path is now validated through: - `fruix system image` - the real XCP-ng boot path now benefits from this automatically because: - `tests/system/run-phase9-xcpng-boot.sh` still calls the Phase 8 harness, and that harness now builds its image through `bin/fruix` Validation: - `tests/system/run-phase7-system-closure.sh` passes - workdir: `/tmp/phase10-canon-closure2-1775119728` - `tests/system/run-phase7-rootfs.sh` passes - workdir: `/tmp/phase10-canon-rootfs3-1775120391` - `tests/system/run-phase8-system-image.sh` passes - workdir: `/tmp/phase10-canon-image-1775120548` - full real XCP-ng regression still passes after the frontend refactor: - `tests/system/run-phase9-xcpng-boot.sh` - workdir: `/tmp/phase10-canon-xcpng-1775120869` Important findings: - the Phase 9 booted system path was already real, but the remaining transitional layer was the tooling/frontend boundary rather than the system internals - adding `bin/fruix` in Phase 10.1 was necessary but not sufficient on its own; the existing validation and deployment workflows also had to adopt it, or the project would still effectively be driven by bespoke phase scripts - after this refactor, the command path is now exercised by: - static closure validation - static rootfs validation - static image validation - and the real XCP-ng boot/import/SSH/ready-marker path Current assessment: - Optional Phase 10 is now complete for the current FreeBSD prototype track - Fruix now has: - a user-facing command surface in `bin/fruix` - real `system build`, `system rootfs`, and `system image` actions - canonical validation/deployment workflows that use that command instead of directly entering the materializers - and a command-driven image path that remains validated on the real XCP-ng VM - this means the project now has not just declarative OS internals, but also a real Fruix operator/tooling layer around those internals Next recommended step: 1. begin the next post-Phase-10 cleanup/polish pass outside the plan milestones 2. prioritize replacing the current Guile / Shepherd compatibility-prefix shims with a more native store-path-aware runtime arrangement 3. consider adding richer deploy/vm-oriented `fruix` commands beyond the now-canonical `system build/rootfs/image` path ## 2026-04-02 — Post-Phase-10: local Shepherd-as-PID-1 prototype booted on FreeBSD Completed work: - began the next post-Phase-10 runtime-integration pass by exploring a Shepherd-as-PID-1 boot mode for Fruix on FreeBSD - compared the approach with Guix's root Shepherd design in: - `~/repos/guix/gnu/services/shepherd.scm` - wrote the subphase report: - `docs/reports/postphase10-shepherd-pid1-qemu-freebsd.md` - extended the declarative FreeBSD operating-system model in: - `modules/fruix/system/freebsd.scm` - added an `init-mode` field with: - `freebsd-init+rc.d-shepherd` - `shepherd-pid1` - generated loader configuration now sets: - `init_exec="/run/current-system/boot/fruix-pid1"` when `init-mode` is `shepherd-pid1` - generated systems in PID 1 mode now include: - `boot/fruix-pid1` - the generated activation script now treats `cap_mkdb` / `pwd_mkdb` as best-effort so immutable store-backed config files do not abort this early boot path - added a dedicated Shepherd-PID-1 operating-system template: - `tests/system/phase11-shepherd-pid1-operating-system.scm.in` - added a dedicated local QEMU/UEFI validation harness: - `tests/system/run-phase11-shepherd-pid1-qemu.sh` Important findings: - FreeBSD's `init(8)` already has a suitable handoff mechanism for this experiment via: - `init_exec` - compared with Guix, the current Fruix implementation is still much more imperative, but it now follows the same broad direction: - boot into Shepherd directly as PID 1 rather than merely starting Shepherd late from rc.d - the first PID 1 attempt failed because the generated Shepherd config imported a repo-side module: - `(fruix shepherd freebsd)` that was not present inside the guest runtime; the fix was to inline the small helper procedures needed by the generated config itself - the early PID 1 path also exposed that store-backed `/etc/login.conf` and `/etc/master.passwd` updates must be best-effort rather than fatal on this bootstrap path - for the current locally built runtime artifacts, the compatibility-prefix shims are still needed; this subphase did not eliminate them yet, but it did remove the larger `rc.d` boot-manager dependency from the local prototype path Validation: - `tests/system/run-phase11-shepherd-pid1-qemu.sh` now passes - passing run workdir: - `/tmp/pid1-qemu6-1775128407` - validated local guest state included: - `ready_marker=ready` - `shepherd_pid=1` - `shepherd_socket=present` - `shepherd_status=running` - `sshd_status=running` - `boot_backend=qemu-uefi-tcg` - `init_mode=shepherd-pid1` Current assessment: - Fruix now has a working local FreeBSD prototype where Shepherd itself is PID 1 - this is not yet the new mainline boot path, but it proves that the project can move beyond the earlier `freebsd-init+rc.d-shepherd` bridge architecture - the PID 1 process image appears as Guile because Shepherd is launched as a Guile script, but the decisive validation point is that: - `/var/run/shepherd.pid` contains `1` - this subphase was validated locally under QEMU/TCG + UEFI; the next meaningful test is the real XCP-ng VM Next recommended step: 1. try the `shepherd-pid1` image on the real XCP-ng VM 2. if it boots there too, decide whether to keep `shepherd-pid1` as an experimental selectable boot mode or advance it further toward the main Fruix boot path 3. continue reducing the remaining Guile / Shepherd compatibility-prefix shims now that the broader `rc.d` boot-manager dependency has been locally bypassed ## 2026-04-02 — Post-Phase-10: Shepherd-as-PID-1 boot also passed on the real XCP-ng VM Completed work: - took the locally validated `shepherd-pid1` boot mode and tested it on the real XCP-ng deployment path - wrote the follow-up report: - `docs/reports/postphase10-shepherd-pid1-xcpng-freebsd.md` - expanded the Shepherd-PID-1 operating-system template so the generated guest remains compatible with both local virtio and the real Xen NIC path: - `tests/system/phase11-shepherd-pid1-operating-system.scm.in` - now includes: - `ifconfig_xn0=SYNCDHCP` - `ifconfig_em0=SYNCDHCP` - `ifconfig_vtnet0=SYNCDHCP` - added a dedicated real-VM Shepherd-PID-1 deployment/validation harness: - `tests/system/run-phase11-shepherd-pid1-xcpng.sh` Validation: - `tests/system/run-phase11-shepherd-pid1-xcpng.sh` now passes on the operator-approved VM and existing VDI: - VM `90490f2e-e8fc-4b7a-388e-5c26f0157289` - VDI `0f1f90d3-48ca-4fa2-91d8-fc6339b95743` - passing run workdir: - `/tmp/pid1-xcpng-1775129768` - passing real-guest metadata confirmed: - `ready_marker=ready` - `run_current_system_target=/frx/store/2940c952e9d35e47f98fe62f296be2b6ab4fceb3eee8248d6a7823decd42a305-fruix-system-fruix-freebsd` - `pid1_command=[guile]` - `shepherd_pid=1` - `shepherd_socket=present` - `shepherd_status=running` - `sshd_status=running` - `init_mode=shepherd-pid1` Important findings: - the local QEMU PID 1 prototype was not a simulator-only artifact; the same general boot design also works on the real XCP-ng/Xen guest - as expected for a Guile-script entry point, the PID 1 process image shows up as Guile, but the meaningful architectural check is that: - `/var/run/shepherd.pid` contains `1` - this means Fruix has now validated two distinct real-VM boot architectures on FreeBSD: - `freebsd-init+rc.d-shepherd` - `shepherd-pid1` - however, this still does not remove the current Guile / Shepherd compatibility-prefix shims; those remain a separate runtime-artifact issue rather than an init-manager issue Current assessment: - Shepherd-as-PID-1 is now no longer merely a local prototype; it is validated on the real XCP-ng VM as well - this significantly strengthens the path toward a more Guix-like Fruix system architecture on FreeBSD - the main remaining native-runtime gap is now the baked-prefix / compatibility-shim problem, not whether Fruix can boot with Shepherd as PID 1 Next recommended step: 1. focus directly on eliminating the remaining Guile / Shepherd compatibility-prefix shims from the guest runtime 2. preserve `shepherd-pid1` as an experimental selectable boot mode while that cleanup proceeds 3. once the runtime-prefix issue is reduced, reassess whether `shepherd-pid1` should replace the older `freebsd-init+rc.d-shepherd` path as the preferred Fruix boot architecture ## 2026-04-02 — Post-Phase-10: removed runtime dependence on `/tmp` Guile / Shepherd compatibility-prefix shims Completed work: - removed the generated guest's runtime dependence on the old `/tmp` compatibility-prefix symlinks for Guile, guile-extra, and Shepherd - wrote the subphase report: - `docs/reports/postphase10-runtime-prefix-shims-freebsd.md` - updated the prefix materializer in: - `modules/fruix/system/freebsd.scm` - bumped the prefix-materializer revision - added deterministic post-copy sanitation for staged runtime prefixes - removed activation-time recreation of these guest-side shims from the generated activation path: - `/tmp/guile-freebsd-validate-install` - `/tmp/guile-gnutls-freebsd-validate-install` - `/tmp/shepherd-freebsd-validate-install` - sanitized the staged guile-extra runtime so it no longer depends on those old prefixes for key module loading: - patched `fibers/config.scm` to use `GUILE_EXTENSIONS_PATH` - patched `gnutls.scm` to fall back to `GUILE_EXTENSIONS_PATH` - removed stale compiled cache files that would otherwise retain the old prefix behavior: - `fibers/config.go` - `gnutls.go` - sanitized the staged Shepherd runtime so it no longer depends on the old temporary prefix for `shepherd config`: - patched `share/guile/site/3.0/shepherd/config.scm` - removed stale compiled cache file: - `shepherd/config.go` - extended the real XCP-ng validation harnesses so they now explicitly check for: - absence of the `/tmp` compatibility-prefix trees - successful Guile module loading from the store-backed runtime - updated: - `tests/system/run-phase9-xcpng-boot.sh` - `tests/system/run-phase11-shepherd-pid1-xcpng.sh` Validation: - `tests/system/run-phase9-xcpng-boot.sh` passes on the real VM with: - workdir: `/tmp/noshim-phase9-smoke-1775143001` - `compat_prefix_shims=absent` - `guile_module_smoke=ok` - `ready_marker=ready` - `shepherd_status=running` - `sshd_status=running` - `tests/system/run-phase11-shepherd-pid1-xcpng.sh` passes on the real VM with: - workdir: `/tmp/noshim-phase11-smoke-1775142712` - `compat_prefix_shims=absent` - `guile_module_smoke=ok` - `ready_marker=ready` - `shepherd_pid=1` - `shepherd_status=running` - `sshd_status=running` - a direct manual guest probe also confirmed that all three `/tmp` compatibility-prefix paths are absent while Guile can still load: - `(fibers config)` - `(gnutls)` - `(shepherd config)` Important findings: - the remaining native-runtime problem was narrower than the earlier boot-manager issue: - boot was already solved - PID 1 was already solved - the next real dependency to remove was the guest's reliance on temporary compatibility aliases - deleting the stale compiled cache files for the affected modules was important; otherwise Guile could continue using prefix-baked compiled forms even after the source modules were patched - this subphase removes runtime dependence on the old `/tmp` compatibility shims, but it does not yet guarantee that every embedded historical prefix string has disappeared from every binary or metadata artifact Current assessment: - Fruix now boots and runs from a store-backed Guile / Shepherd runtime arrangement on FreeBSD without needing guest-side `/tmp` compatibility-prefix symlinks - this now holds for both validated real-VM boot modes: - `freebsd-init+rc.d-shepherd` - `shepherd-pid1` - the main remaining cleanup is deeper and lower-level: - move the local Guile / guile-extra / Shepherd build/install flow itself closer to a truly store-native prefix so the remaining baked strings disappear from the artifacts rather than merely becoming runtime-irrelevant Next recommended step: 1. keep `shepherd-pid1` available as the stronger experimental boot architecture 2. start pushing the local Guile / guile-extra / Shepherd build/install process itself toward a truly store-native prefix layout 3. clean up the remaining historical prefix strings still present in binaries, libtool metadata, and pkg-config metadata where they still matter for developer/operator workflows ## 2026-04-02 — Phase 12.1: deployment provenance and diagnostic metadata improved Completed work: - wrote the next-stage plan document: - `docs/PLAN_3.md` - added a concise progress snapshot: - `docs/PROG_SUMMARY.md` - wrote the Phase 12.1 report: - `docs/reports/phase12-provenance-diagnostics-freebsd.md` - updated `modules/fruix/system/freebsd.scm` so generated system closures now carry explicit provenance files: - `metadata/host-base-provenance.scm` - `metadata/store-layout.scm` - those closure metadata files now record at least: - host `freebsd-version -kru` - host `uname -a` - `/usr/src` path - `/usr/src` git revision/branch when available - `newvers.sh` SHA256 as a fallback source-tree identifier - exact host-staged FreeBSD base store paths - exact Fruix runtime store paths - selected init mode - extended `scripts/fruix.scm` so `fruix system build` and `fruix system image` now emit explicit provenance/layout metadata including: - `host_base_store_count` - `host_base_stores` - `fruix_runtime_store_count` - `fruix_runtime_stores` - `host_base_provenance_file` - `store_layout_file` - `host_freebsd_version` - `host_uname` - `usr_src_git_revision` - `usr_src_git_branch` - `usr_src_newvers_sha256` - tightened the local closure/image validation harnesses so they now assert that this provenance metadata exists: - `tests/system/run-phase7-system-closure.sh` - `tests/system/run-phase8-system-image.sh` - expanded the VM-oriented harnesses to collect more guest-side diagnostic tails where available: - `tests/system/run-phase9-xcpng-boot.sh` - `tests/system/run-phase11-shepherd-pid1-xcpng.sh` - `tests/system/run-phase11-shepherd-pid1-qemu.sh` - now include additional capture for: - `shepherd-bootstrap.out` - `shepherd.log` - recent `dmesg` - stabilized local reproducibility checks by forcing: - `GUILE_AUTO_COMPILE=0` in the host-side closure/image harnesses when invoking `fruix` under `sudo env` Validation: - `tests/system/run-phase7-system-closure.sh` passes with the new provenance checks: - workdir: `/tmp/phase12-1b-closure-1775157039` - confirmed: - `host_base_store_count=8` - `fruix_runtime_store_count=3` - `host_base_provenance_file=/frx/store/.../metadata/host-base-provenance.scm` - `store_layout_file=/frx/store/.../metadata/store-layout.scm` - `host_freebsd_version=15.0-STABLE` - `tests/system/run-phase8-system-image.sh` passes with the new provenance checks: - workdir: `/tmp/phase12-1b-image-1775157039` - confirmed: - `host_base_store_count=8` - `fruix_runtime_store_count=3` - `host_base_provenance_file=/frx/store/.../metadata/host-base-provenance.scm` - `store_layout_file=/frx/store/.../metadata/store-layout.scm` - `host_uname=FreeBSD fruixdev 15.0-STABLE ...` - syntax-checked successfully: - `tests/system/run-phase9-xcpng-boot.sh` - `tests/system/run-phase11-shepherd-pid1-xcpng.sh` - `tests/system/run-phase11-shepherd-pid1-qemu.sh` Important findings: - the current host-staged FreeBSD base pipeline is still transitional, but it is now much more inspectable and self-describing - one-shot reproducibility failures immediately after source edits were partly a host-side auto-compilation artifact; forcing `GUILE_AUTO_COMPILE=0` in the validation harnesses makes the closure/image checks more stable - the project can now identify much more directly: - which closure/image inputs came from the host-staged FreeBSD base - which came from Fruix-built Guile/Shepherd runtime artifacts - what `/usr/src` identity was available at build time Current assessment: - Fruix now has a better-documented and easier-to-debug working pipeline for the current host-staged FreeBSD base model - this is the right amount of hardening before beginning native FreeBSD base-build work; it improves traceability without pretending the current host-copy model is final Next recommended step: 1. continue with Phase 12.2 and tighten the guest-side runtime/operator diagnostics 2. remove or reduce the most distracting remaining boot/runtime rough edges where the fixes are small and local 3. keep the deployment path stable so Phase 13 can start from a sharper baseline ## 2026-04-02 — Phase 12.2: guest runtime diagnostics tightened and `/etc` handling improved Completed work: - wrote the Phase 12.2 report: - `docs/reports/phase12-runtime-diagnostics-freebsd.md` - updated `modules/fruix/system/freebsd.scm` so selected database-backed `/etc` files are now materialized as regular files in the guest rootfs instead of symlinks: - `/etc/passwd` - `/etc/master.passwd` - `/etc/group` - `/etc/login.conf` - the generated activation script now refreshes those files from `/run/current-system/etc` before rebuilding FreeBSD databases - activation now writes a guest-visible log: - `/var/log/fruix-activate.log` - with markers including: - `fruix-activate:start` - `fruix-activate:cap_mkdb=ok` - `fruix-activate:pwd_mkdb=ok` - `fruix-activate:done` - exit status marker via shell trap - tightened closure permissions slightly by making: - `etc/master.passwd` mode `0600` - upgraded validation harnesses so they now assert the improved runtime behavior directly: - `tests/system/run-phase8-system-image.sh` - now checks that image `/etc/login.conf` is a regular file - now checks that image `/etc/master.passwd` is a regular file - `tests/system/run-phase9-xcpng-boot.sh` - `tests/system/run-phase11-shepherd-pid1-xcpng.sh` - `tests/system/run-phase11-shepherd-pid1-qemu.sh` - now check for: - `login_conf_kind=regular` - `login_conf_db=present` - `pwd_dbs=present` - activation log completion marker - fixed a small follow-up bug in the activation log path: - initial implementation used `touch`, which is not staged in the minimal guest - switched to shell redirection instead: - `: >> "$logfile"` Validation: - `tests/system/run-phase8-system-image.sh` passes locally with the new image-layout checks: - workdir: `/tmp/phase12-2-image-1775159011` - confirmed: - `login_conf_kind=regular` - `master_passwd_kind=regular` - `tests/system/run-phase11-shepherd-pid1-qemu.sh` passes locally again with the new activation/runtime checks: - workdir: `/tmp/phase12-2b-qemu-1775161367` - confirmed: - `activate_log=fruix-activate:start ... fruix-activate:done ...` - `login_conf_kind=regular` - `login_conf_db=present` - `pwd_dbs=present` - `shepherd_pid=1` - `sshd_status=running` - `tests/system/run-phase9-xcpng-boot.sh` passes on the real VM with the new checks: - workdir: `/tmp/phase12-2b-phase9-1775161731` - confirmed: - `activate_log=fruix-activate:start ... fruix-activate:done ...` - `login_conf_kind=regular` - `login_conf_db=present` - `pwd_dbs=present` - `compat_prefix_shims=absent` - `guile_module_smoke=ok` - `shepherd_status=running` - `sshd_status=running` - `tests/system/run-phase11-shepherd-pid1-xcpng.sh` passes on the real VM with the new checks: - workdir: `/tmp/phase12-2b-phase11-1775162210` - confirmed: - `activate_log=fruix-activate:start ... fruix-activate:done ...` - `login_conf_kind=regular` - `login_conf_db=present` - `pwd_dbs=present` - `compat_prefix_shims=absent` - `guile_module_smoke=ok` - `shepherd_pid=1` - `sshd_status=running` Important findings: - the old symlink-based handling for login/password database inputs was a real mismatch with FreeBSD expectations; making those files regular in the guest was a better fit than leaving them store-backed symlinks - adding a direct activation log materially improves post-boot diagnosis and avoids guessing whether activation actually completed - the first attempt exposed a missing-userland dependency (`touch`) quickly; because the new diagnostics were explicit, the follow-up fix was immediate and local - both validated boot paths still hold after this change: - `freebsd-init+rc.d-shepherd` - `shepherd-pid1` Current assessment: - the current Fruix guest remains intentionally minimal, but its runtime behavior is now less prototype-noisy and easier to inspect as a basic FreeBSD-like system - this is exactly the kind of targeted hardening that makes the existing system a better launch point for native FreeBSD base-build work Next recommended step: 1. complete Phase 12.3 by making the host-staged FreeBSD base boundary explicit in the package/model layer and docs 2. document the first intended replacement order for native world/kernel work 3. then begin Phase 13 with a clearer transitional boundary ## 2026-04-02 — Phase 12.3: made the host-staged FreeBSD base boundary explicit Completed work: - wrote the Phase 12.3 report: - `docs/reports/phase12-host-staged-base-boundary-freebsd.md` - refined `modules/fruix/packages/freebsd.scm` so the transitional host-copy base boundary is now explicit in the package/model layer - added and exported named transitional package sets: - `%freebsd-host-staged-all-packages` - `%freebsd-host-staged-core-packages` - `%freebsd-host-staged-development-profile-packages` - `%freebsd-host-staged-system-packages` - added and exported: - `freebsd-host-staged-package?` - `%freebsd-host-staged-replacement-order` - preserved compatibility aliases so existing callers still work: - `%freebsd-core-packages` - `%freebsd-development-profile-packages` - `%freebsd-system-packages` - encoded the intended first replacement order for native base-build work directly in the package layer: 1. `freebsd-kernel`, `freebsd-bootloader` 2. `freebsd-runtime`, `freebsd-libc`, `freebsd-userland`, `freebsd-rc-scripts` 3. `freebsd-networking`, `freebsd-openssh` 4. `freebsd-kernel-headers`, `freebsd-clang-toolchain` 5. `freebsd-gmake`, `freebsd-autotools`, `freebsd-openssl`, `freebsd-zlib`, `freebsd-sh`, `freebsd-bash` - updated `modules/fruix/system/freebsd.scm` so the generated closure metadata now carries this boundary information too: - `metadata/store-layout.scm` now includes: - `host-base-stores` - `fruix-runtime-stores` - `host-base-replacement-order` - `init-mode` Validation: - confirmed package-layer behavior directly with Guile: - `(freebsd-host-staged-package? freebsd-runtime)` => `#t` - `%freebsd-host-staged-replacement-order` prints the expected staged replacement order - `tests/system/run-phase7-system-closure.sh` still passes after the package-layer clarification: - workdir: `/tmp/phase12-3-closure-1775162784` - inspected generated closure metadata file: - `/frx/store/25ae9bb85da60b8c77971325e0e11d5390a064132a35e1bab0866cabb802a606-fruix-system-fruix-freebsd/metadata/store-layout.scm` - confirmed it now includes: - `host-base-stores` - `fruix-runtime-stores` - `host-base-replacement-order` Important findings: - the current host-staged FreeBSD base model is no longer just an implicit fact of the implementation; it is now named and documented as a transitional boundary - preserving compatibility aliases means the current working system model does not need a broad rename/refactor just to make that boundary explicit - encoding the replacement order directly in the package/model layer gives Phase 13 a clearer starting point for native `world`/`kernel` work Current assessment: - Phase 12 is now complete - the current Fruix pipeline is better documented, easier to diagnose, less noisy at runtime, and clearer about what remains transitional in the FreeBSD base layer - this is a good stopping point before beginning native FreeBSD base-build artifacts in `/frx/store` Next recommended step: 1. begin Phase 13.1 by modeling FreeBSD `world` and `kernel` as Fruix-managed build artifacts rather than host-copy packages 2. use `/usr/src` as the initial source of truth on the builder side 3. target the first bootable replacement for the current host-staged kernel and core runtime path ## 2026-04-02 — Phase 13.1: modeled native FreeBSD world/kernel artifacts Completed work: - wrote the Phase 13.1 report: - `docs/reports/phase13-native-base-model-freebsd.md` - added native FreeBSD base package objects in `modules/fruix/packages/freebsd.scm`: - `freebsd-native-kernel` - `freebsd-native-world` - added and exported: - `freebsd-native-build-package?` - encoded the first native build parameters directly in those package definitions, including: - `source-root=/usr/src` - `target=amd64` - `target-arch=amd64` - `kernconf=GENERIC` - make flags: - `__MAKE_CONF=/dev/null` - `SRCCONF=/dev/null` - `SRC_ENV_CONF=/dev/null` - `MK_DEBUG_FILES=no` - `MK_TESTS=no` - the first native world artifact now also carries an explicit runtime-oriented prune list: - `usr/share/doc` - `usr/share/examples` - `usr/share/info` - `usr/share/man` - `usr/tests` - extended `modules/fruix/system/freebsd.scm` so `materialize-freebsd-package` now understands: - `copy-build-system` - `freebsd-world-build-system` - `freebsd-kernel-build-system` - added native-build identity/materialization helpers for: - `/usr/src` source-tree identity - `KERNCONF` path hashing - build-root identity - buildworld/buildkernel stamp handling - staged installworld/installkernel materialization - native build metadata files in store outputs - chose an `mtree`-based `/usr/src` identity for the first native output model using: - `type` - `link` - `size` - `mode` - `sha256digest` - updated closure/image metadata modeling so the system can now distinguish: - `host_base_stores` - `native_base_stores` - `fruix_runtime_stores` - updated profile/tree merging to skip private dotfile metadata from store outputs so native-build metadata does not leak into the merged runtime tree Validation: - confirmed the updated package/system modules still load after the native build-model additions - confirmed the new native package objects are present and classified as expected: - `freebsd-native-kernel` reports build-system `freebsd-kernel-build-system` - `freebsd-native-build-package? freebsd-native-world` returns `#t` - re-ran the existing host-copy regression check successfully: - `tests/system/run-phase7-system-closure.sh` - workdir: `/tmp/phase13-1-closure-1775164392` - result: `PASS phase7-system-closure` Important findings: - Fruix now has a real model for FreeBSD base artifacts built from `/usr/src`; the project is no longer limited to describing the FreeBSD base only as host-copy packages - the first native identity story is explicit: - `/usr/src` contributes through an `mtree`-based tree digest - `KERNCONF` contributes through its resolved path hash - selected make/build parameters are part of the manifest too - the repo can now describe a mixed system more honestly by separating: - transitional host-staged base stores - native base stores - Fruix runtime stores Current assessment: - Phase 13.1 is complete - the next step is no longer architectural guesswork; it is concrete execution of the newly added native package/materialization path Next recommended step: 1. build the first concrete `freebsd-native-kernel` and `freebsd-native-world` outputs from `/usr/src` 2. inspect/document their staged contents in `/frx/store` 3. then wire a bootable system closure/image around those native outputs ## 2026-04-03 — Phase 13.2: first native FreeBSD world/kernel outputs built from `/usr/src` Completed work: - wrote the Phase 13.2 report: - `docs/reports/phase13-native-world-kernel-build-freebsd.md` - exercised the new native build path for real and produced the first concrete store outputs from `/usr/src`: - native kernel output under `/frx/store` - native world output under `/frx/store` - added a dedicated Phase 13.2 template/harness: - `tests/system/phase13-native-base-pid1-operating-system.scm.in` - `tests/system/run-phase13-native-base-build.sh` - fixed the first real native-build failure: - `MAKEOBJDIRPREFIX` cannot be passed as a make command-line variable for this FreeBSD build path - changed the native builder to invoke make as: - `env MAKEOBJDIRPREFIX=... make ...` - fixed a subtle output-identity bug in the first `/usr/src` hash implementation: - the initial `mtree`-based source hash accidentally included unstable header comments such as date/user/machine lines - now strips `# ...` header lines before hashing - this stabilized the source-tree identity and stopped the native output/build-root identity from drifting on each run - verified that native world and kernel now share the same: - `source-tree-sha256` - `build-root` - the first native world split remains intentionally runtime-oriented and prunes at least: - `usr/share/doc` - `usr/share/examples` - `usr/share/info` - `usr/share/man` - `usr/tests` Concrete validated outputs: - native kernel store path: - `/frx/store/93f35ddcb9a03f63f83c9e8ae29788685d339789da664f881822b4a1914f5ff6-freebsd-native-kernel-15.0-STABLE` - native world store path: - `/frx/store/3f6f7f8c06ed8dad4cae21a1e8ac8ba4823bdb7cf54328c9bbcccaeb858beb77-freebsd-native-world-15.0-STABLE` - shared native build root: - `/var/tmp/fruix-freebsd-native-build-c59b1b8128b305d9bad9cf3d654771c941c4e8b6a2732f6bc959df96d1d32f58` Validated native-world contents include at least: - `/bin/sh` - `/sbin/init` - `/etc/rc` - `/usr/sbin/sshd` - `/sbin/dhclient` - `/usr/bin/cap_mkdb` - `/usr/sbin/pwd_mkdb` - `/usr/share/locale/C.UTF-8/LC_CTYPE` Validated pruned paths are absent from the world output: - `/usr/share/man` - `/usr/tests` Validation: - real native-base `fruix system build` succeeded with an operating-system using: - `freebsd-native-kernel` - `freebsd-native-world` - host-staged `freebsd-bootloader` - `shepherd-pid1` - `tests/system/run-phase13-native-base-build.sh` passes: - workdir: `/tmp/phase13-2-build-1775173551` - result: `PASS phase13-native-base-build` - the harness confirmed: - closure rebuild path reproducibility - native kernel/world store paths exist - native build info files exist - world/kernel source-tree hashes match - world/kernel build roots match - native build logs exist - `native-base-stores` is present in closure metadata - host/native store boundary now looks as expected for this mixed system: - `host_base_store_count=1` - `native_base_store_count=2` Important findings: - the native build path is now real, not just modeled - the first mixed Phase-13 system boundary is explicit and sensible: - host-staged bootloader only - native kernel + native world - Fruix runtime stores unchanged - the `mtree` preamble bug would have made native output identity drift across runs; fixing it was essential before treating these as reproducible store artifacts - the shared build-root result is important: the kernel/world pair now reuses the same `/usr/src` build state instead of acting like two unrelated builds Current assessment: - Phase 13.2 is complete - Fruix can now build and stage native FreeBSD base artifacts from `/usr/src` in `/frx/store` - the next step is to boot a system using those native outputs rather than stopping at build-time inspection Next recommended step: 1. wire the image/boot path to use the native kernel/world outputs end-to-end 2. validate locally with QEMU/UEFI 3. validate on the approved XCP-ng VM and VDI path ## 2026-04-03 — Phase 13.3: booted Fruix from native FreeBSD kernel/world outputs Completed work: - wrote the Phase 13.3 report: - `docs/reports/phase13-native-base-boot-freebsd.md` - completed the first end-to-end boot path using native `/usr/src`-built FreeBSD base artifacts in `/frx/store` - fixed the first native-image sizing problem: - the old fixed `root-size=256m` was too small once the image carried a native world - added explicit root filesystem sizing support to the CLI/image path: - `scripts/fruix.scm` now accepts `--root-size SIZE` - image metadata now records `root_size` - `tests/system/run-phase8-system-image.sh` now accepts: - `ROOT_SIZE` and records: - `root_size` - `native_base_store_count` - `native_base_stores` - fixed a follow-up image metadata bug: - `materialize-bhyve-image` now returns: - `native-base-stores` - this removed the `length #f` failure in the native image path - generalized the local PID1 QEMU harness a bit further: - `tests/system/run-phase11-shepherd-pid1-qemu.sh` now accepts `OS_TEMPLATE` - added dedicated Phase 13.3 native-base boot wrappers: - `tests/system/run-phase13-native-base-qemu.sh` - `tests/system/run-phase13-native-base-xcpng.sh` - these wrappers reuse the validated PID1 boot path but additionally require the image metadata to prove the booted system is really using the intended Phase-13 base split: - native kernel present - native world present - host base reduced to bootloader only Working native-base boot configuration: - local QEMU: - `ROOT_SIZE=6g` - `DISK_CAPACITY=8g` - real XCP-ng: - `ROOT_SIZE=6g` - disk capacity kept matched to the fixed 30 GiB VDI as before Validation: - local QEMU/UEFI/TCG boot passes through the new wrapper: - `tests/system/run-phase13-native-base-qemu.sh` - workdir: `/tmp/phase13-3-qemu3-1775174863` - result: `PASS phase13-native-base-qemu` - confirmed: - `disk_capacity=8g` - `root_size=6g` - `native_base_store_count=2` - `host_base_store_count=1` - `shepherd_pid=1` - `sshd_status=running` - `native_base_boot=ok` - real XCP-ng boot passes through the new wrapper: - `tests/system/run-phase13-native-base-xcpng.sh` - workdir: `/tmp/phase13-3-xcpng-1775175086` - result: `PASS phase13-native-base-xcpng` - confirmed: - `vm_id=90490f2e-e8fc-4b7a-388e-5c26f0157289` - `vdi_id=0f1f90d3-48ca-4fa2-91d8-fc6339b95743` - `guest_ip=192.168.213.62` - `root_size=6g` - `native_base_store_count=2` - `host_base_store_count=1` - `shepherd_pid=1` - `sshd_status=running` - `compat_prefix_shims=absent` - `guile_module_smoke=ok` - `native_base_boot=ok` - validated native-base closure/image composition now boots with: - native kernel store: - `/frx/store/93f35ddcb9a03f63f83c9e8ae29788685d339789da664f881822b4a1914f5ff6-freebsd-native-kernel-15.0-STABLE` - native world store: - `/frx/store/3f6f7f8c06ed8dad4cae21a1e8ac8ba4823bdb7cf54328c9bbcccaeb858beb77-freebsd-native-world-15.0-STABLE` - remaining host base store: - `/frx/store/8ffcfe0356fea815726b610514a1280a11266851c2acb870047d559795569f0e-freebsd-bootloader-15.0-STABLE` Important findings: - the native world is large enough that the older 256 MiB rootfs assumption is no longer realistic; explicit image sizing is now part of the practical Phase-13 path - after the native-base transition, the remaining transitional boundary is now much narrower and explicit: - host-staged bootloader/boot assets - native kernel - native core world runtime - the real XCP-ng upload path still works with the larger native-world image, but the dynamic VHD is naturally much bigger now (~4.42 GiB) Current assessment: - Phase 13 is complete - Fruix now builds FreeBSD kernel/world artifacts from `/usr/src` into `/frx/store` and successfully boots a declarative system from those native outputs - this is the main architectural pivot Plan 3 called for before Phase 14 Next recommended step: 1. begin Phase 14 by replacing the remaining host-copy boot assets first 2. keep shrinking the host-staged base boundary around the now-working native world/kernel path 3. revisit cleaner runtime vs. development splits after the boot asset transition