clawdie-iso/BUILD.md

6.2 KiB

Clawdie ISO Builder

On xfce-operator-usb, builds a bootable FreeBSD 15.0 operator USB image with:

  • XFCE desktop
  • pre-LightDM live GPU detection
  • Chromium browser
  • Tailscale
  • NetworkMgr launched via mdo, not sudo
  • bundled npm globals (pi, claude, gemini)
  • offline package repository
  • bundled Clawdie-AI tarball for later phases

The ISO version is independent from the bundled Clawdie-AI ref:

ISO_VERSION="0.1.0"
BUILD_CHANNEL="dev"      # dev | release
CLAWDIE_REF="main"       # validation default

Release builds must pin a Clawdie-AI tag with --clawdie-version X.Y.Z.


Prerequisites

On the FreeBSD build host:

sudo pkg install -y curl node24 npm-node24 sudo

Also required:

  • FreeBSD 15.0+
  • 150 GB free build space recommended
  • root or sudo for image assembly
  • 32 GB USB key minimum for the default IMAGE_SIZE=28G

Tailscale is packaged for live operator access. Authentication is expected later from the running USB with mdo -u root tailscale up, after operator credentials and other keys are available.


Quick Start

# Confirm you are building the intended branch/head first.
git status --short --branch
git log --oneline -5

# Full build: fetch + assemble.
sudo ./build.sh

Output:

tmp/output/clawdie-xfce-quindecim-usb-DD.MM.YY-abcdef0.img

Published/downloaded artifacts are compressed as .img.gz. Stream the compressed image directly into dd:

gzip -dc clawdie-xfce-quindecim-usb-DD.MM.YY-abcdef0.img.gz | sudo dd of=/dev/daX bs=1M status=progress conv=fsync
sync

For Linux or FreeBSD downloads from the published HTTPS path, prefer resumable curl with retries before flashing:

curl -fL --continue-at - --retry 5 --retry-delay 5 --progress-bar -O \
  https://osa.smilepowered.org/downloads/iso/clawdie-xfce-quindecim-usb-DD.MM.YY-abcdef0.img.gz
curl -fL --retry 5 --retry-delay 5 -O \
  https://osa.smilepowered.org/downloads/iso/clawdie-xfce-quindecim-usb-DD.MM.YY-abcdef0.img.gz.sha256

For a build-local uncompressed image, plain dd is also fine:

sudo dd if=tmp/output/clawdie-xfce-quindecim-usb-DD.MM.YY-abcdef0.img of=/dev/daX bs=1M status=progress conv=fsync
sync

Use the whole USB device (/dev/daX), not a partition. See FLASHING.md for Linux commands, checksum verification, and stale-label cleanup.


Useful Build Modes

# Download/cache FreeBSD, packages, npm globals, and Clawdie-AI only.
./build.sh --fetch-only

# Assemble using cached inputs.
sudo ./build.sh --skip-fetch

# Fetch packages but reuse the cached FreeBSD memstick image.
sudo ./build.sh --skip-memstick-fetch

# Dev/test image: set live user clawdie password to quindecim.
sudo ./build.sh --live-default-password

# Bundle a specific branch/tag/commit ref.
sudo ./build.sh --clawdie-ref main
sudo ./build.sh --clawdie-ref f04f35eb4e16b50150ae73bad2e271388dc88f82

# Release build from a pinned Clawdie-AI tag.
BUILD_CHANNEL=release sudo ./build.sh --clawdie-version 0.10.0

--skip-fetch is provenance-safe for Clawdie-AI: moving refs are resolved to a commit and cached by that commit. If the commit cannot be resolved safely, the script refuses a moving-ref skip-fetch build rather than producing misleading manifest data.


Build Output and Provenance

The build header shows:

ISO     : 0.1.0-dev
FreeBSD : 15.0-RELEASE amd64
Clawdie : main
Clawdie commit: <resolved-sha>

The image contains:

/usr/local/share/clawdie-iso/build-manifest.json

The installed system receives the same manifest. It records:

  • ISO version and build channel
  • FreeBSD version/arch
  • bundled Clawdie-AI ref and commit
  • ISO repo commit and dirty state
  • UTC build timestamp

The final size output distinguishes:

  • Image size — logical size that must fit on the USB key
  • Allocated — sparse bytes used on the build host

Build Configuration

Edit build.cfg for persistent defaults:

ISO_VERSION="0.1.0"
BUILD_CHANNEL="${BUILD_CHANNEL:-dev}"
IMAGE_SIZE="28G"
CLAWDIE_REF="${CLAWDIE_REF:-main}"
DEFAULT_PKG_BRANCH="latest"
FEATURE_TAILSCALE="${FEATURE_TAILSCALE:-YES}"

Notes:

  • Host pkg repo branch and ISO package branch are independent.
  • DEFAULT_PKG_BRANCH=latest is the ISO package source by default.
  • Provider keys, Telegram, and disk deployment are deferred on this branch.

Build Process

  1. Fetch FreeBSD memstick and verify checksum.
  2. Fetch all package archives for offline install.
  3. Build local pkg repository metadata.
  4. Fetch Clawdie-AI by resolved ref and prepare offline node_modules tarball.
  5. Create/attach the working image.
  6. Inject firstboot scripts, packages, XFCE live-session assets, bundled npm globals, Clawdie-AI tarball, build config, and manifest.
  7. Copy the final sparse image into tmp/output/.

The build is intentionally cache-friendly. If in doubt before validation, run the full sudo ./build.sh once after pulling current main.


Boot Flow Produced by the Image

  1. USB boots to XFCE live session.
  2. /usr/local/etc/rc.d/clawdie_live_gpu runs before LightDM and selects a conservative GPU path.
  3. LightDM autologins as clawdie.
  4. A desktop launcher opens the static Clawdie bootstrap page.
  5. The operator verifies browser, pi, Tailscale, and local networking.
  6. Later phases will add persistence, disk deployment, and upgrade/rescue flows.

Testing

Before writing to hardware, use bhyve when available:

sudo ./scripts/bhyve-pf-allow.sh
sudo ./scripts/bhyve-test.sh

See TESTING.md for the full validation checklist.


Troubleshooting

ERROR: missing package archive for <pkg>

A package was added after your cache was created. Run a full fetch/build:

sudo ./build.sh

pkg not found during unprivileged fetch

build.sh now sets a known FreeBSD tool PATH internally. If your shell still cannot find pkg manually, add /usr/local/sbin to your login PATH.

npm ci falls back to npm install

The bundled Clawdie-AI ref has a package-lock mismatch. The build warns and falls back so validation can continue, but release refs should have a clean lock.

Image says small allocated size

The image is sparse on the build host. Use the logical image size when choosing a USB key.


Last updated: 16.maj.2026