feat: make firstboot agent-name-agnostic for multi-agent deployments

Derive AGENT_NAME from ASSISTANT_NAME instead of hardcoding "clawdie".
Database names, users, and identity vars now follow the agent name.

Add configurable fields to build.cfg and shell-env.sh:
- AGENT_GENDER, PI_TUI_PROVIDER, PI_TUI_MODEL
- ZAI_API_KEY, OPENROUTER_API_KEY, EMBED_BASE_URL, EMBED_MODEL
- TELEGRAM_BOT_TOKEN, FEATURE_TELEGRAM (pre-bakeable for cloud)

Add gender selection to baremetal wizard (bsddialog radiolist).
Update bhyve-test.sh with --name flag, tap0/bridge auto-setup,
sparse disk reuse, and reduced default disk size (25G).

Tested: dry-run env generation produces correct Mevy config
(agent_name=mevy, db=mevy, provider=zai, model=glm-5).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Sam & Claude 2026-04-01 13:31:36 +00:00 committed by 123kupola
parent 46028a7e6d
commit e46d955527
4 changed files with 99 additions and 46 deletions

View file

@ -40,8 +40,27 @@ TARGET="baremetal" # cloud | baremetal
# Leave blank for baremetal — firstboot wizard collects these interactively
ASSISTANT_NAME=""
AGENT_DOMAIN=""
AGENT_GENDER=""
TZ=""
# LLM provider (default: zai with glm-5)
PI_TUI_PROVIDER=""
PI_TUI_MODEL=""
# API keys (pre-baked for cloud, deferred to web UI for baremetal)
ZAI_API_KEY=""
OPENROUTER_API_KEY=""
ANTHROPIC_API_KEY=""
# Embeddings (default: OpenRouter with bge-m3)
EMBED_BASE_URL=""
EMBED_MODEL=""
# Telegram (pre-baked for cloud, deferred for baremetal)
TELEGRAM_BOT_TOKEN=""
TELEGRAM_CHAT_ID=""
FEATURE_TELEGRAM=""
# SSH public key (optional, supplied via --ssh-key flag)
# If provided, disables password auth; if not, enables password auth fallback
SSH_PUBLIC_KEY=""

View file

@ -106,6 +106,10 @@ Data loss or service interruption possible.
By continuing, you assume all risks." 12 60
ASSISTANT_NAME=$(_dialog --inputbox "Assistant name:" 8 50 "Clawdie")
AGENT_GENDER=$(_dialog --radiolist "Agent gender (affects grammar):" 10 50 3 \
"f" "Female" on \
"m" "Male" off \
"n" "Neutral" off)
AGENT_DOMAIN=$(_dialog --inputbox \
"Agent domain (e.g. clawdie.internal):" 8 50 "clawdie.internal")
TZ=$(_dialog --inputbox \
@ -116,7 +120,9 @@ By continuing, you assume all risks." 12 60
step_done "wizard"
fi
export ASSISTANT_NAME AGENT_DOMAIN TZ SSH_PUBLIC_KEY
export ASSISTANT_NAME AGENT_GENDER AGENT_DOMAIN TZ SSH_PUBLIC_KEY
export PI_TUI_PROVIDER PI_TUI_MODEL ZAI_API_KEY OPENROUTER_API_KEY ANTHROPIC_API_KEY
export EMBED_BASE_URL EMBED_MODEL TELEGRAM_BOT_TOKEN TELEGRAM_CHAT_ID FEATURE_TELEGRAM
# ── Run modules ────────────────────────────────────────────────────────────
log_msg "[firstboot] Running modules..."

View file

@ -70,6 +70,10 @@ clawdie_shell_env_write_file() {
local db_ip mgmt_ip git_ip cms_ip worker_start
# Derive agent name from assistant name (lowercase, strip non-alnum)
local agent_name
agent_name=$(echo "$ASSISTANT_NAME" | tr 'A-Z' 'a-z' | sed 's/[^a-z0-9]//g')
# Derive jail IPs from subnet base
db_ip="${AGENT_SUBNET_BASE}.3"
mgmt_ip="${AGENT_SUBNET_BASE}.2"
@ -100,16 +104,27 @@ clawdie_shell_env_write_file() {
# === Identity ===
ASSISTANT_NAME="$ASSISTANT_NAME"
AGENT_NAME="clawdie"
AGENT_NAME="$agent_name"
AGENT_GENDER="${AGENT_GENDER:-f}"
AGENT_DOMAIN="$AGENT_DOMAIN"
TZ="$TZ"
# === Secrets (auto-generated) ===
JWT_SECRET="$jwt_secret"
ANTHROPIC_API_KEY="$api_key"
DB_PASSWORD="$db_password"
REDIS_PASSWORD="$redis_password"
# === LLM Provider ===
PI_TUI_PROVIDER="${PI_TUI_PROVIDER:-zai}"
PI_TUI_MODEL="${PI_TUI_MODEL:-glm-5}"
ZAI_API_KEY="${ZAI_API_KEY:-}"
OPENROUTER_API_KEY="${OPENROUTER_API_KEY:-}"
ANTHROPIC_API_KEY="${ANTHROPIC_API_KEY:-$api_key}"
# === Embeddings ===
EMBED_BASE_URL="${EMBED_BASE_URL:-https://openrouter.ai/api/v1}"
EMBED_MODEL="${EMBED_MODEL:-BAAI/bge-m3}"
# === Network Configuration ===
AGENT_SUBNET_BASE="$AGENT_SUBNET_BASE"
AGENT_GATEWAY_IP="${AGENT_SUBNET_BASE}.1"
@ -122,21 +137,18 @@ WORKER_JAIL_IP_START="$worker_start"
# === Database ===
DB_HOST="$db_ip"
DB_PORT="5432"
DB_NAME="clawdie"
DB_USER="clawdie"
DB_NAME="$agent_name"
DB_USER="$agent_name"
DB_PASSWORD="$db_password"
# === Features (optional) ===
FEATURE_MANAGEMENT_JAIL="true"
FEATURE_OLLAMA="false"
FEATURE_TELEGRAM="false"
FEATURE_TELEGRAM="${FEATURE_TELEGRAM:-false}"
# === Telegram (if enabled) ===
TELEGRAM_BOT_TOKEN=""
TELEGRAM_CHAT_ID=""
# === LLM Provider ===
LLM_PROVIDER="anthropic"
# === Telegram ===
TELEGRAM_BOT_TOKEN="${TELEGRAM_BOT_TOKEN:-}"
TELEGRAM_CHAT_ID="${TELEGRAM_CHAT_ID:-}"
# === Optional: SSH Public Key (if provided at install) ===
SSH_PUBLIC_KEY="${SSH_PUBLIC_KEY:-}"
@ -194,7 +206,7 @@ clawdie_shell_env_validate() {
fi
# Check for required variables
local required_vars="ASSISTANT_NAME AGENT_DOMAIN TZ JWT_SECRET DB_PASSWORD"
local required_vars="ASSISTANT_NAME AGENT_NAME AGENT_DOMAIN TZ JWT_SECRET DB_PASSWORD"
local missing=0
for var in $required_vars; do
if ! grep -q "^$var=" "$ENV_FILE" 2>/dev/null; then

View file

@ -1,15 +1,25 @@
#!/bin/sh
# Setup and boot Clawdie-ISO in bhyve VM
# Usage: bhyve-test.sh [ISO_PATH] [--name VM_NAME]
VM_NAME="clawdie-test"
VM_NAME="${BHYVE_VM_NAME:-clawdie-test}"
VM_DIR="/var/bhyve/$VM_NAME"
DISK_SIZE="50G"
DISK_SIZE="25G"
MEM="2G"
CPUS="2"
ISO_DIR="$(cd "$(dirname "$0")/.." && pwd)"
# Use ISO passed as argument, or auto-detect newest baremetal image
if [ -n "${1:-}" ]; then
ISO="$1"
else
# Parse args
ISO=""
while [ $# -gt 0 ]; do
case "$1" in
--name) VM_NAME="$2"; VM_DIR="/var/bhyve/$VM_NAME"; shift 2 ;;
*) ISO="$1"; shift ;;
esac
done
# Auto-detect newest baremetal image if no ISO given
if [ -z "$ISO" ]; then
ISO="$(ls -t "${ISO_DIR}"/clawdie-iso-baremetal-*.img 2>/dev/null | head -1)"
fi
@ -32,30 +42,25 @@ fi
mkdir -p $VM_DIR
cd $VM_DIR
# Create disk image (will be installed to)
echo "Creating 50GB virtual disk..."
truncate -s $DISK_SIZE disk.img
# Create disk image (sparse — only uses what's written)
if [ ! -f disk.img ]; then
echo "Creating ${DISK_SIZE} virtual disk (sparse)..."
truncate -s $DISK_SIZE disk.img
else
echo "Reusing existing disk.img"
fi
# Boot parameters
echo ""
echo "Starting VM boot sequence..."
echo " VM Name: $VM_NAME"
echo " Disk: $VM_DIR/disk.img ($DISK_SIZE)"
echo " ISO: $ISO"
echo " Memory: 2G"
echo " CPUs: 2"
echo ""
echo "Booting... (this will take a minute)"
echo ""
# Ensure tap interface exists and is on the bridge
if ! ifconfig tap0 >/dev/null 2>&1; then
echo "Creating tap0 interface..."
ifconfig tap0 create up
fi
# Boot VM from ISO
# -A: ACPI
# -H: yield CPU on halt
# -P: PMC (performance monitoring, not needed but compatible)
# -m: memory
# -c: CPUs
# -l: LPC devices (bootrom + serial console)
# ISO as cdrom
# Add tap0 to warden0 bridge if not already a member
if ! ifconfig warden0 | grep -q 'member: tap0'; then
echo "Adding tap0 to warden0 bridge..."
ifconfig warden0 addm tap0
fi
# Locate UEFI bootrom
BOOTROM="/usr/local/share/uefi-firmware/BHYVE_UEFI.fd"
@ -65,16 +70,27 @@ fi
if [ ! -f "$BOOTROM" ]; then
echo "ERROR: UEFI bootrom not found"
echo "Tried:"
echo " /usr/local/share/uefi-firmware/BHYVE_UEFI.fd"
echo " /usr/local/share/edk2-bhyve/BHYVE_UEFI.fd"
exit 1
fi
# Boot parameters
echo ""
echo "Starting VM boot sequence..."
echo " VM Name: $VM_NAME"
echo " Disk: $VM_DIR/disk.img ($DISK_SIZE)"
echo " ISO: $ISO"
echo " Memory: $MEM"
echo " CPUs: $CPUS"
echo " Network: tap0 -> warden0 bridge"
echo ""
echo "Booting... (30 min timeout)"
echo ""
# Boot VM from ISO
timeout 1800 bhyve \
-A -H -P \
-m 2G \
-c 2 \
-m $MEM \
-c $CPUS \
-s 0:0,hostbridge \
-s 1:0,ahci-hd,disk.img \
-s 2:0,ahci-cd,$ISO \