diff --git a/README.md b/README.md index 0942b7c..9517762 100644 --- a/README.md +++ b/README.md @@ -40,15 +40,13 @@ If you want to re-pull just those managed Ollama models later, run `./labctl oll ## Supported Host Profiles -This build intentionally avoids the reference VM's hardware workarounds. +This build is the Linux/WSL variant of LLM Labs Local. If you are deploying on Apple Silicon macOS, use the sibling `LLM-Labs-Local-Mac` project instead. -- macOS: Apple Silicon only, with at least 16 GB unified memory. - Native Debian/Ubuntu: Debian-family Linux with an NVIDIA GPU visible to `nvidia-smi` and at least 8 GB VRAM. - WSL: Debian/Ubuntu-family Linux running under WSL, with the NVIDIA GPU exposed into the distro. The launcher and Ansible preflight classify the host dynamically and apply different setup behavior for: -- `macos` - `native-debian-ubuntu` - `wsl` @@ -146,4 +144,4 @@ The deployment will: - Lab 2 includes `state/lab2/download_whiterabbitneo-gguf.sh`, which uses `git` + `git lfs` to pull only the supported WhiteRabbitNeo quants. Add `--download-only` if you want the files without Ollama registration. - The wiki is cloned from `https://git.zuccaro.me/bzuccaro/LLM-Labs.git` into `state/repos/LLM-Labs` and started with `npm`. - `./labctl down` uninstalls Ollama entirely when this project installed it, instead of only stopping the service. -- Unsloth Studio currently supports chat and data workflows on macOS; Linux/WSL remains the standard path for NVIDIA-backed training. +- This variant is intended for NVIDIA-backed Linux/WSL training and lab workflows. diff --git a/ansible/playbooks/down.yml b/ansible/playbooks/down.yml index 5c7bff7..2a5ca0c 100644 --- a/ansible/playbooks/down.yml +++ b/ansible/playbooks/down.yml @@ -140,22 +140,6 @@ - courseware_down_ollama_marker.stat.exists failed_when: false - - name: Stop courseware-managed Ollama macOS app if running - command: pkill -x Ollama - when: - - ansible_system == "Darwin" - - courseware_down_ollama_marker.stat.exists - changed_when: false - failed_when: false - - - name: Uninstall courseware-managed Ollama Homebrew formula - command: brew uninstall ollama - when: - - ansible_system == "Darwin" - - courseware_down_ollama_marker.stat.exists - changed_when: false - failed_when: false - - name: Remove managed Unsloth path file: path: "{{ ansible_env.HOME }}/.unsloth" diff --git a/ansible/roles/common/defaults/main.yml b/ansible/roles/common/defaults/main.yml index 3e58cba..74d7c03 100644 --- a/ansible/roles/common/defaults/main.yml +++ b/ansible/roles/common/defaults/main.yml @@ -12,10 +12,3 @@ common_packages_debian: - ninja-build - libssl-dev - pkg-config - -common_packages_macos: - - python3 - - git - - curl - - cmake - - ninja diff --git a/ansible/roles/common/tasks/main.yml b/ansible/roles/common/tasks/main.yml index c593ef7..ce2e480 100644 --- a/ansible/roles/common/tasks/main.yml +++ b/ansible/roles/common/tasks/main.yml @@ -20,17 +20,6 @@ when: ansible_os_family == "Debian" become: yes -- name: Ensure Homebrew is installed (macOS) - ansible.builtin.homebrew: - name: - - python3 - - git - - curl - - cmake - - ninja - state: present - when: ansible_os_family == "Darwin" - - name: Install Python virtual environment module (user space) ansible.builtin.pip: name: virtualenv diff --git a/ansible/roles/kiln/tasks/macos.yml b/ansible/roles/kiln/tasks/macos.yml deleted file mode 100644 index 65db515..0000000 --- a/ansible/roles/kiln/tasks/macos.yml +++ /dev/null @@ -1,19 +0,0 @@ -- name: Download Kiln macOS disk image - get_url: - url: "https://github.com/Kiln-AI/Kiln/releases/download/{{ courseware_kiln_release_tag }}/Kiln.MacOS.AppleSilicon.M-Processor.dmg" - dest: "{{ courseware_downloads_dir }}/Kiln.MacOS.AppleSilicon.M-Processor.dmg" - mode: "0644" - -- name: Install Kiln.app into project state - shell: | - set -euo pipefail - mount_point=$(mktemp -d /tmp/kiln.XXXXXX) - hdiutil attach "{{ courseware_downloads_dir }}/Kiln.MacOS.AppleSilicon.M-Processor.dmg" -mountpoint "$mount_point" -nobrowse -quiet - app_path=$(find "$mount_point" -maxdepth 1 -name '*.app' | head -n 1) - rm -rf "{{ courseware_apps_dir }}/Kiln.app" - cp -R "$app_path" "{{ courseware_apps_dir }}/Kiln.app" - hdiutil detach "$mount_point" -quiet - rmdir "$mount_point" - args: - executable: /bin/bash - creates: "{{ courseware_apps_dir }}/Kiln.app" diff --git a/ansible/roles/kiln/tasks/main.yml b/ansible/roles/kiln/tasks/main.yml index 3b7bafb..76eacf9 100644 --- a/ansible/roles/kiln/tasks/main.yml +++ b/ansible/roles/kiln/tasks/main.yml @@ -1,8 +1,3 @@ - name: Install Kiln on Linux include_tasks: linux.yml when: ansible_system == "Linux" - -- name: Install Kiln on macOS - include_tasks: macos.yml - when: ansible_system == "Darwin" - diff --git a/ansible/roles/llama-cpp/tasks/main.yml b/ansible/roles/llama-cpp/tasks/main.yml index 3ec86e0..e2b0028 100644 --- a/ansible/roles/llama-cpp/tasks/main.yml +++ b/ansible/roles/llama-cpp/tasks/main.yml @@ -23,18 +23,6 @@ gpu_type: "{{ 'nvidia' if nvidia_smi_output.rc == 0 else 'none' }}" when: is_wsl | default(false) or ansible_os_family == "Debian" -- name: Check for Metal GPU on macOS - ansible.builtin.command: system_profiler SPDisplaysDataType - register: metal_check - changed_when: false - failed_when: false - when: ansible_os_family == "Darwin" - -- name: Set GPU type for macOS - ansible.builtin.set_fact: - gpu_type: "metal" - when: ansible_os_family == "Darwin" and metal_check.rc == 0 - - name: Display detected GPU type ansible.builtin.debug: msg: "llama.cpp GPU type: {{ gpu_type | default('none') }}" @@ -58,7 +46,6 @@ {{ not llama_cpp_stat.stat.exists or (gpu_type == 'nvidia' and existing_gpu_check.stdout != 'cuda') or - (gpu_type == 'metal' and existing_gpu_check.stdout != 'metal') or (gpu_type == 'amd' and existing_gpu_check.stdout != 'amd') }} @@ -120,19 +107,6 @@ when: gpu_type == 'amd' and cmake_configured.rc != 0 become: no -- name: Configure llama.cpp for Metal (macOS) - ansible.builtin.command: - argv: - - cmake - - .. - - -G Ninja - - -DCMAKE_BUILD_TYPE=Release - - -DGGML_METAL=on - args: - chdir: "{{ llmlab_base }}/lab2/llama.cpp/build" - when: gpu_type == 'metal' and cmake_configured.rc != 0 - become: no - - name: Configure llama.cpp for CPU only ansible.builtin.command: argv: diff --git a/ansible/roles/llama_cpp/tasks/main.yml b/ansible/roles/llama_cpp/tasks/main.yml index b312074..1f5943c 100644 --- a/ansible/roles/llama_cpp/tasks/main.yml +++ b/ansible/roles/llama_cpp/tasks/main.yml @@ -78,7 +78,7 @@ - name: Set llama.cpp backend flag set_fact: - courseware_llama_backend_flag: "{{ '-DGGML_METAL=ON' if ansible_system == 'Darwin' else '-DGGML_CUDA=ON' }}" + courseware_llama_backend_flag: "-DGGML_CUDA=ON" - name: Set llama.cpp build parallelism set_fact: diff --git a/ansible/roles/ollama/tasks/main.yml b/ansible/roles/ollama/tasks/main.yml index 6992075..3f9bd98 100644 --- a/ansible/roles/ollama/tasks/main.yml +++ b/ansible/roles/ollama/tasks/main.yml @@ -16,14 +16,6 @@ become: yes notify: Start Ollama service -- name: Install Ollama (macOS via Homebrew) - ansible.builtin.homebrew: - name: ollama - state: present - when: - - ansible_os_family == "Darwin" - - ollama_version_check.rc != 0 - - name: Check if Ollama service exists ansible.builtin.command: systemctl list-unit-files ollama.service register: ollama_service_check diff --git a/ansible/roles/packages/tasks/macos.yml b/ansible/roles/packages/tasks/macos.yml deleted file mode 100644 index b457beb..0000000 --- a/ansible/roles/packages/tasks/macos.yml +++ /dev/null @@ -1,29 +0,0 @@ -- name: Check installed Homebrew formulas - command: "brew list --versions {{ item }}" - loop: - - git - - git-lfs - - cmake - - node - - python@3.11 - - ollama - register: courseware_brew_checks - changed_when: false - failed_when: false - -- name: Install missing Homebrew formulas - command: "brew install {{ item.item }}" - loop: "{{ courseware_brew_checks.results }}" - when: item.rc != 0 - -- name: Mark Ollama as installed by courseware on macOS - file: - path: "{{ courseware_ollama_install_marker }}" - state: touch - mode: "0644" - when: - - courseware_brew_checks.results - | selectattr('item', 'equalto', 'ollama') - | selectattr('rc', 'ne', 0) - | list - | length > 0 diff --git a/ansible/roles/packages/tasks/main.yml b/ansible/roles/packages/tasks/main.yml index 66c98b6..c2fb3a8 100644 --- a/ansible/roles/packages/tasks/main.yml +++ b/ansible/roles/packages/tasks/main.yml @@ -1,8 +1,3 @@ -- name: Install macOS prerequisites - include_tasks: macos.yml - when: ansible_system == "Darwin" - - name: Install Linux prerequisites include_tasks: linux.yml when: ansible_system == "Linux" - diff --git a/ansible/roles/preflight/tasks/main.yml b/ansible/roles/preflight/tasks/main.yml index b98497b..dd7c6cb 100644 --- a/ansible/roles/preflight/tasks/main.yml +++ b/ansible/roles/preflight/tasks/main.yml @@ -1,56 +1,14 @@ - name: Classify supported host profile set_fact: - courseware_is_macos: "{{ ansible_system == 'Darwin' }}" courseware_is_linux: "{{ ansible_system == 'Linux' }}" courseware_is_wsl: "{{ 'microsoft' in ansible_kernel | lower or 'wsl' in ansible_kernel | lower }}" courseware_is_native_linux: "{{ ansible_system == 'Linux' and not ('microsoft' in ansible_kernel | lower or 'wsl' in ansible_kernel | lower) }}" - courseware_host_profile: "{{ 'macos' if ansible_system == 'Darwin' else ('wsl' if ('microsoft' in ansible_kernel | lower or 'wsl' in ansible_kernel | lower) else ('native-debian-ubuntu' if ansible_system == 'Linux' and ansible_os_family == 'Debian' else 'unsupported')) }}" + courseware_host_profile: "{{ 'wsl' if ansible_system == 'Linux' and ('microsoft' in ansible_kernel | lower or 'wsl' in ansible_kernel | lower) else ('native-debian-ubuntu' if ansible_system == 'Linux' and ansible_os_family == 'Debian' else 'unsupported') }}" - name: Fail on unsupported operating systems fail: - msg: "Supported platforms are Apple Silicon macOS and Debian-family Linux/WSL." - when: ansible_system not in ["Darwin", "Linux"] - -- name: Fail on unsupported macOS architecture - fail: - msg: "This installer supports Apple Silicon Macs only." - when: - - ansible_system == "Darwin" - - ansible_architecture not in ["arm64", "aarch64"] - -- name: Fail on undersized macOS systems - fail: - msg: "This courseware assumes a modern Apple Silicon Mac with at least 16 GB of unified memory." - when: - - ansible_system == "Darwin" - - (ansible_memtotal_mb | int) < 16000 - -- name: Check for Xcode command line tools - command: xcode-select -p - register: courseware_xcode_select - changed_when: false - when: ansible_system == "Darwin" - -- name: Check for Homebrew - command: which brew - register: courseware_brew_check - changed_when: false - failed_when: false - when: ansible_system == "Darwin" - -- name: Fail when Xcode command line tools are missing - fail: - msg: "Install Xcode Command Line Tools first with 'xcode-select --install'." - when: - - ansible_system == "Darwin" - - courseware_xcode_select.rc != 0 - -- name: Fail when Homebrew is missing - fail: - msg: "Install Homebrew first from https://brew.sh/." - when: - - ansible_system == "Darwin" - - courseware_brew_check.rc != 0 + msg: "Supported platforms are Debian-family Linux and WSL." + when: courseware_host_profile == "unsupported" - name: Fail on unsupported Linux family fail: @@ -330,6 +288,5 @@ - name: Set runtime binary defaults set_fact: - courseware_python_bin: >- - {{ '/opt/homebrew/opt/python@3.11/bin/python3.11' if ansible_system == 'Darwin' else '/usr/bin/python3' }} + courseware_python_bin: "/usr/bin/python3" courseware_ollama_bin: "ollama" diff --git a/ansible/roles/transformerlab/tasks/main.yml b/ansible/roles/transformerlab/tasks/main.yml index 379bcd7..e46bd41 100644 --- a/ansible/roles/transformerlab/tasks/main.yml +++ b/ansible/roles/transformerlab/tasks/main.yml @@ -145,7 +145,7 @@ - name: Determine Miniforge platform suffix set_fact: - courseware_transformerlab_miniforge_platform: "{{ 'Linux-x86_64' if ansible_system == 'Linux' and ansible_architecture == 'x86_64' else 'Linux-aarch64' if ansible_system == 'Linux' and ansible_architecture in ['aarch64', 'arm64'] else 'MacOSX-arm64' if ansible_system == 'Darwin' and ansible_architecture == 'arm64' else 'MacOSX-x86_64' if ansible_system == 'Darwin' and ansible_architecture == 'x86_64' else 'unsupported' }}" + courseware_transformerlab_miniforge_platform: "{{ 'Linux-x86_64' if ansible_system == 'Linux' and ansible_architecture == 'x86_64' else 'Linux-aarch64' if ansible_system == 'Linux' and ansible_architecture in ['aarch64', 'arm64'] else 'unsupported' }}" - name: Fail for unsupported Miniforge platform fail: @@ -210,7 +210,7 @@ elif [ "$accelerator" = "rocm" ]; then wheel_args+=(--index https://download.pytorch.org/whl/rocm6.4 --index-strategy unsafe-best-match) extra="rocm" - elif [ "{{ ansible_system }}" != "Darwin" ]; then + else wheel_args+=(--index https://download.pytorch.org/whl/cpu --index-strategy unsafe-best-match) fi diff --git a/ansible/templates/runtime.env.j2 b/ansible/templates/runtime.env.j2 index a42dc86..52fe618 100644 --- a/ansible/templates/runtime.env.j2 +++ b/ansible/templates/runtime.env.j2 @@ -35,5 +35,4 @@ WIKI_DIR="{{ courseware_wiki_repo_dir }}" WIKI_RUNTIME_CONFIG_PATH="{{ courseware_wiki_runtime_config_path }}" LLAMA_CPP_BIN_DIR="{{ courseware_llama_cpp_bin_dir }}" KILN_LINUX_BIN="{{ courseware_apps_dir }}/kiln/Kiln" -KILN_MAC_APP="{{ courseware_apps_dir }}/Kiln.app" -KILN_LAUNCH_PATH="{% if ansible_system == 'Darwin' %}{{ courseware_apps_dir }}/Kiln.app{% else %}{{ courseware_apps_dir }}/kiln/Kiln{% endif %}" +KILN_LAUNCH_PATH="{{ courseware_apps_dir }}/kiln/Kiln" diff --git a/labctl b/labctl index f566909..0ade1ba 100755 --- a/labctl +++ b/labctl @@ -132,29 +132,16 @@ host_is_wsl() { [ "$(uname -s)" = "Linux" ] && uname -r | grep -qiE 'microsoft|wsl' } -host_is_macos() { - [ "$(uname -s)" = "Darwin" ] -} - host_is_linux() { [ "$(uname -s)" = "Linux" ] } -host_is_arm_mac() { - host_is_macos && [ "$(uname -m)" = "arm64" ] -} - host_profile() { if host_is_wsl; then printf '%s\n' "wsl" return fi - if host_is_macos; then - printf '%s\n' "macos" - return - fi - if host_is_linux && host_is_debian_family; then printf '%s\n' "native-debian-ubuntu" return @@ -299,7 +286,6 @@ Python 3 was not found. Install it first, then rerun this command: - Debian/Ubuntu/WSL: sudo apt update && sudo apt install -y python3 python3-venv -- macOS: brew install python@3.11 EOF exit 1 } @@ -401,7 +387,6 @@ Python 3 is installed, but its virtual environment support is still unavailable. Install the missing venv package for your platform, then rerun this command: - Debian/Ubuntu/WSL: sudo apt update && sudo apt install -y python3-venv python3-pip -- macOS: brew reinstall python@3.11 EOF exit 1 fi diff --git a/scripts/service_manager.sh b/scripts/service_manager.sh index bea7810..73a1b41 100755 --- a/scripts/service_manager.sh +++ b/scripts/service_manager.sh @@ -367,14 +367,6 @@ EOF } open_kiln() { - local host_os - - host_os=$(uname -s) - if [ "$host_os" = "Darwin" ] && [ -d "$KILN_MAC_APP" ]; then - open "$KILN_MAC_APP" - return 0 - fi - if [ -x "$KILN_LINUX_BIN" ]; then nohup "$KILN_LINUX_BIN" >/dev/null 2>&1 & echo "started Kiln from $KILN_LINUX_BIN"