From 7704fae71790c929ed50051caf73db5e152d1b69 Mon Sep 17 00:00:00 2001 From: Sam & Claude Date: Sat, 13 Jun 2026 10:33:37 +0200 Subject: [PATCH] feat(iso): stage zot agent (pinned) + populate ZOT_HOME/auth.json (Sam & Claude) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit First concrete step of the zot consolidation (colibri ADR). Opt-in FEATURE_ZOT (default NO; Pi stays default during migration). - build.cfg: FEATURE_ZOT, ZOT_VERSION (pinned v0.2.29), ZOT_REPO, ZOT_ARTIFACT_DIR, ZOT_DEEPSEEK_KEY (optional bake). - scripts/stage-zot-iso.sh: install the prebuilt zot binary -> /usr/local/bin/zot; populate the operator's $ZOT_HOME (~/.local/state/zot) with auth.json ({"deepseek":{"api_key":...}}, 0600) when a key is given, else an auth.json.sample template + README (telegram via `zot telegram-bot setup`). - build.sh: status line, resolve_zot_paths, preflight_zot_artifacts (errors with the GOOS=freebsd go-build hint — zot has no FreeBSD release), install_zot_agent (+ chown operator state), wired into preflight + install sequences. zot is built on the FreeBSD host from the pinned tag: (cd $ZOT_REPO && git checkout v0.2.29 && GOOS=freebsd GOARCH=amd64 \ go build -trimpath -o bin/zot ./cmd/zot) sh -n clean; staging smoke-tested (binary staged, auth.json 0600 valid). Credentials use zot's own resolution (--api-key -> env -> auth.json), replacing baked-into-binary keys. Default build unchanged (FEATURE_ZOT=NO). Co-Authored-By: Claude Opus 4.8 --- build.cfg | 16 ++++++++ build.sh | 61 +++++++++++++++++++++++++++ scripts/stage-zot-iso.sh | 89 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 166 insertions(+) create mode 100755 scripts/stage-zot-iso.sh diff --git a/build.cfg b/build.cfg index 591cc41f..de2b60a2 100644 --- a/build.cfg +++ b/build.cfg @@ -116,6 +116,22 @@ FEATURE_CLAWDIE="${FEATURE_CLAWDIE:-NO}" CLAWDIE_ARTIFACT_DIR="${CLAWDIE_ARTIFACT_DIR:-}" CLAWDIE_ENABLE="${CLAWDIE_ENABLE:-NO}" +# zot agent harness (the consolidation target — see colibri ADR +# docs/ADR-agent-harness-consolidation.md). zot is a single static Go binary +# (providers incl. DeepSeek, Telegram bot, json/rpc modes, SKILL.md, extensions). +# Opt-in (default NO) while Pi stays the default harness during migration. +# Pin a tag for reproducible images; zot has no FreeBSD release, so the build +# host compiles it: (cd $ZOT_REPO && git checkout $ZOT_VERSION && +# GOOS=freebsd GOARCH=amd64 go build -trimpath -o bin/zot ./cmd/zot) +FEATURE_ZOT="${FEATURE_ZOT:-NO}" +ZOT_VERSION="${ZOT_VERSION:-v0.2.29}" +ZOT_REPO="${ZOT_REPO:-/home/clawdie/ai/zot}" +ZOT_ARTIFACT_DIR="${ZOT_ARTIFACT_DIR:-}" +# Optional: bake the operator's DeepSeek key into $ZOT_HOME/auth.json (0600). +# Leave blank to stage an auth.json.sample template the operator fills in, or +# to configure at runtime via `zot` env / `zot telegram-bot setup`. +ZOT_DEEPSEEK_KEY="${ZOT_DEEPSEEK_KEY:-}" + # 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 368df710..3f8902d2 100755 --- a/build.sh +++ b/build.sh @@ -123,6 +123,7 @@ echo " NVIDIA universal : ${NVIDIA_UNIVERSAL:-NO}" echo " Target : ${TARGET:-baremetal}" echo " Colibri : ${FEATURE_COLIBRI:-NO}" echo " Clawdie agent : ${FEATURE_CLAWDIE:-NO}" +echo " zot agent : ${FEATURE_ZOT:-NO} (${ZOT_VERSION:-})" echo "" # Name the output for the thing we are actually building. @@ -371,6 +372,38 @@ preflight_clawdie_artifacts() { fi } +resolve_zot_paths() { + _resolved_zot_repo="${ZOT_REPO:-${SCRIPT_DIR}/../zot}" + case "${_resolved_zot_repo}" in + /*) ;; + *) _resolved_zot_repo="${SCRIPT_DIR}/${_resolved_zot_repo}" ;; + esac + if [ -n "${ZOT_ARTIFACT_DIR:-}" ]; then + _resolved_zot_artifact_dir="${ZOT_ARTIFACT_DIR}" + case "${_resolved_zot_artifact_dir}" in + /*) ;; + *) _resolved_zot_artifact_dir="${SCRIPT_DIR}/${_resolved_zot_artifact_dir}" ;; + esac + else + _resolved_zot_artifact_dir="${_resolved_zot_repo}/bin" + fi +} + +preflight_zot_artifacts() { + [ "${FEATURE_ZOT:-NO}" = "YES" ] || return 0 + [ "${FETCH_ONLY:-0}" -eq 0 ] || return 0 + + resolve_zot_paths + if [ ! -x "${_resolved_zot_artifact_dir}/zot" ]; then + echo "ERROR: zot binary missing: ${_resolved_zot_artifact_dir}/zot" + echo " zot has no FreeBSD release — build it first:" + echo " (cd ${_resolved_zot_repo} && git checkout ${ZOT_VERSION:-v0.2.29} && \\" + echo " GOOS=freebsd GOARCH=amd64 go build -trimpath -o bin/zot ./cmd/zot)" + echo " Or set FEATURE_ZOT=NO to skip zot 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 @@ -854,6 +887,32 @@ install_colibri_service() { fi } +install_zot_agent() { + [ "${FEATURE_ZOT:-NO}" = "YES" ] || { + echo " zot agent staging disabled (FEATURE_ZOT=${FEATURE_ZOT:-NO})" + return 0 + } + + echo " Staging zot agent (${ZOT_VERSION:-})..." + resolve_zot_paths + + env \ + ZOT_ARTIFACT_DIR="${_resolved_zot_artifact_dir}" \ + ZOT_OPERATOR="clawdie" \ + ZOT_DEEPSEEK_KEY="${ZOT_DEEPSEEK_KEY:-}" \ + "${SCRIPT_DIR}/scripts/stage-zot-iso.sh" "${MOUNT_POINT}" + + # zot state lives in the operator's home; own it as the operator. + if /usr/sbin/pw -R "${MOUNT_POINT}" usershow clawdie >/dev/null 2>&1; then + chroot "${MOUNT_POINT}" chown -R clawdie:clawdie /home/clawdie/.local 2>/dev/null || true + fi + + if [ ! -x "${MOUNT_POINT}/usr/local/bin/zot" ]; then + echo "ERROR: zot binary missing from live image" + exit 1 + fi +} + install_clawdie_service() { [ "${FEATURE_CLAWDIE:-NO}" = "YES" ] || { echo " Clawdie agent staging disabled (FEATURE_CLAWDIE=${FEATURE_CLAWDIE:-NO})" @@ -1832,6 +1891,7 @@ EOF preflight_colibri_artifacts preflight_clawdie_artifacts +preflight_zot_artifacts # --- step 1: fetch FreeBSD memstick --- MEMSTICK="${CACHE_DIR}/FreeBSD-${FREEBSD_VERSION}-${FREEBSD_ARCH}-memstick.img" @@ -2223,6 +2283,7 @@ install_live_runtime_packages configure_live_operator_session install_colibri_service install_clawdie_service +install_zot_agent install_nvidia_universal_repo # Copy payload diff --git a/scripts/stage-zot-iso.sh b/scripts/stage-zot-iso.sh new file mode 100755 index 00000000..04181358 --- /dev/null +++ b/scripts/stage-zot-iso.sh @@ -0,0 +1,89 @@ +#!/bin/sh +# Stage the prebuilt `zot` agent binary + credentials into an image root. +# +# zot is the agent-harness consolidation target (one static Go binary). It has no +# FreeBSD release, so build it on the host first and point ZOT_ARTIFACT_DIR here: +# (cd ../zot && git checkout "$ZOT_VERSION" \ +# && GOOS=freebsd GOARCH=amd64 go build -trimpath -o bin/zot ./cmd/zot) +# +# Credentials: zot resolves provider keys as --api-key -> provider env var -> +# $ZOT_HOME/auth.json. This stages auth.json (DeepSeek) under the operator's +# default ZOT_HOME (~/.local/state/zot). The Telegram token is configured +# separately at runtime via `zot telegram-bot setup` (it lives in zot state). +# +# Usage: +# ZOT_ARTIFACT_DIR=/path/to/bin scripts/stage-zot-iso.sh /path/to/image-root + +set -eu + +if [ "${1:-}" = "" ]; then + echo "usage: $0 DESTDIR" >&2 + exit 64 +fi + +DESTDIR=$1 +ZOT_ARTIFACT_DIR=${ZOT_ARTIFACT_DIR:?set ZOT_ARTIFACT_DIR to the dir holding the built zot binary} +ZOT_OPERATOR=${ZOT_OPERATOR:-clawdie} +ZOT_DEEPSEEK_KEY=${ZOT_DEEPSEEK_KEY:-} + +BIN_SRC="${ZOT_ARTIFACT_DIR}/zot" +BIN_DIR="${DESTDIR}/usr/local/bin" +# zot's default ZOT_HOME on FreeBSD is ~/.local/state/zot +ZOT_HOME_REL=".local/state/zot" +OP_HOME="${DESTDIR}/home/${ZOT_OPERATOR}" +ZOT_HOME="${OP_HOME}/${ZOT_HOME_REL}" + +if [ ! -x "${BIN_SRC}" ]; then + echo "missing executable zot artifact: ${BIN_SRC}" >&2 + echo "hint: (cd \$ZOT_REPO && GOOS=freebsd GOARCH=amd64 go build -trimpath -o bin/zot ./cmd/zot)" >&2 + exit 66 +fi + +mkdir -p "${BIN_DIR}" "${ZOT_HOME}" +install -m 0555 "${BIN_SRC}" "${BIN_DIR}/zot" + +# auth.json: bake the DeepSeek key if provided (0600), else leave a template. +if [ -n "${ZOT_DEEPSEEK_KEY}" ]; then + umask 077 + cat > "${ZOT_HOME}/auth.json" < "${ZOT_HOME}/auth.json.sample" <<'EOF' +{ + "deepseek": { "api_key": "sk-REPLACE-ME" } +} +EOF + _cred_note="auth.json.sample staged (operator copies to auth.json, chmod 0600)" +fi + +cat > "${ZOT_HOME}/README.iso" < provider env -> auth.json): + - ${_cred_note} + - or export DEEPSEEK_API_KEY at runtime. + +Telegram bridge (token stored in zot state, not auth.json): + zot telegram-bot setup # paste BotFather token + zot telegram-bot start + +Supervision contract for Colibri glasspane: + zot --json "..." # newline-delimited json events + zot rpc # json-rpc loop +EOF + +cat <