diff --git a/configs/llama-server.service b/configs/llama-server.service new file mode 100644 index 0000000..ecc5a5c --- /dev/null +++ b/configs/llama-server.service @@ -0,0 +1,22 @@ +[Unit] +Description=llama.cpp inference server for Timmy +After=network.target + +[Service] +Type=simple +User=root +WorkingDirectory=/root/timmy +ExecStart=/root/timmy/llama-server \ + -m /root/timmy/models/hermes-3-8b.Q4_K_M.gguf \ + --host 127.0.0.1 \ + --port 8081 \ + -c 8192 \ + -np 1 \ + --jinja \ + -ngl 0 +Restart=always +RestartSec=10 +Environment="HOME=/root" + +[Install] +WantedBy=multi-user.target diff --git a/configs/timmy-agent.service b/configs/timmy-agent.service new file mode 100644 index 0000000..e4e0d76 --- /dev/null +++ b/configs/timmy-agent.service @@ -0,0 +1,17 @@ +[Unit] +Description=Timmy Agent Harness +After=llama-server.service +Requires=llama-server.service + +[Service] +Type=simple +User=root +WorkingDirectory=/root/timmy +ExecStart=/root/timmy/venv/bin/python /root/timmy/timmy-home/agent/agent_daemon.py +Restart=always +RestartSec=30 +Environment="HOME=/root" +Environment="TIMMY_MODEL_URL=http://127.0.0.1:8081" + +[Install] +WantedBy=multi-user.target diff --git a/scripts/provision-timmy-vps.sh b/scripts/provision-timmy-vps.sh new file mode 100644 index 0000000..b9978bc --- /dev/null +++ b/scripts/provision-timmy-vps.sh @@ -0,0 +1,260 @@ +#!/bin/bash +# Timmy VPS Provisioning Script +# Transforms fresh Ubuntu 22.04+ VPS into sovereign local-first wizard + +set -e + +TIMMY_USER="${TIMMY_USER:-root}" +TIMMY_HOME="${TIMMY_HOME:-/root}" +TIMMY_DIR="$TIMMY_HOME/timmy" +REPO_URL="${REPO_URL:-http://143.198.27.163:3000/Timmy_Foundation/timmy-home.git}" +MODEL_URL="${MODEL_URL:-https://huggingface.co/TheBloke/Hermes-3-Llama-3.1-8B-GGUF/resolve/main/hermes-3-llama-3.1-8b.Q4_K_M.gguf}" +MODEL_NAME="${MODEL_NAME:-hermes-3-8b.Q4_K_M.gguf}" + +echo "========================================" +echo " Timmy VPS Provisioning" +echo "========================================" +echo "" + +# Colors +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +log() { + echo -e "${GREEN}[TIMMY]${NC} $1" +} + +warn() { + echo -e "${YELLOW}[WARN]${NC} $1" +} + +error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +# Check if running as root +if [ "$EUID" -ne 0 ]; then + error "Please run as root" + exit 1 +fi + +# Check Ubuntu version +if ! grep -q "Ubuntu 22.04\|Ubuntu 24.04" /etc/os-release; then + warn "Not Ubuntu 22.04/24.04 - may not work correctly" +fi + +log "Step 1/8: Installing system dependencies..." +export DEBIAN_FRONTEND=noninteractive +apt-get update -qq +apt-get install -y -qq \ + build-essential \ + cmake \ + git \ + curl \ + wget \ + python3 \ + python3-pip \ + python3-venv \ + libopenblas-dev \ + pkg-config \ + ufw \ + jq \ + sqlite3 \ + libsqlite3-dev \ + 2>&1 | tail -5 + +log "Step 2/8: Setting up directory structure..." +mkdir -p "$TIMMY_DIR"/{soul,scripts,logs,shared,models,configs} +mkdir -p "$TIMMY_HOME/.config/systemd/user" + +log "Step 3/8: Building llama.cpp from source..." +if [ ! -f "$TIMMY_DIR/llama-server" ]; then + cd /tmp + git clone --depth 1 https://github.com/ggerganov/llama.cpp.git 2>/dev/null || true + cd llama.cpp + + # Build with OpenBLAS for CPU optimization + cmake -B build \ + -DGGML_BLAS=ON \ + -DGGML_BLAS_VENDOR=OpenBLAS \ + -DLLAMA_BUILD_TESTS=OFF \ + -DLLAMA_BUILD_EXAMPLES=OFF \ + -DCMAKE_BUILD_TYPE=Release + + cmake --build build --config Release -j$(nproc) + + # Copy binaries + cp build/bin/llama-server "$TIMMY_DIR/" + cp build/bin/llama-cli "$TIMMY_DIR/" + + log "llama.cpp built successfully" +else + log "llama.cpp already exists, skipping build" +fi + +log "Step 4/8: Downloading model weights..." +if [ ! -f "$TIMMY_DIR/models/$MODEL_NAME" ]; then + cd "$TIMMY_DIR/models" + wget -q --show-progress "$MODEL_URL" -O "$MODEL_NAME" || { + error "Failed to download model. Continuing anyway..." + } + log "Model downloaded" +else + log "Model already exists, skipping download" +fi + +log "Step 5/8: Setting up llama-server systemd service..." +cat > /etc/systemd/system/llama-server.service << EOF +[Unit] +Description=llama.cpp inference server for Timmy +After=network.target + +[Service] +Type=simple +User=$TIMMY_USER +WorkingDirectory=$TIMMY_DIR +ExecStart=$TIMMY_DIR/llama-server \\ + -m $TIMMY_DIR/models/$MODEL_NAME \\ + --host 127.0.0.1 \\ + --port 8081 \\ + -c 8192 \\ + -np 1 \\ + --jinja \\ + -ngl 0 +Restart=always +RestartSec=10 +Environment="HOME=$TIMMY_HOME" + +[Install] +WantedBy=multi-user.target +EOF + +systemctl daemon-reload +systemctl enable llama-server.service + +log "Step 6/8: Cloning timmy-home repo and setting up agent..." +if [ ! -d "$TIMMY_DIR/timmy-home" ]; then + cd "$TIMMY_DIR" + git clone "$REPO_URL" timmy-home 2>/dev/null || warn "Could not clone repo" +fi + +# Create minimal Python environment for agent +if [ ! -d "$TIMMY_DIR/venv" ]; then + python3 -m venv "$TIMMY_DIR/venv" + "$TIMMY_DIR/venv/bin/pip" install -q requests pyyaml 2>&1 | tail -3 +fi + +log "Step 7/8: Setting up Timmy agent systemd service..." +cat > /etc/systemd/system/timmy-agent.service << EOF +[Unit] +Description=Timmy Agent Harness +After=llama-server.service +Requires=llama-server.service + +[Service] +Type=simple +User=$TIMMY_USER +WorkingDirectory=$TIMMY_DIR +ExecStart=$TIMMY_DIR/venv/bin/python $TIMMY_DIR/timmy-home/agent/agent_daemon.py +Restart=always +RestartSec=30 +Environment="HOME=$TIMMY_HOME" +Environment="TIMMY_MODEL_URL=http://127.0.0.1:8081" + +[Install] +WantedBy=multi-user.target +EOF + +systemctl daemon-reload +systemctl enable timmy-agent.service + +log "Step 8/8: Configuring firewall..." +# Reset UFW +ufw --force reset 2>/dev/null || true +ufw default deny incoming +ufw default allow outgoing + +# Allow SSH +ufw allow 22/tcp + +# Allow Syncthing (sync protocol) +ufw allow 22000/tcp +ufw allow 22000/udp + +# Allow Syncthing (discovery) +ufw allow 21027/udp + +# Note: llama-server on 8081 is NOT exposed (localhost only) + +ufw --force enable + +log "Starting services..." +systemctl start llama-server.service || warn "llama-server failed to start (may need model)" + +# Wait for llama-server to be ready +log "Waiting for llama-server to be ready..." +for i in {1..30}; do + if curl -s http://127.0.0.1:8081/health >/dev/null 2>&1; then + log "llama-server is healthy!" + break + fi + sleep 2 +done + +# Create status script +cat > "$TIMMY_DIR/scripts/status.sh" << 'EOF' +#!/bin/bash +echo "=== Timmy VPS Status ===" +echo "" +echo "Services:" +systemctl is-active llama-server.service && echo " llama-server: RUNNING" || echo " llama-server: STOPPED" +systemctl is-active timmy-agent.service && echo " timmy-agent: RUNNING" || echo " timmy-agent: STOPPED" +echo "" +echo "Inference Health:" +curl -s http://127.0.0.1:8081/health | jq . 2>/dev/null || echo " Not responding" +echo "" +echo "Disk Usage:" +df -h $HOME | tail -1 +echo "" +echo "Memory:" +free -h | grep Mem +EOF +chmod +x "$TIMMY_DIR/scripts/status.sh" + +# Create README +cat > "$TIMMY_DIR/README.txt" << EOF +Timmy Sovereign Wizard VPS +========================== + +Quick Commands: + $TIMMY_DIR/scripts/status.sh - Check system status + systemctl status llama-server - Check inference service + systemctl status timmy-agent - Check agent service + +Directories: + $TIMMY_DIR/models/ - AI model weights + $TIMMY_DIR/soul/ - SOUL.md and conscience files + $TIMMY_DIR/logs/ - Agent logs + $TIMMY_DIR/shared/ - Syncthing shared folder + +Inference Endpoint: + http://127.0.0.1:8081 (localhost only) + +Provisioning complete! +EOF + +echo "" +echo "========================================" +log "Provisioning Complete!" +echo "========================================" +echo "" +echo "Status:" +"$TIMMY_DIR/scripts/status.sh" +echo "" +echo "Next steps:" +echo " 1. Run syncthing setup: curl -sL $REPO_URL/raw/branch/main/scripts/setup-syncthing.sh | bash" +echo " 2. Check inference: curl http://127.0.0.1:8081/health" +echo " 3. Review logs: journalctl -u llama-server -f" +echo ""