From bea082a2014a3edc31cb006108b952c8adbbc8bc Mon Sep 17 00:00:00 2001 From: Jino Jose Date: Tue, 14 Jul 2026 12:06:49 +0530 Subject: [PATCH] Document installer release architecture --- README.md | 38 ++++++++++++++++++-- autoinstall/offline/README.md | 11 ++++++ autoinstall/offline/build-bundle.sh | 52 ++++++++++++++++++++-------- autoinstall/offline/verify-bundle.sh | 2 +- 4 files changed, 85 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 0ba274d..4bdd814 100644 --- a/README.md +++ b/README.md @@ -8,9 +8,10 @@ This repository is the source of truth for the Nexus One AI platform package, including installer flows, deployment roles, portal assets, backend services, licensing enforcement, and the bootable ISO build path. -The ISO is only one delivery surface. It stays small by pulling this package -from cgit during setup, then the installer deploys the selected tier and -feature set on the target server. +The ISO is one delivery surface. The online Server installer stays small by +pulling this package and the selected tier payload during setup. Offline +installers embed their approved platform payload and starter models, while +large models are delivered as separate signed model packs. ## Product Structure @@ -43,6 +44,37 @@ Powered by Cezen four tiers). See [Section 6](#6-tier-and-packaging-guide) and [Section 8](#8-features-by-tier). +## Installer Release Architecture + +Nexus One AI uses four bootable ISO products built from this shared codebase: + +| ISO | Connectivity | Selection and payload | Current status | +|---|---|---|---| +| Online Universal Server | Internet required during setup | Hardware/license preflight followed by Server S, M, L, or Max selection | Existing build path; validation continues | +| Offline Workstation | No internet required | Fixed Workstation category with the complete local platform and approved Workstation starter models | In development | +| Offline Server S/M | No internet required | Server S or M selected from hardware and license; small/medium local payload | Planned | +| Offline Server L/Max | No internet required | Server L or Max selected from hardware and license; enterprise platform payload | Planned | + +Large Server L/Max models are not bootable installers and are not duplicated +inside the ISO. They are separate signed model packs imported from approved USB +or external storage after platform installation. The same signed offline update +format will patch already-installed systems across all four ISO products; fixed +updates are also rolled into later ISO rebuilds for clean installations. + +Expected removable-media guidance: + +- Online Universal Server ISO: approximately 2-4 GB; use an 8 GB or larger USB. +- Offline Workstation ISO: currently estimated at 35-50 GB; use a 64 GB minimum, + with 128 GB recommended for reliable flashing and future growth. +- Offline Server S/M and L/Max sizes will be recorded only after their payloads + are built and deduplicated; do not publish speculative final sizes. +- Large model packs may range from a few gigabytes to hundreds of gigabytes and + should normally be carried on dedicated external storage. + +An ISO is not labelled offline merely because the source tree is embedded. It +must pass a clean installation with network interfaces disconnected, payload +integrity verification, reboot persistence, and service/model validation. + ## Product Collateral Technical buyer-facing collateral lives in `docs/` for reuse in customer diff --git a/autoinstall/offline/README.md b/autoinstall/offline/README.md index 98a88a9..15fa77b 100644 --- a/autoinstall/offline/README.md +++ b/autoinstall/offline/README.md @@ -4,6 +4,17 @@ This directory defines the payload embedded by `build-iso-offline.sh`. The offline installer is deliberately separate from the existing online bootstrap ISO until disconnected clean-install validation is complete. +The agreed bootable release matrix is: + +1. Online Universal Server ISO with Server S/M/L/Max selection. +2. Offline Workstation ISO. +3. Offline Server S/M ISO. +4. Offline Server L/Max ISO. + +Large models remain separate signed model packs. Signed update bundles patch +installed appliances without an operating-system reinstall, and validated +updates are periodically rolled into refreshed ISO builds. + ## Offline Workstation contents - the exact `aipackage` source revision used for the build diff --git a/autoinstall/offline/build-bundle.sh b/autoinstall/offline/build-bundle.sh index 26633bc..be24098 100755 --- a/autoinstall/offline/build-bundle.sh +++ b/autoinstall/offline/build-bundle.sh @@ -35,10 +35,18 @@ if [ "$available_kb" -lt $((80 * 1024 * 1024)) ]; then fi rm -rf "$OUTPUT_DIR" -mkdir -p "$PAYLOAD_DIR"/{apt,containers,models,python,runtime,source} "$MANIFEST_DIR" +mkdir -p "$PAYLOAD_DIR"/{apt,containers,models,runtime,source} \ + "$PAYLOAD_DIR/python"/{backend,chromadb,platform} "$MANIFEST_DIR" echo "-> Capturing pinned appliance source" -git -C "$PACKAGE_DIR" rev-parse HEAD > "$MANIFEST_DIR/source-commit.txt" +if git -C "$PACKAGE_DIR" rev-parse HEAD >/dev/null 2>&1; then + git -C "$PACKAGE_DIR" rev-parse HEAD > "$MANIFEST_DIR/source-commit.txt" +elif [ -n "${OFFLINE_SOURCE_COMMIT:-}" ]; then + printf '%s\n' "$OFFLINE_SOURCE_COMMIT" > "$MANIFEST_DIR/source-commit.txt" +else + echo "ERROR: source commit is unavailable; set OFFLINE_SOURCE_COMMIT for exported source trees." >&2 + exit 1 +fi rsync -a --delete \ --exclude '.git/' --exclude '*.iso' --exclude 'offline-output/' \ --exclude 'how-it-flows.gif' \ @@ -52,9 +60,15 @@ apt-get install -y --download-only --reinstall \ -o "Dir::Cache::archives=$PAYLOAD_DIR/apt" "${apt_packages[@]}" echo "-> Downloading Python wheelhouse" -python3 -m pip download --dest "$PAYLOAD_DIR/python" \ - -r "$PACKAGE_DIR/ansible/roles/cezen-backend/files/requirements.txt" \ - -r "$SCRIPT_DIR/python-packages.txt" +python3 -m pip download --dest "$PAYLOAD_DIR/python/backend" \ + -r "$PACKAGE_DIR/ansible/roles/cezen-backend/files/requirements.txt" +python3 -m pip download --dest "$PAYLOAD_DIR/python/chromadb" \ + 'chromadb==0.5.23' +grep -vE '^[[:space:]]*(#|$|chromadb==)' "$SCRIPT_DIR/python-packages.txt" \ + > "$OUTPUT_DIR/platform-python-packages.txt" +python3 -m pip download --dest "$PAYLOAD_DIR/python/platform" \ + -r "$OUTPUT_DIR/platform-python-packages.txt" +rm -f "$OUTPUT_DIR/platform-python-packages.txt" echo "-> Capturing Miniconda installer" curl --fail --location --retry 3 "$MINICONDA_URL" \ @@ -76,17 +90,27 @@ echo "-> Capturing Ollama runtime and Starter models" if ! command -v ollama >/dev/null; then curl --fail --location --retry 3 https://ollama.com/install.sh | sh fi -systemctl start ollama 2>/dev/null || true -for model in $OLLAMA_MODELS; do ollama pull "$model"; done tar -C / -czf "$PAYLOAD_DIR/runtime/ollama-runtime.tar.gz" \ usr/local/bin/ollama usr/local/lib/ollama -ollama_root="${OLLAMA_MODELS_DIR:-/usr/share/ollama/.ollama/models}" -[ -d "$ollama_root" ] || ollama_root="/root/.ollama/models" -[ -d "$ollama_root" ] || { - echo "ERROR: Ollama model store not found after pull." >&2 - exit 1 -} -tar -C "$(dirname "$ollama_root")" -czf "$PAYLOAD_DIR/models/ollama-models.tar.gz" models +isolated_ollama="$OUTPUT_DIR/ollama-staging" +mkdir -p "$isolated_ollama" +OLLAMA_MODELS="$isolated_ollama/models" OLLAMA_HOST=127.0.0.1:11435 \ + ollama serve >"$OUTPUT_DIR/ollama-staging.log" 2>&1 & +ollama_pid=$! +cleanup_ollama() { kill "$ollama_pid" 2>/dev/null || true; } +trap cleanup_ollama EXIT +for _ in $(seq 1 30); do + OLLAMA_HOST=127.0.0.1:11435 ollama list >/dev/null 2>&1 && break + sleep 1 +done +for model in $OLLAMA_MODELS; do + OLLAMA_MODELS="$isolated_ollama/models" OLLAMA_HOST=127.0.0.1:11435 \ + ollama pull "$model" +done +cleanup_ollama +trap - EXIT +tar -C "$isolated_ollama" -czf "$PAYLOAD_DIR/models/ollama-models.tar.gz" models +rm -rf "$isolated_ollama" "$OUTPUT_DIR/ollama-staging.log" echo "-> Capturing vLLM Starter model snapshot" python3 -m pip install --quiet huggingface-hub diff --git a/autoinstall/offline/verify-bundle.sh b/autoinstall/offline/verify-bundle.sh index 7aa84e7..e3f64ec 100755 --- a/autoinstall/offline/verify-bundle.sh +++ b/autoinstall/offline/verify-bundle.sh @@ -23,7 +23,7 @@ for path in "${required[@]}"; do } done -for directory in payload/apt payload/containers payload/python payload/models/huggingface; do +for directory in payload/apt payload/containers payload/python/backend payload/python/chromadb payload/python/platform payload/models/huggingface; do find "$OUTPUT_DIR/$directory" -type f -print -quit | grep -q . || { echo "ERROR: required offline payload directory is empty: $directory" >&2 exit 1