From cf1c58a95c0c1bf7b6937abf2ff43c2588fcf2ad Mon Sep 17 00:00:00 2001 From: Sam & Claude Date: Tue, 2 Jun 2026 08:34:52 +0200 Subject: [PATCH] feat: stage the simplified `clawdie` agent into the ISO (Sam & Claude) Adds an opt-in FEATURE_CLAWDIE lane that stages the new one-binary clawdie agent (glasspane + herdr + DeepSeek/Telegram) from the shared ../colibri checkout, alongside the existing Colibri daemon staging. - build.cfg: FEATURE_CLAWDIE (default NO), CLAWDIE_ARTIFACT_DIR, CLAWDIE_ENABLE, plus build-flag credential notes. - scripts/stage-clawdie-iso.sh: install clawdie binary + rc.d + rc.conf sample + optional clawdie.env override template. - build.sh: resolve_clawdie_paths, preflight_clawdie_artifacts, install_clawdie_service (creates clawdie user/group, enables rc.d like Clawdie-AI), status line, and call-site wiring. Gated; default build unchanged. - iso-build skill: clawdie preflight section + a "carry the XFCE operator-USB fixes" reminder for the next build (SDDM-over-LightDM, clawdie-live-gpu KMS, hardened USB power policy). sh -n clean on build.sh and stage-clawdie-iso.sh; markdown gate clean on touched files. Co-Authored-By: Claude Opus 4.8 --- build.cfg | 13 +++++ build.sh | 101 +++++++++++++++++++++++++++++++++ scripts/stage-clawdie-iso.sh | 107 +++++++++++++++++++++++++++++++++++ skills/iso-build/SKILL.md | 46 +++++++++++++++ 4 files changed, 267 insertions(+) create mode 100755 scripts/stage-clawdie-iso.sh diff --git a/build.cfg b/build.cfg index 399a78be..d339d056 100644 --- a/build.cfg +++ b/build.cfg @@ -81,6 +81,19 @@ COLIBRI_ARTIFACT_DIR="${COLIBRI_ARTIFACT_DIR:-}" COLIBRI_DAEMON_ENABLE="${COLIBRI_DAEMON_ENABLE:-NO}" COLIBRI_COST_MODE="${COLIBRI_COST_MODE:-smart}" +# Clawdie agent — the simplified, operator-friendly Colibri lane. +# One small Rust binary (glasspane + herdr + DeepSeek/Telegram), built from the +# same ../colibri checkout. Opt-in (default NO) so it does not disturb the +# current default build; flip to YES for the simplified operator image. +# The two credentials are normally baked into the binary at build time: +# (cd ../colibri && CLAWDIE_TG_TOKEN=... CLAWDIE_DEEPSEEK_KEY=... \ +# cargo build --release -p clawdie) +# Leave them blank to ship a "bring your own key" binary configured via the +# rc.d env file (/usr/local/etc/clawdie/clawdie.env) at runtime instead. +FEATURE_CLAWDIE="${FEATURE_CLAWDIE:-NO}" +CLAWDIE_ARTIFACT_DIR="${CLAWDIE_ARTIFACT_DIR:-}" +CLAWDIE_ENABLE="${CLAWDIE_ENABLE:-YES}" + # Local LLM runtime (optional) # Choices: none | ollama | llama_cpp LOCAL_LLM_PROVIDER="${LOCAL_LLM_PROVIDER:-none}" diff --git a/build.sh b/build.sh index cb2f1e36..00a89bd1 100755 --- a/build.sh +++ b/build.sh @@ -121,6 +121,7 @@ echo " Pkg : ${DEFAULT_PKG_BRANCH}" echo " GPU : ${GPU_DRIVER:-auto-detect}" echo " Target : ${TARGET:-baremetal}" echo " Colibri : ${FEATURE_COLIBRI:-NO}" +echo " Clawdie : ${FEATURE_CLAWDIE:-NO}" echo "" # Name the output for the thing we are actually building. @@ -310,6 +311,41 @@ preflight_colibri_artifacts() { done } +# clawdie shares the ../colibri checkout; CLAWDIE_ARTIFACT_DIR overrides where +# the prebuilt `clawdie` binary is found. +resolve_clawdie_paths() { + resolve_colibri_paths + _resolved_clawdie_repo="${_resolved_colibri_repo}" + if [ -n "${CLAWDIE_ARTIFACT_DIR:-}" ]; then + _resolved_clawdie_artifact_dir="${CLAWDIE_ARTIFACT_DIR}" + case "${_resolved_clawdie_artifact_dir}" in + /*) ;; + *) _resolved_clawdie_artifact_dir="${SCRIPT_DIR}/${_resolved_clawdie_artifact_dir}" ;; + esac + else + _resolved_clawdie_artifact_dir="${_resolved_clawdie_repo}/target/release" + fi +} + +preflight_clawdie_artifacts() { + [ "${FEATURE_CLAWDIE:-NO}" = "YES" ] || return 0 + [ "${FETCH_ONLY:-0}" -eq 0 ] || return 0 + + resolve_clawdie_paths + _clawdie_rc="${_resolved_clawdie_repo}/packaging/freebsd/clawdie.in" + if [ ! -f "${_clawdie_rc}" ]; then + echo "ERROR: clawdie rc.d source missing: ${_clawdie_rc}" + echo " Set COLIBRI_REPO=/path/to/colibri or FEATURE_CLAWDIE=NO." + exit 1 + fi + if [ ! -x "${_resolved_clawdie_artifact_dir}/clawdie" ]; then + echo "ERROR: clawdie release binary missing: ${_resolved_clawdie_artifact_dir}/clawdie" + echo " Build first: (cd ${_resolved_clawdie_repo} && cargo build --release -p clawdie)" + echo " Or set FEATURE_CLAWDIE=NO to skip clawdie staging." + exit 1 + fi +} + override_networkmgr_package() { _networkmgr_pkg=$(find "${PKG_REPO_DIR}/All/Hashed" -maxdepth 1 -type f -name 'networkmgr-*.pkg' | sort | tail -1) if [ -z "${_networkmgr_pkg:-}" ]; then @@ -745,6 +781,69 @@ install_colibri_service() { fi } +install_clawdie_service() { + [ "${FEATURE_CLAWDIE:-NO}" = "YES" ] || { + echo " Clawdie agent staging disabled (FEATURE_CLAWDIE=${FEATURE_CLAWDIE:-NO})" + return 0 + } + + echo " Staging Clawdie agent..." + + resolve_clawdie_paths + + env \ + COLIBRI_REPO="${_resolved_clawdie_repo}" \ + CLAWDIE_ARTIFACT_DIR="${_resolved_clawdie_artifact_dir}" \ + CLAWDIE_STAGE_ENABLE="${CLAWDIE_ENABLE:-YES}" \ + "${SCRIPT_DIR}/scripts/stage-clawdie-iso.sh" "${MOUNT_POINT}" + + if ! /usr/sbin/pw -R "${MOUNT_POINT}" groupshow clawdie >/dev/null 2>&1; then + /usr/sbin/pw -R "${MOUNT_POINT}" groupadd clawdie + fi + if ! /usr/sbin/pw -R "${MOUNT_POINT}" usershow clawdie >/dev/null 2>&1; then + /usr/sbin/pw -R "${MOUNT_POINT}" useradd clawdie \ + -g clawdie \ + -d /var/db/clawdie \ + -s /usr/sbin/nologin \ + -c "Clawdie Agent" + fi + + mkdir -p \ + "${MOUNT_POINT}/var/db/clawdie" \ + "${MOUNT_POINT}/var/run/clawdie" \ + "${MOUNT_POINT}/var/log/clawdie" + chroot "${MOUNT_POINT}" chown -R clawdie:clawdie \ + /var/db/clawdie \ + /var/run/clawdie \ + /var/log/clawdie + chmod 0750 \ + "${MOUNT_POINT}/var/db/clawdie" \ + "${MOUNT_POINT}/var/run/clawdie" \ + "${MOUNT_POINT}/var/log/clawdie" + + set_config_line "${MOUNT_POINT}/etc/rc.conf" "clawdie_enable=\"${CLAWDIE_ENABLE:-YES}\"" + set_config_line "${MOUNT_POINT}/etc/rc.conf" 'clawdie_user="clawdie"' + set_config_line "${MOUNT_POINT}/etc/rc.conf" 'clawdie_group="clawdie"' + set_config_line "${MOUNT_POINT}/etc/rc.conf" 'clawdie_data_dir="/var/db/clawdie"' + set_config_line "${MOUNT_POINT}/etc/rc.conf" 'clawdie_run_dir="/var/run/clawdie"' + set_config_line "${MOUNT_POINT}/etc/rc.conf" 'clawdie_socket="/var/run/clawdie/clawdie.sock"' + set_config_line "${MOUNT_POINT}/etc/rc.conf" 'clawdie_logfile="/var/log/clawdie/clawdie.log"' + set_config_line "${MOUNT_POINT}/etc/rc.conf" 'clawdie_host="$(hostname)"' + + if [ ! -x "${MOUNT_POINT}/usr/local/bin/clawdie" ]; then + echo "ERROR: clawdie binary missing from live image" + exit 1 + fi + if [ ! -x "${MOUNT_POINT}/usr/local/etc/rc.d/clawdie" ]; then + echo "ERROR: clawdie rc.d script missing from live image" + exit 1 + fi + if ! /usr/sbin/pw -R "${MOUNT_POINT}" usershow clawdie >/dev/null 2>&1; then + echo "ERROR: clawdie service user missing from live image" + exit 1 + fi +} + install_live_npm_globals() { echo " Installing bundled npm globals into live image..." @@ -1517,6 +1616,7 @@ EOF } preflight_colibri_artifacts +preflight_clawdie_artifacts # --- step 1: fetch FreeBSD memstick --- MEMSTICK="${CACHE_DIR}/FreeBSD-${FREEBSD_VERSION}-${FREEBSD_ARCH}-memstick.img" @@ -1907,6 +2007,7 @@ rm -f "${MOUNT_POINT}/etc/installerconfig" install_live_runtime_packages configure_live_operator_session install_colibri_service +install_clawdie_service # Copy payload # Rebuild payload paths from scratch inside the reusable work image. A failed diff --git a/scripts/stage-clawdie-iso.sh b/scripts/stage-clawdie-iso.sh new file mode 100755 index 00000000..dcbbc10d --- /dev/null +++ b/scripts/stage-clawdie-iso.sh @@ -0,0 +1,107 @@ +#!/bin/sh +# Stage the prebuilt `clawdie` FreeBSD binary + rc.d service into an image root. +# +# `clawdie` is the simplified, operator-friendly Colibri agent: one small binary +# (glasspane + herdr + DeepSeek/Telegram). This script does NOT build it — build +# or provide the artifact first, optionally with baked credentials: +# +# (cd ../colibri && CLAWDIE_TG_TOKEN=... CLAWDIE_DEEPSEEK_KEY=... \ +# cargo build --release -p clawdie) +# +# Usage: +# COLIBRI_REPO=../colibri scripts/stage-clawdie-iso.sh /path/to/image-root +# CLAWDIE_ARTIFACT_DIR=/path/to/release scripts/stage-clawdie-iso.sh /path/to/image-root + +set -eu + +if [ "${1:-}" = "" ]; then + echo "usage: $0 DESTDIR" >&2 + exit 64 +fi + +DESTDIR=$1 +SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) +REPO_ROOT=$(CDPATH= cd -- "${SCRIPT_DIR}/.." && pwd) +COLIBRI_REPO=${COLIBRI_REPO:-"${REPO_ROOT}/../colibri"} +CLAWDIE_ARTIFACT_DIR=${CLAWDIE_ARTIFACT_DIR:-"${COLIBRI_REPO}/target/release"} +CLAWDIE_STAGE_ENABLE=${CLAWDIE_STAGE_ENABLE:-YES} + +BIN_DIR="${DESTDIR}/usr/local/bin" +RC_DIR="${DESTDIR}/usr/local/etc/rc.d" +ETC_DIR="${DESTDIR}/usr/local/etc/clawdie" +DB_DIR="${DESTDIR}/var/db/clawdie" +RUN_DIR="${DESTDIR}/var/run/clawdie" +LOG_DIR="${DESTDIR}/var/log/clawdie" +RC_SOURCE="${COLIBRI_REPO}/packaging/freebsd/clawdie.in" + +require_file() { + if [ ! -f "$1" ]; then + echo "missing required clawdie artifact: $1" >&2 + exit 66 + fi +} + +require_exec() { + if [ ! -x "$1" ]; then + echo "missing executable clawdie artifact: $1" >&2 + echo "hint: (cd ${COLIBRI_REPO} && cargo build --release -p clawdie)" >&2 + exit 66 + fi +} + +require_file "${RC_SOURCE}" +require_exec "${CLAWDIE_ARTIFACT_DIR}/clawdie" +mkdir -p "${BIN_DIR}" "${RC_DIR}" "${ETC_DIR}" "${DB_DIR}" "${RUN_DIR}" "${LOG_DIR}" + +install -m 0555 "${CLAWDIE_ARTIFACT_DIR}/clawdie" "${BIN_DIR}/clawdie" +install -m 0555 "${RC_SOURCE}" "${RC_DIR}/clawdie" + +cat > "${ETC_DIR}/rc.conf.sample" < "${ETC_DIR}/clawdie.env.sample" <<'EOF' +# Optional per-host credential overrides for clawdie. +# Copy to clawdie.env (chmod 0600) to override the baked build-flag values. +# CLAWDIE_TG_TOKEN=123456:telegram-bot-token +# CLAWDIE_DEEPSEEK_KEY=sk-deepseek-key +EOF +fi + +cat > "${ETC_DIR}/README.iso" <<'EOF' +Clawdie agent ISO staging notes +=============================== + +The ISO build creates the clawdie user/group and enables the rc.d service +according to build.cfg. Out of the box clawdie offers exactly: a Telegram bot +and a DeepSeek lane — both normally baked at build time. Runtime validation: + + service clawdie start + service clawdie status + sockstat | grep clawdie # Herdr socket bound + service clawdie stop + +Lifted on purpose: cost modes, quotas, multi-provider fallback, per-user limits. +EOF + +chmod 0750 "${DB_DIR}" "${RUN_DIR}" "${LOG_DIR}" + +cat <