#!/usr/bin/env bash # # Build the TWINNED core pair: the container host (Home Assistant + everything in # hosts/container-host/) and the LLM host (Ollama, hosts/llm-host/), as two ISOs that # already know about each other. # # WHAT "TWINNED" MEANS HERE, concretely: CoreSystemConfig.json states the subnet prefix # once and one last octet per host. Everything else is computed. The container host's # OLLAMA_HOST is the LLM host's address because both were derived from those numbers in # the same build — not because someone typed the same IP into two files and remembered # to keep them in sync. Move the LLM host from .13 to .21 and rebuild, and the # container host's Ollama URL follows on its own. Neither ISO can be built pointing at # an address the other one isn't using. # # Both images get a matching SMARTHOME_PAIR_ID in /etc/smarthome-build, so two ISOs on # two USB sticks can be checked against each other months later. # # Everything each host needs is burnt in: static network config, hostname, admin user, # SSH key, every service token, the generated env files, and this repo itself. The # machines come up configured, with no post-install editing of env files by hand. # # sudo -E tools/build-core-pair.sh # both # sudo -E tools/build-core-pair.sh container # just the container host # sudo -E tools/build-core-pair.sh llm # just the LLM host # # READ THIS BEFORE YOU BUILD: the resulting ISOs contain every secret in # CoreSystemConfig.json — Wi-Fi PSK, service tokens, MQTT and HA credentials, your # SSH public key. They are credential-bearing artifacts. .gitignore keeps them out of # the repo, but an ISO on a USB stick in a drawer is still every token in this # household. Treat them accordingly, and wipe sticks you stop using. set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # shellcheck source=lib/coreconfig.sh source "${SCRIPT_DIR}/lib/coreconfig.sh" TARGET="${1:-both}" case "$TARGET" in both|container|llm) ;; *) core_die "Usage: $0 [both|container|llm]" ;; esac core_load core_require_root "$TARGET" PAIR_ID="$(core_pair_id)" cat < Ollama : ${CORE_OLLAMA_HOST} kiosks -> Home Assistant : ${CORE_HA_URL} kiosks -> identity : ${CORE_IDENTITY_URL} kiosks -> MQTT : ${CORE_MQTT_BROKER_HOST}:${CORE_MQTT_BROKER_PORT} Building : ${TARGET} ============================================================================ EOF OUTPUT_DIR="${CORE_REPO_ROOT}/${CORE_BUILD_OUTPUT_DIR}" mkdir -p "$OUTPUT_DIR" if [[ "$TARGET" == "both" || "$TARGET" == "container" ]]; then core_log "Building the container host ISO" "${SCRIPT_DIR}/build-container-host-iso.sh" fi if [[ "$TARGET" == "both" || "$TARGET" == "llm" ]]; then core_log "Building the LLM host ISO" "${SCRIPT_DIR}/build-llm-host-iso.sh" fi cat < States). The shipped default is a guess, and it's the single highest-risk unknown in Phase 6. Then do the thing the split exists for: power the LLM host OFF and confirm the house still works. See hosts/llm-host/README.md. ============================================================================ EOF