2026-05-12 19:26:35 +02:00
# Clawdie ISO Builder
2026-03-24 00:51:22 +00:00
2026-05-24 23:21:02 +02:00
On `xfce-operator-usb` , builds a bootable FreeBSD 15.0 operator USB image with:
- XFCE desktop
- pre-SDDM live GPU detection
- Firefox browser
- Tailscale
- NetworkMgr launched via `mdo` , not `sudo`
- native Wi-Fi firmware bundle for NetworkMgr-managed wireless adapters
- bundled npm globals (`pi` only); `codex` ships as a FreeBSD pkg
instead of npm; `claude-code` is skipped on the live image because
its native deps have no FreeBSD binary (see `install_live_npm_globals` )
- bash as the default operator shell, with zsh + packaged oh-my-zsh available as optional user shell tooling
- Blender for Python-capable 3D/operator workflows
- offline package repository
- bundled Clawdie-AI tarball for later phases
2026-06-13 12:00:57 +02:00
- Colibri Rust control-plane service for the live USB
- deployed-system `clawdie` service lane for future disk/server installs
2026-03-24 00:51:22 +00:00
2026-06-15 10:08:30 +02:00
The ISO carries its own product version, independent of any component (zot,
Colibri, Clawdie-AI). Component versions are recorded in `build-manifest.json` .
2026-03-24 00:51:22 +00:00
2026-05-12 19:26:35 +02:00
```sh
docs: prep 0.11.0 publish — artifact names, download URLs, CHANGELOG
Stages the publish-time doc bump from 0.10.0 to 0.11.0: artifact filenames and
osa download/verify URLs (FLASHING, README, TESTING, BUILD, iso-publish skill),
the ISO product-version claims (README, BUILD), and enriches the existing
CHANGELOG [0.11.0] entry with this cycle's operator-facing ISO merges
(Join Hive vault provisioning, Tailscale auto-join, Mother MCP link, jq).
Left untouched: --clawdie-version examples (clawdie-ai namespace) and the
[0.10.0] CHANGELOG history. HOLD until the 0.11.0 image is built + hosted —
the download URLs 404 until then.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 06:33:25 +02:00
ISO_VERSION="0.11.0" # explicit product version (required; no zot-tracking)
2026-05-12 19:26:35 +02:00
BUILD_CHANNEL="dev" # dev | release
CLAWDIE_REF="main" # validation default
2026-03-24 00:51:22 +00:00
```
2026-05-12 19:26:35 +02:00
Release builds must pin a Clawdie-AI tag with `--clawdie-version X.Y.Z` .
---
docs: announce Tailscale mandatory, --target flag, glasspane, repo unification (Sam & Claude)
- README: rewrite for unified iso repo, two targets, mandatory Tailscale pre-req
- BUILD: add Step 0 (auth key), --target flag, --insecure-no-tailscale, first boot Tailscale screen 1
- AGENTS: note clawdie-shell archived, clawdie-iso is canonical, point to PLAN-UNIFY.md
2026-04-06 03:44:02 +00:00
2026-05-12 19:26:35 +02:00
## Prerequisites
2026-04-06 11:45:12 +02:00
2026-05-12 19:26:35 +02:00
On the FreeBSD build host:
2026-04-06 11:45:12 +02:00
2026-05-12 19:26:35 +02:00
```sh
2026-05-24 23:21:02 +02:00
sudo pkg install -y curl node24 npm-node24 sudo
2026-05-12 19:26:35 +02:00
```
docs: announce Tailscale mandatory, --target flag, glasspane, repo unification (Sam & Claude)
- README: rewrite for unified iso repo, two targets, mandatory Tailscale pre-req
- BUILD: add Step 0 (auth key), --target flag, --insecure-no-tailscale, first boot Tailscale screen 1
- AGENTS: note clawdie-shell archived, clawdie-iso is canonical, point to PLAN-UNIFY.md
2026-04-06 03:44:02 +00:00
2026-05-12 19:26:35 +02:00
Also required:
docs: announce Tailscale mandatory, --target flag, glasspane, repo unification (Sam & Claude)
- README: rewrite for unified iso repo, two targets, mandatory Tailscale pre-req
- BUILD: add Step 0 (auth key), --target flag, --insecure-no-tailscale, first boot Tailscale screen 1
- AGENTS: note clawdie-shell archived, clawdie-iso is canonical, point to PLAN-UNIFY.md
2026-04-06 03:44:02 +00:00
2026-05-12 19:26:35 +02:00
- FreeBSD 15.0+
- 150 GB free build space recommended
- root or `sudo` for image assembly
2026-05-24 23:21:02 +02:00
- 32 GB USB key minimum for the current default `IMAGE_SIZE=28G`
- 64 GB or larger recommended when you want more offline growth headroom
2026-06-13 12:00:57 +02:00
- prebuilt Colibri release artifacts for the live USB control plane
2026-03-24 00:51:22 +00:00
2026-05-24 23:21:02 +02:00
Tailscale is packaged for live operator access. You can either bake
`--tailscale-auth-key` for one-shot first-boot autojoin or authenticate later
from the running USB with `mdo -u root tailscale up` .
2026-05-12 19:26:35 +02:00
2026-05-28 00:46:24 +02:00
### Colibri artifacts
2026-06-13 12:00:57 +02:00
The operator USB stages Colibri as the live control plane. It expects prebuilt
docs: rewrite negative patterns to positive actionable instructions
Convert 'do not' / 'never' / 'avoid' / 'cannot' / 'must not' patterns
into positive 'do ABC to achieve XYZ' instructions across four key docs.
Files changed:
- AGENTS.md: role restrictions, linux constraints, formatting gate,
private workspace, scratch paths, mount discipline, source-of-truth
- BUILD.md: colibri compilation, mini-binary policy, USB flashing,
SSH-key distribution, mDNS scope, PF logging, host disk policy
- skills/iso-build/SKILL.md: build gating, CLI policy, command chaining,
tmux workflow, colibri preflight/cargo-clean timing, SDDM retention
- PLAN-OPERATOR-USB-NEXT.md: SDDM contract, package categorization,
bhyve gating, dashboard dependencies, seed checkout exclusions
Safety-critical constraints (USB whole-disk flashing, verified artifacts
only) are preserved with positive rephrasing that keeps the constraint
intact.
2026-06-21 13:13:08 +02:00
FreeBSD release binaries; Rust compilation takes place before image mounting,
and only prebuilt binaries land on the mounted image.
2026-05-28 00:46:24 +02:00
Default adjacent-checkout flow:
```sh
2026-06-05 00:38:25 +02:00
(cd /home/clawdie/ai/colibri & & cargo build --workspace --release)
2026-05-28 00:46:24 +02:00
sudo ./build.sh --skip-fetch
```
Override locations when needed:
```sh
2026-06-05 00:38:25 +02:00
COLIBRI_REPO=/home/clawdie/ai/colibri sudo ./build.sh --skip-fetch
2026-05-28 00:46:24 +02:00
COLIBRI_ARTIFACT_DIR=/path/to/colibri-target/release sudo ./build.sh --skip-fetch
```
2026-06-13 12:00:57 +02:00
Temporary debugging escape hatch while the flag still exists:
2026-05-28 00:46:24 +02:00
```sh
FEATURE_COLIBRI=NO sudo ./build.sh --skip-fetch
```
2026-06-21 08:11:39 +02:00
Operator-USB validation builds use the Colibri-backed default lane. Set
`FEATURE_COLIBRI=NO` only for focused staging/debug work. The image includes:
2026-05-28 00:46:24 +02:00
```text
2026-06-21 07:55:24 +02:00
/usr/local/bin/colibri-daemon # always-on Colibri control-plane daemon
/usr/local/bin/colibri # operator CLI for status, tasks, skills, and spawning
/usr/local/bin/colibri-mcp # MCP bridge for Zed/Claude Code/Cursor
/usr/local/bin/colibri-tui # optional terminal dashboard if present in artifacts
/usr/local/bin/colibri-test-agent # dev/validation only when COLIBRI_STAGE_TEST_AGENT=YES
/usr/local/etc/rc.d/colibri_daemon # FreeBSD service wrapper for colibri-daemon
/var/db/colibri # persistent SQLite/state directory
/var/run/colibri # runtime socket and PID directory
/var/log/colibri # daemon logs
2026-05-28 00:46:24 +02:00
```
The build also creates the `colibri` service user/group and writes rc.conf
2026-06-15 09:10:52 +02:00
values for `colibri_daemon_enable` , paths, and `colibri_daemon_cost_mode` . Operator USB
2026-06-13 12:00:57 +02:00
validation builds enable `colibri_daemon_enable=YES` ; the service starts after
the login milestone and is the lightweight control plane for the live USB.
2026-06-13 19:29:31 +02:00
`colibri-mcp` is staged out of the box for MCP-capable editors and assistants.
It defaults to read-only tools; launch it with `COLIBRI_MCP_WRITE=1` only for a
2026-06-13 19:36:03 +02:00
trusted write-capable MCP profile. Example MCP client configs are installed at
`/usr/local/share/clawdie-iso/mcp-examples/` .
2026-06-13 19:29:31 +02:00
2026-06-13 12:00:57 +02:00
### Colibri vs. Clawdie service names
```text
Live USB image
rc.conf: colibri_daemon_enable="YES"
service: colibri_daemon
purpose: lightweight live control plane for the operator desktop
Installed/deployed system
rc.conf: clawdie_enable="YES"
service: clawdie
purpose: persistent host agent/facade for health, inventory, watchdog,
credentials, and Colibri-backed orchestration
```
2026-06-13 12:12:34 +02:00
No current ISO build flag stages `service clawdie` . That name is reserved for
installed/deployed systems until the real persistent host service is chosen. The
docs: rewrite negative patterns to positive actionable instructions
Convert 'do not' / 'never' / 'avoid' / 'cannot' / 'must not' patterns
into positive 'do ABC to achieve XYZ' instructions across four key docs.
Files changed:
- AGENTS.md: role restrictions, linux constraints, formatting gate,
private workspace, scratch paths, mount discipline, source-of-truth
- BUILD.md: colibri compilation, mini-binary policy, USB flashing,
SSH-key distribution, mDNS scope, PF logging, host disk policy
- skills/iso-build/SKILL.md: build gating, CLI policy, command chaining,
tmux workflow, colibri preflight/cargo-clean timing, SDDM retention
- PLAN-OPERATOR-USB-NEXT.md: SDDM contract, package categorization,
bhyve gating, dashboard dependencies, seed checkout exclusions
Safety-critical constraints (USB whole-disk flashing, verified artifacts
only) are preserved with positive rephrasing that keeps the constraint
intact.
2026-06-21 13:13:08 +02:00
baseline live USB ships Colibri directly and excludes the old mini-binary
intended for the final deployed service.
2026-05-28 00:46:24 +02:00
2026-05-12 19:26:35 +02:00
---
2026-03-24 00:51:22 +00:00
## Quick Start
2026-05-12 19:26:35 +02:00
```sh
2026-05-24 23:21:02 +02:00
# Confirm you are building the intended branch/head first.
git status --short --branch
git log --oneline -5
2026-05-12 19:26:35 +02:00
# Full build: fetch + assemble.
sudo ./build.sh
```
2026-04-06 11:45:12 +02:00
2026-05-12 19:26:35 +02:00
Output:
2026-04-06 11:45:12 +02:00
2026-05-12 19:26:35 +02:00
```text
docs: prep 0.11.0 publish — artifact names, download URLs, CHANGELOG
Stages the publish-time doc bump from 0.10.0 to 0.11.0: artifact filenames and
osa download/verify URLs (FLASHING, README, TESTING, BUILD, iso-publish skill),
the ISO product-version claims (README, BUILD), and enriches the existing
CHANGELOG [0.11.0] entry with this cycle's operator-facing ISO merges
(Join Hive vault provisioning, Tailscale auto-join, Mother MCP link, jq).
Left untouched: --clawdie-version examples (clawdie-ai namespace) and the
[0.10.0] CHANGELOG history. HOLD until the 0.11.0 image is built + hosted —
the download URLs 404 until then.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 06:33:25 +02:00
tmp/output/clawdie-quindecim-0.11.0.img
2026-05-24 23:21:02 +02:00
```
2026-06-14 12:04:56 +02:00
Published/downloaded artifacts are compressed as `.img.xz` . Stream the
2026-05-24 23:21:02 +02:00
compressed image directly into `dd` :
```sh
2026-06-22 20:24:25 +02:00
xz -dc clawdie-quindecim-0.11.0.img.xz | dd of=/dev/daX bs=1M status=progress conv=fsync & & sync
2026-05-24 23:21:02 +02:00
sync
docs: announce Tailscale mandatory, --target flag, glasspane, repo unification (Sam & Claude)
- README: rewrite for unified iso repo, two targets, mandatory Tailscale pre-req
- BUILD: add Step 0 (auth key), --target flag, --insecure-no-tailscale, first boot Tailscale screen 1
- AGENTS: note clawdie-shell archived, clawdie-iso is canonical, point to PLAN-UNIFY.md
2026-04-06 03:44:02 +00:00
```
2026-05-24 23:21:02 +02:00
For Linux or FreeBSD downloads from the published HTTPS path, prefer resumable
`curl` with retries before flashing:
2026-05-12 19:26:35 +02:00
```sh
2026-05-24 23:21:02 +02:00
curl -fL --continue-at - --retry 5 --retry-delay 5 --progress-bar -O \
docs: prep 0.11.0 publish — artifact names, download URLs, CHANGELOG
Stages the publish-time doc bump from 0.10.0 to 0.11.0: artifact filenames and
osa download/verify URLs (FLASHING, README, TESTING, BUILD, iso-publish skill),
the ISO product-version claims (README, BUILD), and enriches the existing
CHANGELOG [0.11.0] entry with this cycle's operator-facing ISO merges
(Join Hive vault provisioning, Tailscale auto-join, Mother MCP link, jq).
Left untouched: --clawdie-version examples (clawdie-ai namespace) and the
[0.10.0] CHANGELOG history. HOLD until the 0.11.0 image is built + hosted —
the download URLs 404 until then.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 06:33:25 +02:00
https://osa.smilepowered.org/downloads/iso/clawdie-quindecim-0.11.0.img.xz
2026-05-24 23:21:02 +02:00
curl -fL --retry 5 --retry-delay 5 -O \
docs: prep 0.11.0 publish — artifact names, download URLs, CHANGELOG
Stages the publish-time doc bump from 0.10.0 to 0.11.0: artifact filenames and
osa download/verify URLs (FLASHING, README, TESTING, BUILD, iso-publish skill),
the ISO product-version claims (README, BUILD), and enriches the existing
CHANGELOG [0.11.0] entry with this cycle's operator-facing ISO merges
(Join Hive vault provisioning, Tailscale auto-join, Mother MCP link, jq).
Left untouched: --clawdie-version examples (clawdie-ai namespace) and the
[0.10.0] CHANGELOG history. HOLD until the 0.11.0 image is built + hosted —
the download URLs 404 until then.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 06:33:25 +02:00
https://osa.smilepowered.org/downloads/iso/clawdie-quindecim-0.11.0.img.xz.sha256
2026-03-24 00:51:22 +00:00
```
2026-05-24 23:21:02 +02:00
For a build-local uncompressed image, plain `dd` is also fine:
```sh
2026-06-22 20:24:25 +02:00
dd if=tmp/output/clawdie-quindecim-0.11.0.img of=/dev/daX bs=1M status=progress conv=fsync & & sync
2026-05-24 23:21:02 +02:00
sync
```
docs: rewrite negative patterns to positive actionable instructions
Convert 'do not' / 'never' / 'avoid' / 'cannot' / 'must not' patterns
into positive 'do ABC to achieve XYZ' instructions across four key docs.
Files changed:
- AGENTS.md: role restrictions, linux constraints, formatting gate,
private workspace, scratch paths, mount discipline, source-of-truth
- BUILD.md: colibri compilation, mini-binary policy, USB flashing,
SSH-key distribution, mDNS scope, PF logging, host disk policy
- skills/iso-build/SKILL.md: build gating, CLI policy, command chaining,
tmux workflow, colibri preflight/cargo-clean timing, SDDM retention
- PLAN-OPERATOR-USB-NEXT.md: SDDM contract, package categorization,
bhyve gating, dashboard dependencies, seed checkout exclusions
Safety-critical constraints (USB whole-disk flashing, verified artifacts
only) are preserved with positive rephrasing that keeps the constraint
intact.
2026-06-21 13:13:08 +02:00
Target the whole USB device (`/dev/daX` ); flashing to a partition is unsafe and
unsupported. See [FLASHING.md ](FLASHING.md )
2026-05-24 23:21:02 +02:00
for Linux commands, checksum verification, and stale-label cleanup.
2026-05-12 19:26:35 +02:00
---
## Useful Build Modes
2026-03-24 00:51:22 +00:00
2026-05-12 19:26:35 +02:00
```sh
# Download/cache FreeBSD, packages, npm globals, and Clawdie-AI only.
./build.sh --fetch-only
# Assemble using cached inputs.
Unify ISO and fix GPU installation gap (Sam & ZAI)
BREAKING CHANGE: Removes --target and --gpu-driver flags, unified ISO for all use cases
## Phase 0: GPU Fix + Unified ISO
### Core Changes
**GPU Package Installation (FIXES CRITICAL GAP):**
- Add clawdie_shell_nvidia_install() function to shell-nvidia.sh
- NVIDIA drivers now installed after detection (previously only configured)
- Works offline (USB packages) or online (pkg install)
- Resolves issue where rc.conf was set but driver not installed
**Unified ISO Architecture:**
- Remove --target flag from build.sh (no more vps/baremetal branching)
- Remove --gpu-driver flag from build.sh (runtime detection instead)
- All packages included on every ISO (desktop + all GPU drivers)
- Single image works on VPS, baremetal, and cloud
**Runtime Detection:**
- Add shell-desktop.sh for display detection at firstboot
- VPS/cloud: no display → lightdm disabled (headless)
- Baremetal: display detected → lightdm enabled (Lumina desktop)
- GPU detection always runs, installs correct driver version
**Sudo Unification:**
- Replace all doas references with sudo across entire codebase
- Update AGENTS.md with system configuration guidelines
- Update all documentation (BUILD.md, README.md, REQUIREMENTS.md, etc.)
- Admin panel now uses sudo for privileged operations
### Files Modified
**Core System:**
- build.sh: Remove target/gpu-driver logic, unified package selection
- firstboot/firstboot.sh: Add desktop detection module
- firstboot/shell-nvidia.sh: Add package installation function (+33 lines)
**New Files:**
- firstboot/shell-desktop.sh: Display detection and desktop enablement
- packages/pkg-list-nvidia-all.txt: All three NVIDIA driver versions (390/470/590)
- .opencode/plans/phase0-gpu-fix-unified-iso.md: Implementation plan
**Documentation:**
- PLAN-UNIFY.md: Update Step 3 for unified approach
- REQUIREMENTS.md: Simplify (no target choice), update for sudo
- BUILD.md: Update for unified ISO, sudo commands
- README.md: Update installation instructions
- AGENTS.md: Add system configuration section (sudo standardization)
- ADMIN-PANEL.md: Update privileged operations to use sudo
- CLAWDIE-SHELL.md: Update example commands to sudo
- CLAWDIE-ISO-REFACTORED.md: Update access paths to sudo
- REFACTOR-SUMMARY.md: Update permissions section to sudo
### Benefits
**Simplicity:**
- One build command: ./build.sh (no flags needed)
- One ISO to test and maintain
- No wrong choices for users
- No documentation explaining target differences
**Flexibility:**
- VPS can use GUI via VNC (wayvnc always available)
- Baremetal can run headless (disable lightdm)
- Repurpose hardware without reinstall
- All GPU drivers available for any hardware
**Technical:**
- Fixes critical GPU driver installation gap
- Runtime detection replaces build-time decisions
- Disk overhead: ~650MB (1-2% of 50GB - acceptable)
- No runtime overhead on VPS (services disabled by detection)
### Testing Required
- [ ] Build unified ISO: ./build.sh
- [ ] Test on VPS (no display): lightdm disabled, packages installed
- [ ] Test on baremetal (display): lightdm enabled, Lumina boots
- [ ] Test on NVIDIA hardware: driver installed and loaded
- [ ] Test sudo commands work without password prompts
- [ ] Verify all doas references removed
2026-04-06 13:28:56 +02:00
sudo ./build.sh --skip-fetch
2026-05-12 19:26:35 +02:00
2026-05-24 23:21:02 +02:00
# 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
# Bake an SSH public key for pubkey-only live USB access.
sudo ./build.sh --ssh-key "$(cat ~/.ssh/id_ed25519.pub)"
# Autojoin a tailnet on first boot via a one-shot self-deleting service.
sudo ./build.sh --tailscale-auth-key "$TAILSCALE_AUTH_KEY"
2026-05-12 19:26:35 +02:00
# 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
2026-03-24 00:51:22 +00:00
```
2026-05-12 19:26:35 +02:00
`--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.
2026-03-24 00:51:22 +00:00
2026-05-24 23:21:02 +02:00
### SSH key note for live-debug builds
`build.sh` accepts `--ssh-key` for the live USB. The key is installed into
`/home/clawdie/.ssh/authorized_keys` so the operator can pull logs without
hand-transcribing them from a tty.
Find an existing public key:
```sh
ls -l ~/.ssh/*.pub
cat ~/.ssh/id_ed25519.pub
```
Create a dedicated key for distributable images:
```sh
ssh-keygen -t ed25519 -a 100 -f ~/.ssh/clawdie-live-usb -C "clawdie-live-usb"
sudo ./build.sh --ssh-key "$(cat ~/.ssh/clawdie-live-usb.pub)"
```
**Listening policy on the live USB:** `sshd` runs unconditionally and listens
on all interfaces — both the LAN path and the tailnet path, so an operator
without Tailscale can still SSH in from the local network. Auth is restrictive
regardless: pubkey only, no passwords, no root. The daemon runs even when
`--ssh-key` is not provided (no authorized key → no one can authenticate;
harmless but predictable).
**Tailscale coupling:** when the build also receives a Tailscale auth key, the
live USB autojoins the tailnet on first boot and is reachable by MagicDNS
hostname (`ssh clawdie@clawdie-live` ). That's the preferred path; the LAN
path remains a fallback. Recommend passing both for hardware testing:
```sh
sudo ./build.sh \
--live-default-password \
--ssh-key "$(cat ~/.ssh/clawdie-live-usb.pub)" \
--tailscale-auth-key "$TAILSCALE_AUTH_KEY"
```
Current implementation:
- `--ssh-key` prepopulates `/home/clawdie/.ssh/authorized_keys` (mode 0600,
`.ssh/` mode 0700, owned `clawdie:clawdie` ).
- `sshd_enable="YES"` in the live rc.conf, unconditionally.
- Policy lives in a drop-in at
`/etc/ssh/sshd_config.d/clawdie-live.conf` , with the base
`/etc/ssh/sshd_config` including that directory. Contents:
`PubkeyAuthentication yes` , `PasswordAuthentication no` ,
`KbdInteractiveAuthentication no` , `ChallengeResponseAuthentication no` ,
`PermitRootLogin no` .
- `build-manifest.json` records the baked-in key fingerprint
(`ssh-keygen -lf <pubkey>` ) so the operator can verify the running image
matches expectation.
**Distribution-safety note:** public keys are public, so baking one in is
not a confidentiality issue — but anyone with the image file can SSH into a
live boot of it. For dev/test builds that's the right tradeoff. For public
docs: rewrite negative patterns to positive actionable instructions
Convert 'do not' / 'never' / 'avoid' / 'cannot' / 'must not' patterns
into positive 'do ABC to achieve XYZ' instructions across four key docs.
Files changed:
- AGENTS.md: role restrictions, linux constraints, formatting gate,
private workspace, scratch paths, mount discipline, source-of-truth
- BUILD.md: colibri compilation, mini-binary policy, USB flashing,
SSH-key distribution, mDNS scope, PF logging, host disk policy
- skills/iso-build/SKILL.md: build gating, CLI policy, command chaining,
tmux workflow, colibri preflight/cargo-clean timing, SDDM retention
- PLAN-OPERATOR-USB-NEXT.md: SDDM contract, package categorization,
bhyve gating, dashboard dependencies, seed checkout exclusions
Safety-critical constraints (USB whole-disk flashing, verified artifacts
only) are preserved with positive rephrasing that keeps the constraint
intact.
2026-06-21 13:13:08 +02:00
release images, omit `--ssh-key` entirely; operators add a key
2026-05-24 23:21:02 +02:00
themselves after first boot or build their own image. The dedicated
`clawdie-live-usb` key avoids leaking personal keys into shareable images.
See `doc/LIVE-SESSION-REVIEW.md` for the full pre-build plan and TESTING
hooks.
### LAN discovery (mDNS / Avahi)
The live USB advertises itself on the local network as
`clawdie-live.local` so the operator can SSH/`scp` without finding the
DHCP-assigned IP each boot. Two access paths in priority order:
```sh
# Preferred when Tailscale was passed at build time:
ssh clawdie@clawdie -live # MagicDNS
# Always-on LAN discovery — no Tailscale required:
ssh clawdie@clawdie -live.local # mDNS / Avahi
# Last-resort fallback if multicast is blocked on the network:
ssh clawdie@< dhcp-ip-from-router >
```
The implementation contract:
- Explicit packages in `packages/pkg-list-live-operator.txt` :
`avahi-app` (already transitive in the closure, list explicitly to
pin the contract) and `nss_mdns` .
- `avahi_daemon_enable="YES"` in live rc.conf. `dbus_enable="YES"` is
already set; Avahi depends on it.
- `/etc/nsswitch.conf` `hosts:` line set to
`files mdns_minimal [NOTFOUND=return] dns mdns` so `.local` names
resolve from the live USB itself.
- No config changes to the packaged Avahi `ssh.service` — its
`_ssh._tcp` advertisement is what we want.
**Scope discipline:** mDNS is **only** for LAN discovery of the live
USB itself. Clawdie's internal service names continue to live under
`home.arpa` (`ai.home.arpa` , `cms.home.arpa` , `git.home.arpa` ,
docs: rewrite negative patterns to positive actionable instructions
Convert 'do not' / 'never' / 'avoid' / 'cannot' / 'must not' patterns
into positive 'do ABC to achieve XYZ' instructions across four key docs.
Files changed:
- AGENTS.md: role restrictions, linux constraints, formatting gate,
private workspace, scratch paths, mount discipline, source-of-truth
- BUILD.md: colibri compilation, mini-binary policy, USB flashing,
SSH-key distribution, mDNS scope, PF logging, host disk policy
- skills/iso-build/SKILL.md: build gating, CLI policy, command chaining,
tmux workflow, colibri preflight/cargo-clean timing, SDDM retention
- PLAN-OPERATOR-USB-NEXT.md: SDDM contract, package categorization,
bhyve gating, dashboard dependencies, seed checkout exclusions
Safety-critical constraints (USB whole-disk flashing, verified artifacts
only) are preserved with positive rephrasing that keeps the constraint
intact.
2026-06-21 13:13:08 +02:00
`<tenant>.home.arpa` ). Keep internal service names under `home.arpa` ;
reserve `.local` exclusively for mDNS — RFC 6762 reserves `.local` for
mDNS, and mixing the two namespaces breaks both.
2026-05-24 23:21:02 +02:00
**Network caveat:** some corporate networks, hotel Wi-Fi, and isolated
guest VLANs block multicast traffic. In those environments
`clawdie-live.local` won't resolve and the operator falls back to the
Tailscale path (if configured) or the DHCP IP path. Worth knowing
before debugging "mDNS doesn't work" on a hostile network.
### PF firewall on the live USB
PF is enabled by default with a minimal, permissive baseline: outbound
open, inbound limited to SSH, mDNS, ICMP, DHCP-client, and Tailscale's
UDP 41641. The actual access restriction on SSH is carried by `sshd`
auth policy (pubkey only), not PF interface scoping.
docs: rewrite negative patterns to positive actionable instructions
Convert 'do not' / 'never' / 'avoid' / 'cannot' / 'must not' patterns
into positive 'do ABC to achieve XYZ' instructions across four key docs.
Files changed:
- AGENTS.md: role restrictions, linux constraints, formatting gate,
private workspace, scratch paths, mount discipline, source-of-truth
- BUILD.md: colibri compilation, mini-binary policy, USB flashing,
SSH-key distribution, mDNS scope, PF logging, host disk policy
- skills/iso-build/SKILL.md: build gating, CLI policy, command chaining,
tmux workflow, colibri preflight/cargo-clean timing, SDDM retention
- PLAN-OPERATOR-USB-NEXT.md: SDDM contract, package categorization,
bhyve gating, dashboard dependencies, seed checkout exclusions
Safety-critical constraints (USB whole-disk flashing, verified artifacts
only) are preserved with positive rephrasing that keeps the constraint
intact.
2026-06-21 13:13:08 +02:00
**PF logging stack is opt-in by default.** `pflog_enable`
and `pflogd_enable` remain at their `NO` defaults. The ruleset
has no `log` keywords, so nothing is captured by default. When
debugging from a booted live USB, the operator enables the stack by
2026-05-24 23:21:02 +02:00
hand:
```sh
mdo -u root kldload pflog
mdo -u root ifconfig pflog0 create
mdo -u root tcpdump -ni pflog0
```
Post-disk-install both knobs can be flipped to `YES` from `sysrc` for
forensic log capture. Not the live USB default.
The ruleset lives at `live/operator-session/pf-live.conf` (separate
from the installed-system policy in `firstboot/shell-pf.sh` , which has
different threat-model assumptions).
See `doc/LIVE-SESSION-REVIEW.md` for the full ruleset and TESTING hooks.
### Targeted tmpfs for write-heavy paths
The live USB targets 8 GB RAM minimum hardware. Mirror the proven
NomadBSD desktop-live pattern for the system paths, then add one
Clawdie-specific Firefox cache optimization:
| Path | Backing | Why |
| ---------------------- | ------------------------------- | ------------------------------------------------------------------------------------------------- |
| `/tmp` | tmpfs | X sockets, screenshot tools, browser/app temp files; NomadBSD ships this for SDDM/XFCE live media |
| `/var/log` | tmpfs | avoid steady-state USB writes from syslog, sshd, Avahi, dbus, and desktop services |
| `/home/clawdie/.cache` | symlink to `/tmp/clawdie/cache` | Firefox cache2, GTK icon cache, thumbnails — dominant desktop-session USB writer |
Keep `tmpmfs="NO"` and `varmfs="NO"` . The historical Clawdie breakage came
from the stock memstick's blanket rc.d `tmpmfs` /`varmfs` overlays, which hid
important `/var` content. Controlled fstab tmpfs entries for only `/tmp` and
`/var/log` are a different mechanism and match NomadBSD's long-running live
desktop design.
`/var/tmp` stays on disk. NomadBSD does not tmpfs it, and applications often
use `/var/tmp` for longer-lived crash-recovery state.
**Not adopted in this phase:** unionfs root / "XFCE from RAM". The
FreeBSD UFS buffer cache already keeps hot reads in RAM after first
load, and a full unionfs overlay would regress SDDM/SSH-host-key
persistence. Revisit when disk install + USB-removable mode become a
real requirement.
See `doc/LIVE-SESSION-REVIEW.md` for the rationale, the explicit
"what stays on disk" list, and TESTING hooks.
### Tailscale auth-key build flag
`build.sh` accepts `--tailscale-auth-key` for the live USB. When present, the
key is written to a root-only secret file inside the image and consumed by a
one-shot rc.d service on first boot. The service runs:
```text
tailscale up --auth-key=... --hostname=clawdie-live --ssh=false
```
Then it deletes the key file and disables itself. The operator can still join
manually after boot when no auth key was baked:
```sh
mdo -u root tailscale up
```
The auth key never lands in `build-manifest.json` or `build.cfg` — only the
boolean `tailscale_auth_key_baked: true|false` is recorded in the manifest.
2026-05-12 19:26:35 +02:00
---
2026-03-24 00:51:22 +00:00
2026-05-12 19:26:35 +02:00
## Build Output and Provenance
The build header shows:
```text
2026-06-15 08:04:31 +02:00
ISO : < iso-version > -dev
2026-05-12 19:26:35 +02:00
FreeBSD : 15.0-RELEASE amd64
Clawdie : main
Clawdie commit: < resolved-sha >
```
The image contains:
```text
/usr/local/share/clawdie-iso/build-manifest.json
2026-03-24 00:51:22 +00:00
```
2026-05-12 19:26:35 +02:00
The installed system receives the same manifest. It records:
- ISO version and build channel
- FreeBSD version/arch
- bundled Clawdie-AI ref and commit
2026-06-15 17:06:17 +02:00
- ISO repo commit and modified state
2026-05-12 19:26:35 +02:00
- 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
---
2026-03-24 00:51:22 +00:00
## Build Configuration
2026-05-12 19:26:35 +02:00
Edit `build.cfg` for persistent defaults:
2026-03-24 00:51:22 +00:00
```sh
docs: prep 0.11.0 publish — artifact names, download URLs, CHANGELOG
Stages the publish-time doc bump from 0.10.0 to 0.11.0: artifact filenames and
osa download/verify URLs (FLASHING, README, TESTING, BUILD, iso-publish skill),
the ISO product-version claims (README, BUILD), and enriches the existing
CHANGELOG [0.11.0] entry with this cycle's operator-facing ISO merges
(Join Hive vault provisioning, Tailscale auto-join, Mother MCP link, jq).
Left untouched: --clawdie-version examples (clawdie-ai namespace) and the
[0.10.0] CHANGELOG history. HOLD until the 0.11.0 image is built + hosted —
the download URLs 404 until then.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 06:33:25 +02:00
ISO_VERSION="${ISO_VERSION:-0.11.0}"
2026-05-12 19:26:35 +02:00
BUILD_CHANNEL="${BUILD_CHANNEL:-dev}"
2026-05-24 23:21:02 +02:00
IMAGE_SIZE="28G"
2026-05-12 19:26:35 +02:00
CLAWDIE_REF="${CLAWDIE_REF:-main}"
DEFAULT_PKG_BRANCH="latest"
FEATURE_TAILSCALE="${FEATURE_TAILSCALE:-YES}"
2026-03-24 00:51:22 +00:00
```
2026-05-12 19:26:35 +02:00
Notes:
2026-03-24 00:51:22 +00:00
2026-05-12 19:26:35 +02:00
- Host pkg repo branch and ISO package branch are independent.
- `DEFAULT_PKG_BRANCH=latest` is the ISO package source by default.
2026-05-24 23:21:02 +02:00
- Provider keys, Telegram, and disk deployment are deferred on this branch.
---
## Packages Deferred to Disk Install
The live operator USB is intentionally a lean substrate: bring up the
desktop, the browser, the agent CLIs, networking, and jails — nothing
more. Packages listed below are fetched into the offline repository via
`packages/pkg-list-disk-install-extras.txt` , but are intentionally not
installed onto the live rootfs.
**Two distinct categories live in the same file** with the same code
path (fetched, not installed on live), but different long-term homes:
2026-06-17 14:56:38 +02:00
1. **Desktop-spin leftovers** (telegram-desktop, mpv, abiword,
2026-05-24 23:21:02 +02:00
simplescreenrecorder, …). Inherited from the earlier all-in-one
desktop image. Don't match the operator-USB role. **Long-term home:
disk-install only.** Not returning to the live USB.
2. **Roadmap-essential, deferred for stabilization** (`blender` ).
First-class operator capability, not a leftover. Clawdie's product
scope explicitly covers parametric design → CAD/CAM → CNC fabrication
for OSA-style geodesic work
([osa.smilepowered.org ](https://osa.smilepowered.org/ )), and
Blender's bundled `bpy` Python module is the skill substrate for
those workflows. Held off the live USB for now only because its
ffmpeg/libpulse/mesa-libs/boost surface would partially un-do the
lean-rootfs payoff we want during the early hardware-validation
cycle. **Long-term home: back on the live USB** once dependency
docs: rewrite negative patterns to positive actionable instructions
Convert 'do not' / 'never' / 'avoid' / 'cannot' / 'must not' patterns
into positive 'do ABC to achieve XYZ' instructions across four key docs.
Files changed:
- AGENTS.md: role restrictions, linux constraints, formatting gate,
private workspace, scratch paths, mount discipline, source-of-truth
- BUILD.md: colibri compilation, mini-binary policy, USB flashing,
SSH-key distribution, mDNS scope, PF logging, host disk policy
- skills/iso-build/SKILL.md: build gating, CLI policy, command chaining,
tmux workflow, colibri preflight/cargo-clean timing, SDDM retention
- PLAN-OPERATOR-USB-NEXT.md: SDDM contract, package categorization,
bhyve gating, dashboard dependencies, seed checkout exclusions
Safety-critical constraints (USB whole-disk flashing, verified artifacts
only) are preserved with positive rephrasing that keeps the constraint
intact.
2026-06-21 13:13:08 +02:00
surface is audited and operator workflow exists. Classify it as
roadmap-essential in all future audits, not desktop-spin cruft.
2026-05-24 23:21:02 +02:00
**Intent:** keep this table as the authoritative "what we will deploy
to disk" reference so the work is not lost between commits. The
disk-install consumer still needs to install
`pkg-list-disk-install-extras.txt` when that path lands.
| Package | Role | Direct pkg size | Installed size | Category |
| ---------------------- | ------------------------------------------------------ | -----------------------------: | -------------: | ----------------- |
| `blender` | Parametric 3D modelling + Python `bpy` skill substrate | (large; measure on next image) | (large) | roadmap-essential |
| `telegram-desktop` | Messaging | 52.08 MiB | 236.90 MiB | leftover |
| `abiword` | Word processor | 4.75 MiB | 21.60 MiB | leftover |
| `mpv` | Media player | 1.60 MiB | 6.96 MiB | leftover |
| `simplescreenrecorder` | Screen/audio capture | 1.31 MiB | 3.83 MiB | leftover |
| `xls2txt` | Spreadsheet text converter | 0.55 MiB | 2.14 MiB | leftover |
| `antiword` | `.doc` text converter | 0.15 MiB | 0.65 MiB | leftover |
| `epdfview` | PDF viewer | 0.12 MiB | 0.40 MiB | leftover |
| `catdoc` | `.doc` / `.xls` converter | 0.08 MiB | 0.60 MiB | leftover |
| `p5-docx2txt` | `.docx` converter | 0.02 MiB | 0.06 MiB | leftover |
| `odt2txt` | `.odt` converter | 0.02 MiB | 0.04 MiB | leftover |
Removing the leftover bundle from the live USB shrinks the image and
drops the PulseAudio + PipeWire transitive surface — see "Audio surface
implications" below. The bundle is still useful on a full installed
operator desktop, hence **deferred** rather than **deleted** .
Blender's deferral is different: it's a _commitment_ to the
CNC/parametric-fabrication roadmap, parked off the live USB only until
the dep-set audit completes.
### Audio surface implications
The audio stack is the main architectural payoff of the bundle move and
Firefox browser swap, separate from the size win. Confirmed by direct
2026-06-13 11:38:28 +02:00
package-dep inspection. The `qt6-*` /`kf6-*` entries below are transitive package
dependencies from desktop applications, not an installer direction:
2026-05-24 23:21:02 +02:00
| Package | Pulls in (audio-relevant) |
| ---------------------- | ---------------------------------------------------------------------------------- |
| `telegram-desktop` | `qt6-declarative` , `qt6-wayland` , `qt6-svg` , `qt6-lottie` , `kf6-*` , ** `pipewire` ** |
| `simplescreenrecorder` | ** `pulseaudio` **, ** `pipewire` **, `qt6-base` , `ffmpeg` |
| `mpv` | `ffmpeg` , `libplacebo` , `mesa-libs` , `wayland` , `vulkan-loader` |
| `abiword` | `goffice` , `libgsf` , `wv` |
`simplescreenrecorder` is the worst offender — a single niche tool drags
in both the PulseAudio daemon _and_ the PipeWire daemon. Removing the
bundle from the live rootfs restores the FreeBSD-native OSS default by
construction, not by config-tuning.
Replacing Chromium with Firefox also removes the Chromium →
`speech-dispatcher` → `pulseaudio` dependency chain. Firefox keeps a
modern browser on the live USB without installing the PulseAudio daemon.
`xfce4-mixer` 's GStreamer-plugin chain typically pulls
`gstreamer1-plugins-pulse` . This is the remaining live-USB libpulse
puller after the bundle move and is tracked under "Audit candidates"
below.
### Audit candidates (live USB, keep for now)
These stay on the live USB, but they're flagged for a second-pass audit
once the desktop is proven stable on hardware:
| Package | Reason to revisit |
| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `xfce4-mixer` | wraps GStreamer; the GStreamer plugin bundle on FreeBSD typically pulls libpulse. The OSS-native intent of picking xfce4-mixer is partially undermined by this. Replacement candidates: `mixer(8)` from a terminal launcher, or a tiny OSS-only mixer applet. |
| `pcmanfm` | file-manager fallback while `xfdesktop` reliability is being validated. Drop once `xfdesktop` is the proven path. |
| `bitchx` | IRC client; desktop-era leftover. Kept on the live USB for now — size impact is negligible (~few hundred KiB) and the operator may want a quick chat tool on a fresh boot. |
### Currently essential (both live and disk)
Listed for completeness so the lean/full split stays honest:
- **Desktop session:** `xfce4-desktop` , `xfce4-panel` , `xfce4-session` ,
`xfce4-settings` , `xfce4-wm` , `xfce4-terminal` ,
`xfce4-whiskermenu-plugin` , `sddm` , `xinit` , `xterm` .
- **GTK / desktop integration:** `gsettings-desktop-schemas` ,
`adwaita-icon-theme` , `adwaita-icon-theme-legacy` ,
`gtk-update-icon-cache` , `shared-mime-info` , `desktop-file-utils` .
- **Browser + agent runtime:** `firefox` , `node24` , `npm-node24` (with
bundled `pi` npm globals). `codex` is included as a FreeBSD
pkg, not via npm. `claude-code` is excluded from the live image —
its native deps have no FreeBSD binary.
- **Networking:** `tailscale` , `networkmgr` , `wifi-firmware-kmod` ,
`FreeBSD-fwget` .
- **Jails:** `bastille` .
2026-06-17 14:56:38 +02:00
- **Operator diagnostics:** `tmux` , `screen` , `mc` , `zip` , `unzip` ,
2026-06-21 09:57:25 +02:00
`7-zip` , `python312` , `dejavu` , `py311-pillow` .
**Python:** `python3` is **3.11** (FreeBSD's `PYTHON_DEFAULT` ). `python312`
is also installed and available as `python3.12` for anything that needs
newer. The image-render / screenshot skill uses `py311-pillow` (works on
`python3` ); `clawdie-join-hive.sh` advertises `image-render` when Pillow
imports and `screenshot` when a display is present.
2026-06-21 09:36:28 +02:00
2026-05-24 23:21:02 +02:00
- **Xorg base:** `xorg-minimal` , `xkeyboard-config` , `xkbcomp` ,
`xf86-input-libinput` , `xf86-video-scfb` , `xf86-video-intel` ,
`xf86-video-amdgpu` , `xf86-video-ati` , `drm-kmod` ,
`gpu-firmware-intel-kmod-geminilake` ,
`gpu-firmware-intel-kmod-kabylake` .
- **System bus:** `dbus` .
### Decisions implemented for next build
These decisions are now reflected in `packages/pkg-list-*.txt` and the
live XFCE launcher/mime defaults. The next build should validate the new
closure and hardware behavior.
| Decision | Status | Notes |
| ---------------------------------------------------------------------- | ----------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Drop `chromium` , add `firefox` | **implemented** | Browser swap applied in `packages/pkg-list-live-operator.txt` , `packages/pkg-list-jails.txt` , README, the bootstrap page, the launch helper, and the panel launcher. Firefox on FreeBSD avoids the Chromium → `speech-dispatcher` → `pulseaudio` chain. |
| Split deferred bundle into `packages/pkg-list-disk-install-extras.txt` | **implemented** | The list remains in `pkg_list_all()` so archives land in the offline repo, but is absent from `pkg_list_live_installer()` so it stays off the live rootfs. The future disk-install consumer still needs to install it explicitly. |
| `simplescreenrecorder` : defer or drop outright? | **deferred to disk extras for now** | Kept in `pkg-list-disk-install-extras.txt` with the rest of the desktop bundle so the package remains available offline; revisit before implementing the disk-install consumer. |
| PulseAudio installable as an option on disk-install target? | **open** | On the live USB the answer is "no daemon, OSS default." On the _installed_ operator desktop, do we ship `pulseaudio` as an opt-in install (e.g. via a setup-time toggle, or as part of `pkg-list-disk-install-extras.txt` ), or commit to FreeBSD-native OSS/sndio across the board? Decision affects whether the deferred-bundle file should include `pulseaudio` as an explicit entry. |
2026-03-24 00:51:22 +00:00
2026-05-12 19:26:35 +02:00
---
2026-03-24 00:51:22 +00:00
2026-05-12 19:26:35 +02:00
## Build Process
docs: announce Tailscale mandatory, --target flag, glasspane, repo unification (Sam & Claude)
- README: rewrite for unified iso repo, two targets, mandatory Tailscale pre-req
- BUILD: add Step 0 (auth key), --target flag, --insecure-no-tailscale, first boot Tailscale screen 1
- AGENTS: note clawdie-shell archived, clawdie-iso is canonical, point to PLAN-UNIFY.md
2026-04-06 03:44:02 +00:00
2026-05-12 19:26:35 +02:00
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.
2026-05-24 23:21:02 +02:00
6. Inject firstboot scripts, packages, XFCE live-session assets, bundled npm
globals, Clawdie-AI tarball, build config, and manifest.
2026-05-12 19:26:35 +02:00
7. Copy the final sparse image into `tmp/output/` .
2026-03-24 00:51:22 +00:00
2026-05-12 19:26:35 +02:00
The build is intentionally cache-friendly. If in doubt before validation, run the
full `sudo ./build.sh` once after pulling current `main` .
2026-04-06 11:45:12 +02:00
2026-06-21 12:12:29 +02:00
### Build-host disk policy
When OSA gets tight on disk, prefer deleting **repo-local build artifacts**
(`tmp/packages` , `tmp/cache/work.img` , cached FreeBSD memstick images, old output
artifacts) over pruning host packages.
docs: rewrite negative patterns to positive actionable instructions
Convert 'do not' / 'never' / 'avoid' / 'cannot' / 'must not' patterns
into positive 'do ABC to achieve XYZ' instructions across four key docs.
Files changed:
- AGENTS.md: role restrictions, linux constraints, formatting gate,
private workspace, scratch paths, mount discipline, source-of-truth
- BUILD.md: colibri compilation, mini-binary policy, USB flashing,
SSH-key distribution, mDNS scope, PF logging, host disk policy
- skills/iso-build/SKILL.md: build gating, CLI policy, command chaining,
tmux workflow, colibri preflight/cargo-clean timing, SDDM retention
- PLAN-OPERATOR-USB-NEXT.md: SDDM contract, package categorization,
bhyve gating, dashboard dependencies, seed checkout exclusions
Safety-critical constraints (USB whole-disk flashing, verified artifacts
only) are preserved with positive rephrasing that keeps the constraint
intact.
2026-06-21 13:13:08 +02:00
Preserve the remaining host-side graphics/media stack; it supports current
operator tooling and validation lanes, not an old X11 desktop:
2026-06-21 12:12:29 +02:00
- `ffmpeg` + `py311-pillow` back the Hermes/image-render and screenshot path.
- `gtk3` , `cairo` , `pango` , `fontconfig` , `libX11` , `mesa-*` , `wayland` ,
`wlroots` , and related libs are shared by Codex-adjacent tooling, VNC/screenshot
helpers, media/rendering packages, and Python operator tools.
- Dry-run package removal on OSA showed that reclaiming this subtree would remove
2026-06-21 12:17:57 +02:00
far more than a stale desktop: `Codex` , `ffmpeg` , `py311-pillow` , ImageMagick,
2026-06-21 12:12:29 +02:00
graphviz, aider-adjacent Python packages, and remote-display helpers all rode on
the same dependency closure.
2026-06-21 12:17:57 +02:00
In practice: if you need gigabytes quickly, clear build caches first:
2026-06-21 12:24:51 +02:00
sudo rm -rf tmp/packages tmp/cache tmp/output
2026-06-21 12:17:57 +02:00
These caches typically reclaim 3-8 GB. If host pkg pressure becomes chronic,
that is a signal to move more build/package work onto
`mother-build` (PLANNED — see docs/POUDRIERE-BUILD-SERVER.md), not to hollow
out the FreeBSD operator host.
Note: OSA's `/tmp` is a ZFS dataset separate from build caches. If shell
commands fail with "No space left on device" during agent operations, clear
`/tmp` independently:
sudo rm -rf /tmp/*
2026-06-21 12:12:29 +02:00
2026-05-12 19:26:35 +02:00
---
2026-03-24 00:51:22 +00:00
2026-05-24 23:21:02 +02:00
## Boot Flow Produced by the Image
2026-03-26 14:03:08 +00:00
2026-05-24 23:21:02 +02:00
1. USB boots to XFCE live session.
2. `/usr/local/etc/rc.d/clawdie_live_gpu` runs before SDDM and selects a conservative GPU path.
3. SDDM presents the greeter; the operator logs in as `clawdie` to launch the Clawdie XFCE session.
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.
2026-05-12 19:26:35 +02:00
---
2026-03-26 14:03:08 +00:00
2026-05-12 19:26:35 +02:00
## Testing
2026-03-26 14:03:08 +00:00
2026-06-04 18:55:55 +02:00
Default verification order for the operator USB is now:
1. static artifact verification on the build host
2. bhyve boot verification on the ML350p virtualization lane
3. physical hardware validation for the final acceptance pass
Use bhyve before writing to hardware whenever the lane is available:
2026-03-26 14:03:08 +00:00
2026-05-12 19:26:35 +02:00
```sh
2026-04-04 09:49:01 +00:00
sudo ./scripts/bhyve-pf-allow.sh
feat(firstboot): resume/reset flags, checkpoint guards + move bhyve scripts
firstboot.sh:
- Set SHELL_{GPU,NVIDIA,PKG,ENV,DEPLOY}_TEST=1 before sourcing modules
(prevents double-execution on source — same bug fixed in integration-test)
- Add --resume: run_step() skips steps already recorded in progress file
- Add --reset: clears progress file, starts over from scratch
- Add --help
- Wizard tracked as checkpoint so --resume skips re-prompting the user
- run_step() helper: guard → run → mark done in one call
scripts/bhyve-test.sh (was tmp/bhyve-test-setup.sh):
- Moved to tracked scripts/ directory (tmp/ is gitignored)
- Timeout 300→1800s (full install is 20–25 min, not 5)
scripts/run-bhyve-test.sh (was tmp/run-bhyve-test.sh):
- Moved to scripts/, log output redirected to logs/ (also gitignored)
BUILD.md, TESTING.md, IMPLEMENTATION-PLAN.md:
- Update all bhyve script references to scripts/bhyve-test.sh
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-30 13:00:24 +00:00
sudo ./scripts/bhyve-test.sh
2026-05-12 19:26:35 +02:00
```
2026-06-04 18:55:55 +02:00
Current ML350p bhyve plan:
- host RAM budget: ZFS ARC 6G + Poudriere tmpfs 4G + headroom 6G
- bhyve RAM budget: FreeBSD ISO test 4G + Linux cross-compile 4G + FreeBSD builder 4G + spare 4G
- intended VM roles:
- ISO boot verification after each build
- Linux target validation
- FreeBSD/Poudriere test lane
Use bhyve to catch boot, SDDM/XFCE, and service-start regressions early. Keep
real hardware as the final proof for GPU quirks, Wi-Fi, audio, touchpad, and
display/panel behavior.
2026-05-12 19:26:35 +02:00
See [TESTING.md ](TESTING.md ) for the full validation checklist.
2026-03-26 14:03:08 +00:00
---
2026-03-24 00:51:22 +00:00
## Troubleshooting
2026-05-12 19:26:35 +02:00
**`ERROR: missing package archive for <pkg>` **
2026-03-24 00:51:22 +00:00
2026-05-12 19:26:35 +02:00
A package was added after your cache was created. Run a full fetch/build:
2026-03-24 00:51:22 +00:00
2026-05-12 19:26:35 +02:00
```sh
sudo ./build.sh
```
2026-03-24 00:51:22 +00:00
2026-05-12 19:26:35 +02:00
**`pkg` not found during unprivileged fetch**
2026-03-24 00:51:22 +00:00
2026-05-12 19:26:35 +02:00
`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.
2026-03-24 00:51:22 +00:00
2026-05-12 19:26:35 +02:00
**`npm ci` falls back to `npm install` **
2026-03-24 00:51:22 +00:00
2026-05-12 19:26:35 +02:00
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.
2026-03-24 00:51:22 +00:00
2026-05-12 19:26:35 +02:00
**Image says small allocated size**
2026-03-24 00:51:22 +00:00
2026-05-12 19:26:35 +02:00
The image is sparse on the build host. Use the logical image size when choosing
a USB key.
2026-03-24 00:51:22 +00:00
---
2026-05-24 23:21:02 +02:00
**Last updated:** 16.maj.2026