diff --git a/README.md b/README.md index 7949f87..b075ec8 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,10 @@ The direct checkout entrypoint now also prefers a prepared builder root at: when `fruix-bootstrap` has already prepared one. +## Guides + +- `docs/self-hosted-dev.md` — build the self-hosted development installer ISO and prepare an installed Fruix node for development work + ## Intended lifecycle ```text diff --git a/docs/self-hosted-dev.md b/docs/self-hosted-dev.md new file mode 100644 index 0000000..38266da --- /dev/null +++ b/docs/self-hosted-dev.md @@ -0,0 +1,405 @@ +# Self-hosted Fruix development + +This guide describes the current human-facing path for: + +1. building a Fruix installer ISO for the self-hosted development system +2. installing that system onto a VM or machine +3. turning the installed node into a practical Fruix development host + +This path is now validated most strongly in VM workflows, especially the +current XCP-ng loop, but the same basic process applies to any machine that can +boot the generated installer ISO. + +## What this system is for + +`examples/system/self-hosted-dev.scm` defines a Fruix node intended to: + +- run Fruix locally +- expose SSH for operator access +- provide a development profile with the current editor/runtime tooling +- provide a sanitized build profile for native base/package work +- serve as a host for the pi-agent-style development workflow + +Today that development profile includes the currently recovered developer tools, +notably: + +- Clang toolchain +- GNU make + FreeBSD make files +- Autotools +- OpenSSL + zlib +- sh + bash +- Node.js + npm +- ripgrep +- tmux +- neovim + +## Before you build + +### 1. Prepare a Fruix builder host + +The commands below assume: + +- you are on a FreeBSD host +- `fruix-bootstrap` has already prepared a builder root +- this repo is checked out locally + +The checkout entrypoint prefers a prepared builder root at: + +- `~/.local/opt/fruix-builder` + +So if that builder exists, you can usually invoke Fruix from the checkout with: + +```sh +./bin/fruix ... +``` + +### 2. Copy the example declaration and customize it + +Start from the example: + +```sh +cp examples/system/self-hosted-dev.scm my-self-hosted-dev.scm +``` + +At minimum, edit: + +- `#:host-name` +- `#:root-authorized-keys` for remote SSH access +- any user/account details you want to change + +A minimal customization usually looks like: + +```scheme +(use-modules (fruix system freebsd) + (fruix packages freebsd)) + +(define self-hosted-development-operating-system + (operating-system + #:host-name "fruix-dev-1" + #:rc-conf-entries '(("clear_tmp_enable" . "YES") + ("sendmail_enable" . "NONE") + ("sshd_enable" . "YES")) + #:root-authorized-keys + '("ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA... you@example") + #:development-packages %freebsd-development-profile-packages + #:build-packages %freebsd-development-profile-packages)) +``` + +If you skip `#:root-authorized-keys`, the installed node may still be usable +from the console, but it will not be ready for the normal remote development +loop. + +### 3. Pick a store directory with real space + +Image and installer builds can be large. Prefer a store directory with plenty of +space, for example: + +```sh +mkdir -p /var/tmp/fruix-selfhosted-store +``` + +## Build the installer ISO + +Run: + +```sh +./bin/fruix system installer-iso ./my-self-hosted-dev.scm \ + --system self-hosted-development-operating-system \ + --store /var/tmp/fruix-selfhosted-store \ + > /tmp/self-hosted-installer-iso.out +``` + +The command prints metadata rather than just one path. Recover the ISO path +from the output like this: + +```sh +iso=$(sed -n 's/^iso_image=//p' /tmp/self-hosted-installer-iso.out | sed -n '$p') +printf 'ISO: %s\n' "$iso" +``` + +Other useful fields in that output are: + +- `iso_store_path=` +- `installer_closure_path=` +- `target_closure_path=` +- `installer_state_path=` + +If you want to inspect the whole result later, keep the metadata file: + +```sh +less /tmp/self-hosted-installer-iso.out +``` + +## Boot and install + +### 1. Boot the ISO + +Use the generated `installer.iso` in whichever way is convenient for your +hardware or VM platform: + +- attach it as virtual media in a VM +- boot it as a CD/DVD image +- or write it to removable media using your usual FreeBSD workflow + +For development use, give the target disk enough headroom. In practice, +something in the **20-40 GiB** range is a much better starting point than a +minimal test disk. + +### 2. Use the installer + +The current intended human path from the booted installer is: + +```sh +/usr/local/bin/fruix system installer-tui +``` + +That starts the current experimental Newt-based installer flow. + +Notes: + +- this is still marked experimental +- the ISO was built from your declaration, so this is the path to try first +- if you are installing in a VM, use the VM console for the TUI + +### 3. If you need the direct CLI install path + +If you want an explicit non-interactive install from the booted installer +environment, use `fruix system install` and pass the declaration file +explicitly. + +Direct installs to `/dev/...` targets are intentionally gated. In the installer +shell, when you are already root, the simplest current pattern is: + +```sh +export FRUIX_ASSEMBLY_PRIVILEGED_COMMAND=env +export FRUIX_ASSEMBLY_ALLOW_BLOCK_DEVICE_TARGETS=1 + +/usr/local/bin/fruix system install /run/current-system/metadata/system-declaration.scm \ + --system self-hosted-development-operating-system \ + --target /dev/vtbd0 +``` + +Adjust `/dev/vtbd0` to the real target device. + +If you use this path, remember: + +- it is destructive for the selected target +- block-device installs are opt-in on purpose +- the TUI path is the friendlier default for humans + +## First boot after installation + +Once the installed system boots, log in on the console or over SSH and do a +quick sanity check: + +```sh +/usr/local/bin/fruix system status +``` + +You should see metadata describing the current generation, closure, and default +declaration paths. + +If you added root SSH keys in the declaration, verify remote access from your +operator machine. + +## Development environment on the installed node + +The installed self-hosted system already includes two important helper scripts. + +### 1. General development shell + +For editor/runtime/package-development work: + +```sh +eval "$(/usr/local/bin/fruix-development-environment)" +``` + +That exports a development-oriented environment pointing at: + +- `/run/current-system/development-profile` +- compiler/toolchain paths +- Node/npm paths +- runtime library paths +- man pages and other tool metadata + +After enabling it, useful smoke checks are: + +```sh +cc --version +node --version +npm --version +rg --version +tmux -V +nvim --version | sed -n '1p' +``` + +### 2. Sanitized build shell + +For native FreeBSD base rebuild work and stricter build testing: + +```sh +eval "$(/usr/local/bin/fruix-build-environment)" +``` + +That switches to the build-profile-oriented environment and drops the normal +development-shell overrides that would interfere with more controlled builds. + +Useful quick checks: + +```sh +echo "$FRUIX_BUILD_PROFILE" +make -V .CURDIR >/dev/null +``` + +### 3. Optional native base rebuild helper + +The self-hosted system also installs: + +- `/usr/local/bin/fruix-self-hosted-native-build` + +and exposes it through: + +```sh +/usr/local/bin/fruix system build-base +``` + +That is the current node-local helper for rebuilding FreeBSD world/kernel +artifacts from the staged source tree. It is useful, but it is a heavier, +longer-running workflow than ordinary declaration or package iteration. + +## Working on Fruix itself from the installed node + +There are two different Fruix entrypoints on an installed self-hosted node, and +it helps to use the right one. + +### 1. The installed node CLI + +```sh +/usr/local/bin/fruix +``` + +Use this for node-local lifecycle operations such as: + +- `fruix system status` +- `fruix system reconfigure` +- `fruix system rollback` +- `fruix system switch` + +This CLI is bundled into the installed system closure and is the right tool for +managing the node you are currently running. + +### 2. The checkout CLI + +If you are editing Fruix source code in a working tree, use the checkout +entrypoint from that tree: + +```sh +/path/to/fruix/bin/fruix +``` + +That path evaluates the Fruix source in your checkout and is what you want when +changing: + +- Fruix modules +- package definitions +- system render logic +- installer logic +- build/materialization code + +### 3. Getting a checkout onto the node + +The current self-hosted development profile does **not** yet provide a packaged +`git`, so the easiest current options are: + +- copy an existing checkout onto the node with `scp`/`rsync` +- mount or share a dataset that contains the checkout +- or add your own temporary host-side transfer step + +### 4. Preparing the checkout environment + +For checkout-based work, prepare the node the same way as any other Fruix build +host: + +- create or copy in a Fruix checkout +- prepare `~/.local/opt/fruix-builder` using `fruix-bootstrap` +- run the checkout via `./bin/fruix` + +The checkout entrypoint already prefers `~/.local/opt/fruix-builder` when it is +present. + +## A practical day-to-day loop + +### Declaration-only changes + +If you are only changing the system declaration used by the running node: + +```sh +/usr/local/bin/fruix system reconfigure /path/to/my-self-hosted-dev.scm \ + --system self-hosted-development-operating-system +``` + +That builds a new closure using the node's bundled Fruix payload and switches +node metadata to the new generation. + +After a successful reconfigure, plan on a reboot. + +If you need to undo it: + +```sh +/usr/local/bin/fruix system rollback +``` + +### Fruix source-tree changes + +If you changed Fruix code in a checkout, build with that checkout: + +```sh +/path/to/fruix/bin/fruix system build /path/to/my-self-hosted-dev.scm \ + --system self-hosted-development-operating-system \ + --store /var/tmp/fruix-dev-store \ + > /tmp/fruix-build.out +``` + +Recover the closure path: + +```sh +closure=$(sed -n 's/^closure_path=//p' /tmp/fruix-build.out | sed -n '$p') +printf 'closure: %s\n' "$closure" +``` + +Then switch the running node to that closure: + +```sh +/usr/local/bin/fruix system switch "$closure" +``` + +Again, plan on a reboot after switching. + +## Recommended post-install checklist + +For a node that should serve as a real self-hosted Fruix development box, the +useful immediate checklist is: + +- [ ] confirm SSH access works with your real operator key +- [ ] run `/usr/local/bin/fruix system status` +- [ ] enable the development environment and check `cc`, `node`, `npm`, `tmux`, and `nvim` +- [ ] copy a Fruix checkout onto the machine +- [ ] prepare `~/.local/opt/fruix-builder` on the node +- [ ] verify the checkout entrypoint works: `./bin/fruix --help` +- [ ] keep a scratch store directory for checkout builds, e.g. `/var/tmp/fruix-dev-store` +- [ ] do one full `reconfigure` and one `rollback` before treating the node as a daily driver + +## Current limitations and expectations + +This workflow is useful now, but it is still an actively developing path. + +Important current expectations: + +- the self-hosted path is real and usable, but not yet the final polished Fruix + product workflow +- the installed-node lifecycle is farther along than the broader deploy/upgrade + story +- the development profile is practical, but still intentionally small and + transitional +- some rough edges remain; treat the current system as a serious development + environment, not yet a finished distribution experience