Add self-deploying setup scripts for all sub-projects (P1-P8)

- Root setup.sh orchestrator with per-phase dispatch (./setup.sh p1..p8 | all | status)
- Makefile convenience targets (make infra, make llm, make status, etc.)
- scripts/common.sh: shared bash library for OS detection, Docker helpers,
  service management (launchd/systemd), package install, env management
- .env.example + .gitignore: shared config template and secret exclusions

P1 (homeai-infra): full implementation
- docker-compose.yml: Uptime Kuma, code-server, n8n
- Note: Home Assistant, Portainer, Gitea are pre-existing instances
- setup.sh: Docker install, homeai network, container health checks

P2 (homeai-llm): full implementation
- Ollama native install with CUDA/ROCm/Metal auto-detection
- launchd plist (macOS) + systemd service (Linux) for auto-start
- scripts/pull-models.sh: idempotent model puller from manifest
- scripts/benchmark.sh: tokens/sec measurement per model
- Open WebUI on port 3030 (avoids Gitea :3000 conflict)

P3-P8: working stubs with prerequisite checks and TODO sections

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Aodhan Collins
2026-03-04 21:10:53 +00:00
parent 38247d7cc4
commit 7978eaea14
23 changed files with 2525 additions and 0 deletions

140
setup.sh Normal file
View File

@@ -0,0 +1,140 @@
#!/usr/bin/env bash
# setup.sh — HomeAI root orchestrator
#
# Usage:
# ./setup.sh all # run all phases in order
# ./setup.sh p1 # infra only
# ./setup.sh p2 # llm only
# ./setup.sh p1 p2 # multiple phases
# ./setup.sh status # show service health
#
# Phases: p1=infra p2=llm p3=voice p4=agent p5=character
# p6=esp32 p7=visual p8=images
set -euo pipefail
REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=scripts/common.sh
source "${REPO_DIR}/scripts/common.sh"
# ─── Phase definitions ─────────────────────────────────────────────────────────
declare -A PHASE_NAME=(
[p1]="homeai-infra (Docker stack)"
[p2]="homeai-llm (Ollama + Open WebUI)"
[p3]="homeai-voice (STT / TTS / Wyoming)"
[p4]="homeai-agent (OpenClaw + skills + mem0)"
[p5]="homeai-character (Character Manager UI)"
[p6]="homeai-esp32 (ESPHome firmware)"
[p7]="homeai-visual (VTube Studio bridge)"
[p8]="homeai-images (ComfyUI workflows)"
)
PHASE_ORDER=(p1 p2 p3 p4 p5 p6 p7 p8)
run_phase() {
local phase="$1"
local subdir="${REPO_DIR}/homeai-${phase#p}"
# Map phase ID to directory name
case "$phase" in
p1) subdir="${REPO_DIR}/homeai-infra" ;;
p2) subdir="${REPO_DIR}/homeai-llm" ;;
p3) subdir="${REPO_DIR}/homeai-voice" ;;
p4) subdir="${REPO_DIR}/homeai-agent" ;;
p5) subdir="${REPO_DIR}/homeai-character" ;;
p6) subdir="${REPO_DIR}/homeai-esp32" ;;
p7) subdir="${REPO_DIR}/homeai-visual" ;;
p8) subdir="${REPO_DIR}/homeai-images" ;;
*) die "Unknown phase: $phase" ;;
esac
local setup_script="${subdir}/setup.sh"
if [[ ! -f "$setup_script" ]]; then
die "Setup script not found: $setup_script"
fi
log_section "Phase ${phase^^}: ${PHASE_NAME[$phase]}"
bash "$setup_script"
}
show_status() {
log_section "HomeAI Service Status"
load_env_services
local services=(
"Home Assistant|${HA_URL:-http://localhost:8123}"
"Portainer|${PORTAINER_URL:-https://localhost:9443}"
"Uptime Kuma|${UPTIME_KUMA_URL:-http://localhost:3001}"
"Gitea|${GITEA_URL:-http://localhost:3000}"
"code-server|${CODE_SERVER_URL:-http://localhost:8090}"
"n8n|${N8N_URL:-http://localhost:5678}"
"Ollama|${OLLAMA_URL:-http://localhost:11434}"
"Open WebUI|${OPEN_WEBUI_URL:-http://localhost:3030}"
)
for entry in "${services[@]}"; do
local name="${entry%%|*}"
local url="${entry##*|}"
if curl -sf --max-time 2 "$url" -o /dev/null 2>/dev/null; then
printf " ${GREEN}${RESET} %-20s %s\n" "$name" "$url"
else
printf " ${RED}${RESET} %-20s %s\n" "$name" "$url"
fi
done
echo ""
}
usage() {
echo ""
echo " Usage: $0 <phase...> | all | status"
echo ""
echo " Phases:"
for p in "${PHASE_ORDER[@]}"; do
printf " %-6s %s\n" "$p" "${PHASE_NAME[$p]}"
done
echo ""
echo " Examples:"
echo " $0 all # setup everything in order"
echo " $0 p1 p2 # infra + llm only"
echo " $0 status # check service health"
echo ""
}
# ─── Main ──────────────────────────────────────────────────────────────────────
main() {
if [[ $# -eq 0 ]]; then
usage
exit 0
fi
detect_platform
# Bootstrap root .env if missing
bootstrap_env "${REPO_DIR}"
local phases=()
for arg in "$@"; do
case "$arg" in
all) phases=("${PHASE_ORDER[@]}") ;;
status) show_status; exit 0 ;;
p[1-8]) phases+=("$arg") ;;
help|-h|--help) usage; exit 0 ;;
*) die "Unknown argument: $arg. Run '$0 help' for usage." ;;
esac
done
if [[ ${#phases[@]} -eq 0 ]]; then
usage; exit 0
fi
for phase in "${phases[@]}"; do
run_phase "$phase"
done
log_section "Setup complete"
show_status
}
main "$@"