From 2c1121114329fe344d40e969ef5927dfc698c8fd Mon Sep 17 00:00:00 2001 From: Will Weaver Date: Sat, 6 Jun 2026 17:12:49 -0400 Subject: [PATCH 01/14] feat: switch from qwen-coder to GLM-4.7-Flash MLX, remove Ollama entirely Replaces all qwen-coder MLX models on MegamanX with GLM-4.7-Flash (all 3 quants: 4bit, 6bit, 8bit). Removes Ollama service, llm-host role, and all ollama configurations across all targets (MegamanX, wweaver, darwin-server). Updates Vane, OpenCode, and Pi to use GLM models. --- devenv.nix | 2 - flake.nix | 13 +--- modules/common/options.nix | 49 +----------- modules/common/shell.nix | 15 +--- modules/roles/default.nix | 1 - modules/roles/llm-host.nix | 21 ----- modules/services/ollama/common.nix | 105 ------------------------- modules/services/ollama/darwin.nix | 50 ------------ modules/services/ollama/nixos.nix | 63 --------------- modules/services/vane/darwin.nix | 5 +- profiles/monkey/profile.nix | 11 +-- profiles/wweaver/profile.nix | 10 +-- targets/MegamanX/default.nix | 36 +++++---- targets/darwin-server/default.nix | 21 ----- targets/wweaver/default.nix | 20 +---- tests/default.nix | 3 - tests/test-coverage.nix | 10 +-- tests/test-packages.nix | 4 +- tests/test-roles.nix | 87 +-------------------- tests/test-services.nix | 120 +---------------------------- 20 files changed, 37 insertions(+), 609 deletions(-) delete mode 100644 modules/roles/llm-host.nix delete mode 100644 modules/services/ollama/common.nix delete mode 100644 modules/services/ollama/darwin.nix delete mode 100644 modules/services/ollama/nixos.nix diff --git a/devenv.nix b/devenv.nix index 2820d16f..a2f8dc9b 100644 --- a/devenv.nix +++ b/devenv.nix @@ -790,8 +790,6 @@ in { ".#checks.''${CURRENT_SYSTEM}.sketchybar-entrypoint" \ ".#checks.''${CURRENT_SYSTEM}.onepassword-guard" \ ".#checks.''${CURRENT_SYSTEM}.onepassword-config-output" \ - ".#checks.''${CURRENT_SYSTEM}.ollama-options" \ - ".#checks.''${CURRENT_SYSTEM}.ollama-custom-options" \ ".#checks.''${CURRENT_SYSTEM}.vane-options" \ ".#checks.''${CURRENT_SYSTEM}.vane-custom-options" \ ".#checks.''${CURRENT_SYSTEM}.openclaw-options" \ diff --git a/flake.nix b/flake.nix index ec9b6871..a41984b0 100644 --- a/flake.nix +++ b/flake.nix @@ -149,7 +149,6 @@ configuration ./modules ./modules/nixos/base.nix - ./modules/services/ollama/nixos.nix ./modules/services/openclaw inputs.nix-openclaw.nixosModules.openclaw-gateway ./os/microvm.nix @@ -175,7 +174,6 @@ configuration ./modules ./modules/nixos/base.nix - ./modules/services/ollama/nixos.nix ./modules/services/openclaw inputs.nix-openclaw.nixosModules.openclaw-gateway ./os/microvm.nix @@ -261,7 +259,6 @@ nix-homebrew.darwinModules.nix-homebrew ./modules ./modules/roles/homebrew.nix - ./modules/services/ollama/darwin.nix ./modules/services/vane/darwin.nix ./os/darwin.nix ./modules/home-manager/aerospace.nix @@ -272,7 +269,7 @@ }; # Darwin server - headless macOS server for VM hosting - # Uses Lume for macOS VMs, with Ollama for local LLMs + # Uses Lume for macOS VMs "darwin-server" = nix-darwin.lib.darwinSystem { specialArgs = {inherit inputs mkUser;}; modules = [ @@ -284,7 +281,6 @@ configuration ./modules ./modules/services/lume/darwin.nix - ./modules/services/ollama/darwin.nix ./os/darwin.nix ./targets/darwin-server home-manager.darwinModules.home-manager @@ -342,7 +338,6 @@ modules = [ ./library/archetypes/headless-server-darwin.nix ./modules/services/lume/darwin.nix - ./modules/services/ollama/darwin.nix ./os/darwin.nix ./targets/darwin-server home-manager.darwinModules.home-manager @@ -367,7 +362,6 @@ nix-homebrew.darwinModules.nix-homebrew ./modules ./modules/roles/homebrew.nix - ./modules/services/ollama/darwin.nix ./modules/services/vane/darwin.nix ./modules/services/searxng/darwin.nix ./modules/services/higgs/darwin.nix @@ -423,7 +417,6 @@ ./modules/nixos/desktop.nix ./modules/nixos/gaming.nix ./modules/nixos/streaming.nix - ./modules/services/ollama/nixos.nix ./modules/services/openclaw inputs.nix-openclaw.nixosModules.openclaw-gateway ./os/nixos.nix @@ -576,7 +569,6 @@ ./modules/nixos/desktop.nix ./modules/nixos/gaming.nix ./modules/nixos/streaming.nix - ./modules/services/ollama/nixos.nix ./modules/services/openclaw inputs.nix-openclaw.nixosModules.openclaw-gateway ./os/nixos.nix @@ -712,7 +704,6 @@ role-composition role-packages role-cascades - llm-host-shared-models no-dead-development-option module-coverage skills-manifest @@ -739,8 +730,6 @@ sketchybar-entrypoint aerospace-options aerospace-custom-options - ollama-options - ollama-custom-options vane-options vane-custom-options vane-opnix-url-options diff --git a/modules/common/options.nix b/modules/common/options.nix index 0bbfff92..501b9069 100644 --- a/modules/common/options.nix +++ b/modules/common/options.nix @@ -126,13 +126,6 @@ with lib; { description = "Pi coding agent with rtk"; }; }; - llm-host = { - enable = mkOption { - type = types.bool; - default = false; - description = "Local LLM hosting (ollama)"; - }; - }; assistant = { enable = mkOption { @@ -483,7 +476,7 @@ with lib; { model = mkOption { type = types.nullOr types.str; default = null; - description = "Model for this agent (e.g., ollama/qwen3.5:2b)"; + description = "Model for this agent (e.g., higgs/glm47-flash-4bit)"; }; prompt = mkOption { type = types.str; @@ -755,44 +748,6 @@ with lib; { }; }; - ollama = { - enable = mkOption { - type = types.bool; - default = false; - description = "Enable Ollama local LLM service"; - }; - - host = mkOption { - type = types.str; - default = "127.0.0.1"; - description = "Host address for Ollama to bind to (use 0.0.0.0 for network access)"; - }; - - port = mkOption { - type = types.port; - default = 11434; - description = "Port for Ollama API"; - }; - - models = mkOption { - type = types.listOf types.str; - default = []; - description = "List of models to pre-pull on service start"; - }; - - acceleration = mkOption { - type = types.nullOr (types.enum ["cuda" "rocm" "metal"]); - default = null; - description = "GPU acceleration type (null for auto-detection)"; - }; - - environmentFile = mkOption { - type = types.nullOr types.path; - default = null; - description = "Path to environment file with additional Ollama configuration"; - }; - }; - vane = { enable = mkOption { type = types.bool; @@ -1204,7 +1159,7 @@ with lib; { }; provider = mkOption { type = types.str; - description = "Provider ID (e.g., 'anthropic', 'openai', 'ollama')"; + description = "Provider ID (e.g., 'anthropic', 'openai', 'higgs')"; }; modelId = mkOption { type = types.str; diff --git a/modules/common/shell.nix b/modules/common/shell.nix index 2d15d831..68873fd1 100644 --- a/modules/common/shell.nix +++ b/modules/common/shell.nix @@ -1,8 +1,4 @@ -{ - config, - pkgs, - ... -}: let +{pkgs, ...}: let # Create proper executable scripts in the nix store switch-nix-script = pkgs.writeShellScriptBin "switch-nix" (builtins.readFile ./scripts/switch-nix); nix-cloud-init-script = pkgs.writeShellScriptBin "nix-cloud-init" (builtins.readFile ./scripts/nix-cloud-init); @@ -17,15 +13,6 @@ in { programs.zsh.interactiveShellInit = '' export SHELL=${pkgs.zsh}/bin/zsh - ${ - if config.myConfig.ollama.enable - then '' - # Ollama configuration (set because myConfig.ollama is enabled) - export OLLAMA_HOST="http://${config.myConfig.ollama.host}:${toString config.myConfig.ollama.port}" - '' - else "" - } - # Source switch-nix function if [ -f ${switch-nix-script}/bin/switch-nix ]; then . ${switch-nix-script}/bin/switch-nix diff --git a/modules/roles/default.nix b/modules/roles/default.nix index b5b1fb44..0c2251d6 100644 --- a/modules/roles/default.nix +++ b/modules/roles/default.nix @@ -21,7 +21,6 @@ in { ./pi.nix ./assistant.nix ./email-backup.nix - ./llm-host.nix ./microvm-host.nix ./tailscale.nix # Note: homebrew.nix is imported separately by configurations that use nix-homebrew diff --git a/modules/roles/llm-host.nix b/modules/roles/llm-host.nix deleted file mode 100644 index 363e341e..00000000 --- a/modules/roles/llm-host.nix +++ /dev/null @@ -1,21 +0,0 @@ -{ - config, - lib, - pkgs, - ... -}: let - cfg = config.myConfig.roles.llm-host; -in { - config = lib.mkIf cfg.enable { - environment.systemPackages = with pkgs; [ - ollama - ]; - - myConfig.ollama = { - enable = true; - host = "0.0.0.0"; - port = 11434; - models = config.myConfig.sharedModels; - }; - }; -} diff --git a/modules/services/ollama/common.nix b/modules/services/ollama/common.nix deleted file mode 100644 index 044f5591..00000000 --- a/modules/services/ollama/common.nix +++ /dev/null @@ -1,105 +0,0 @@ -# Shared Ollama configuration and scripts -# -# This module provides common functionality used by the main ollama module. -# It exposes shared values via config._ollamaCommon for internal use. -{ - config, - lib, - pkgs, - ... -}: -with lib; let - cfg = config.myConfig.ollama; - - # Environment variables shared across platforms - baseEnvironment = { - OLLAMA_HOST = "${cfg.host}:${toString cfg.port}"; - }; - - # GPU acceleration environment variables - accelerationEnv = - optionalAttrs (cfg.acceleration == "cuda") {OLLAMA_GPU_DRIVER = "cuda";} - // optionalAttrs (cfg.acceleration == "rocm") {OLLAMA_GPU_DRIVER = "rocm";} - // optionalAttrs (cfg.acceleration == "metal") {OLLAMA_GPU_DRIVER = "metal";}; - - # Combined environment - serviceEnvironment = baseEnvironment // accelerationEnv; - - # Script to wait for Ollama to be ready and pull models - modelPullScript = pkgs.writeShellScript "ollama-pull-models" '' - set -euo pipefail - - OLLAMA_HOST="${cfg.host}:${toString cfg.port}" - MAX_RETRIES=30 - RETRY_INTERVAL=1 - - echo "Waiting for Ollama to be ready..." - for i in $(seq 1 $MAX_RETRIES); do - if ${pkgs.curl}/bin/curl -s "http://${cfg.host}:${toString cfg.port}/api/tags" > /dev/null 2>&1; then - echo "Ollama is ready" - break - fi - if [ "$i" -eq "$MAX_RETRIES" ]; then - echo "ERROR: Ollama failed to start within $MAX_RETRIES seconds" - exit 1 - fi - sleep $RETRY_INTERVAL - done - - # Pre-pull configured models - ${concatMapStringsSep "\n" (model: '' - echo "Pulling model: ${model}" - ${pkgs.ollama}/bin/ollama pull ${model} || echo "WARNING: Failed to pull ${model}, continuing..." - '') - cfg.models} - - echo "Model pull complete" - ''; - - # Main start script that launches Ollama and pulls models - ollamaStartScript = pkgs.writeShellScript "ollama-start" '' - set -euo pipefail - - # Set up environment - export OLLAMA_HOST="${cfg.host}:${toString cfg.port}" - ${optionalString (cfg.acceleration == "cuda") "export OLLAMA_GPU_DRIVER=cuda"} - ${optionalString (cfg.acceleration == "rocm") "export OLLAMA_GPU_DRIVER=rocm"} - ${optionalString (cfg.acceleration == "metal") "export OLLAMA_GPU_DRIVER=metal"} - - # Load environment file if specified - ${optionalString (cfg.environmentFile != null) '' - if [ -f "${cfg.environmentFile}" ]; then - echo "Loading environment from ${cfg.environmentFile}" - set -a - source "${cfg.environmentFile}" - set +a - else - echo "WARNING: Environment file ${cfg.environmentFile} not found" - fi - ''} - - # Start Ollama server in background - ${pkgs.ollama}/bin/ollama serve & - OLLAMA_PID=$! - - # Pull models after server starts - ${modelPullScript} & - - # Keep the server running - wait $OLLAMA_PID - ''; -in { - # Internal option for sharing values between modules (not user-facing) - options._ollamaCommon = mkOption { - type = types.attrs; - internal = true; - description = "Internal: Shared Ollama configuration values"; - }; - - # Export shared values for use by the main module - config._ollamaCommon = { - inherit serviceEnvironment ollamaStartScript modelPullScript; - packages = [pkgs.ollama]; - pathEnv = "/run/current-system/sw/bin:/nix/var/nix/profiles/default/bin:/usr/bin:/bin"; - }; -} diff --git a/modules/services/ollama/darwin.nix b/modules/services/ollama/darwin.nix deleted file mode 100644 index 8a563282..00000000 --- a/modules/services/ollama/darwin.nix +++ /dev/null @@ -1,50 +0,0 @@ -# Ollama service module for Darwin (macOS) -# -# Uses launchd to manage Ollama as a system daemon. -# Imports shared configuration from common.nix. -# Uses nixpkgs ollama package (v0.17.7) which is kept up-to-date by the Nix community. -{ - config, - lib, - ... -}: -with lib; let - cfg = config.myConfig.ollama; - - # Common values are exposed via config._ollamaCommon from common.nix - inherit (config._ollamaCommon) serviceEnvironment ollamaStartScript pathEnv packages; - - # Get the first configured user for Darwin launchd environment - # Falls back to a generic "ollama" user if no users configured - primaryUser = - if config.myConfig.users != [] - then (builtins.head config.myConfig.users).name - else "ollama"; - - # Darwin home directory based on user - darwinHomeDir = "/Users/${primaryUser}"; -in { - imports = [./common.nix]; - - config = mkIf cfg.enable { - environment.systemPackages = packages; - - launchd.daemons.ollama = { - serviceConfig = { - Label = "org.ollama.server"; - ProgramArguments = ["${ollamaStartScript}"]; - RunAtLoad = true; - KeepAlive = true; - StandardOutPath = "/tmp/ollama.log"; - StandardErrorPath = "/tmp/ollama.err"; - EnvironmentVariables = - serviceEnvironment - // { - HOME = darwinHomeDir; - USER = primaryUser; - PATH = pathEnv; - }; - }; - }; - }; -} diff --git a/modules/services/ollama/nixos.nix b/modules/services/ollama/nixos.nix deleted file mode 100644 index f99873a1..00000000 --- a/modules/services/ollama/nixos.nix +++ /dev/null @@ -1,63 +0,0 @@ -# Ollama service module for NixOS (Linux) -# -# Uses systemd to manage Ollama as a system service. -# Imports shared configuration from common.nix. -{ - config, - lib, - ... -}: -with lib; let - cfg = config.myConfig.ollama; - - # Common values are exposed via config._ollamaCommon from common.nix - inherit (config._ollamaCommon) serviceEnvironment ollamaStartScript pathEnv packages; -in { - imports = [./common.nix]; - - config = mkIf cfg.enable { - environment.systemPackages = packages; - - systemd.services.ollama = { - description = "Ollama Local LLM Server"; - wantedBy = ["multi-user.target"]; - after = ["network-online.target"]; - wants = ["network-online.target"]; - - serviceConfig = { - Type = "simple"; - ExecStart = "${ollamaStartScript}"; - Restart = "on-failure"; - RestartSec = "5s"; - - # Environment variables - Environment = mapAttrsToList (n: v: "${n}=${v}") (serviceEnvironment - // { - PATH = pathEnv; - }); - - # Environment file support - EnvironmentFile = mkIf (cfg.environmentFile != null) cfg.environmentFile; - - # Basic hardening - NoNewPrivileges = true; - PrivateTmp = true; - ProtectSystem = "strict"; - ProtectHome = "read-only"; - ReadWritePaths = [ - "/var/lib/ollama" - "/tmp" - ]; - }; - }; - - # Create state directory - systemd.tmpfiles.rules = [ - "d /var/lib/ollama 0755 root root -" - ]; - - # Open firewall if binding to non-localhost - networking.firewall.allowedTCPPorts = - mkIf (cfg.host != "127.0.0.1") [cfg.port]; - }; -} diff --git a/modules/services/vane/darwin.nix b/modules/services/vane/darwin.nix index 9a537776..0abf8dec 100644 --- a/modules/services/vane/darwin.nix +++ b/modules/services/vane/darwin.nix @@ -57,8 +57,9 @@ with lib; let "name": "Higgs Gateway (local)", "type": "openai", "chatModels": [ - {"name": "qwen-coder", "key": "qwen-coder"}, - {"name": "qwen-35b", "key": "qwen-35b"} + {"name": "glm47-flash-4bit", "key": "glm47-flash-4bit"}, + {"name": "glm47-flash-6bit", "key": "glm47-flash-6bit"}, + {"name": "glm47-flash-8bit", "key": "glm47-flash-8bit"} ], "embeddingModels": [ {"name": "qwen-embed", "key": "qwen-embed"} diff --git a/profiles/monkey/profile.nix b/profiles/monkey/profile.nix index fa180104..631e4cf9 100644 --- a/profiles/monkey/profile.nix +++ b/profiles/monkey/profile.nix @@ -10,7 +10,7 @@ desktop.enable = true; workstation.enable = true; entertainment.enable = true; - llm-host.enable = true; + opencode.enable = true; pi.enable = true; homebrew.enable = true; @@ -22,15 +22,6 @@ }; providers = { - ollama = { - name = "Ollama Local"; - baseURL = "http://localhost:11434/v1"; - models = { - "qwen3.5:2b".name = "Qwen 3.5 2B (Fast)"; - "qwen3.5".name = "Qwen 3.5 9B (Balanced)"; - "qwen3.5:122b".name = "Qwen 3.5 122B (Quality)"; - }; - }; opencode-go = { name = "OpenCode Go"; baseURL = "https://opencode.ai/zen/go/v1"; diff --git a/profiles/wweaver/profile.nix b/profiles/wweaver/profile.nix index a2e0a568..77fa833c 100644 --- a/profiles/wweaver/profile.nix +++ b/profiles/wweaver/profile.nix @@ -10,7 +10,7 @@ desktop.enable = true; workstation.enable = true; entertainment.enable = true; - llm-host.enable = true; + opencode.enable = true; pi.enable = true; homebrew.enable = true; @@ -29,14 +29,6 @@ onePasswordItem = "op://Justworks/Justworks LiteLLM/wweaver-poweruser-key"; dynamicModels = true; }; - ollama = { - name = "Ollama (local)"; - baseURL = "http://localhost:11434/v1"; - models = { - "qwen3.5:latest".name = "Qwen 3.5 (7B)"; - "qwen3.5:2b".name = "Qwen 3.5 (2B)"; - }; - }; }; claudeCode = {}; diff --git a/targets/MegamanX/default.nix b/targets/MegamanX/default.nix index 9567e087..74d54188 100644 --- a/targets/MegamanX/default.nix +++ b/targets/MegamanX/default.nix @@ -18,7 +18,7 @@ desktop.enable = true; workstation.enable = true; entertainment.enable = true; - llm-host.enable = true; + opencode.enable = true; pi.enable = true; homebrew.enable = true; @@ -35,12 +35,17 @@ }; models = [ { - path = "mlx-community/Qwen3-Coder-Next-4bit"; - name = "qwen-coder"; + path = "mlx-community/GLM-4.7-Flash-4bit"; + name = "glm47-flash-4bit"; + } + { + path = "mlx-community/GLM-4.7-Flash-6bit"; + name = "glm47-flash-6bit"; + mlxProfile = "balanced"; } { - path = "mlx-community/Qwen3.6-35B-A3B-8bit"; - name = "qwen-35b"; + path = "mlx-community/GLM-4.7-Flash-8bit"; + name = "glm47-flash-8bit"; mlxProfile = "throughput"; } { @@ -93,8 +98,8 @@ searxng.enable = true; opencode = { enable = true; - # Default model - qwen-coder handles both coding and fast chat - model = lib.mkForce "higgs/qwen-coder"; + # Default model - glm47-flash-4bit for fast coding/chat + model = lib.mkForce "higgs/glm47-flash-4bit"; # Configure Higgs as the unified provider providers.higgs = { @@ -103,11 +108,14 @@ baseURL = "http://localhost:8000/v1"; onePasswordItem = ""; models = { - "qwen-coder" = { - name = "Qwen3 Coder Next (Local MLX)"; + "glm47-flash-4bit" = { + name = "GLM-4.7-Flash 4bit (Fast)"; + }; + "glm47-flash-6bit" = { + name = "GLM-4.7-Flash 6bit (Balanced)"; }; - "qwen-35b" = { - name = "Qwen3.6 35B A3B (Local MLX)"; + "glm47-flash-8bit" = { + name = "GLM-4.7-Flash 8bit (Quality)"; }; "qwen-embed" = { name = "Qwen3 Embedding 4B (Local MLX)"; @@ -127,7 +135,7 @@ plan = { description = "Analysis and planning without making changes"; mode = "primary"; - model = "higgs/qwen-35b"; + model = "higgs/glm47-flash-8bit"; prompt = "You are a planning assistant. Analyze code and create plans without making changes."; permission = { edit = "deny"; @@ -161,9 +169,9 @@ ''; models.local-higgs = { - name = "Higgs Gateway (Qwen Coder)"; + name = "Higgs Gateway (GLM-4.7-Flash)"; provider = "openai"; - modelId = "qwen-coder"; + modelId = "glm47-flash-4bit"; baseUrl = "http://localhost:8000/v1"; }; diff --git a/targets/darwin-server/default.nix b/targets/darwin-server/default.nix index 55fae096..7533d6a8 100644 --- a/targets/darwin-server/default.nix +++ b/targets/darwin-server/default.nix @@ -42,12 +42,6 @@ # Pre-pull macOS Tahoe vanilla image prePullImages = ["macos-tahoe-vanilla:latest"]; }; - # Enable Ollama with Qwen3 14B for wadsworth - ollama = { - enable = true; - acceleration = "metal"; # Use Apple Silicon GPU - models = ["qwen3:14b"]; - }; }; # Enable OpenClaw via official nix-openclaw home-manager module @@ -98,21 +92,6 @@ allowFrom = ["279110923438915586"]; dmPolicy = "pairing"; }; - - agents = { - defaults = { - # Use local Ollama with Qwen3 14B (auto-discovery mode) - # Ollama must be running and OLLAMA_API_KEY env var set - model = "ollama/qwen3:14b"; - }; - }; - }; - - # Environment for Ollama connection - environment = { - OLLAMA_HOST = "127.0.0.1:11434"; - # Required for local Ollama auth (not a real API key, just a marker) - OLLAMA_API_KEY = "ollama-local"; }; }; }; diff --git a/targets/wweaver/default.nix b/targets/wweaver/default.nix index baf730cd..3579f1e1 100644 --- a/targets/wweaver/default.nix +++ b/targets/wweaver/default.nix @@ -1,6 +1,5 @@ # wweaver (work laptop) target configuration { - lib, mkUser, inputs, ... @@ -28,22 +27,14 @@ desktop.enable = true; workstation.enable = true; entertainment.enable = true; - llm-host.enable = true; opencode.enable = true; pi.enable = true; homebrew.enable = true; }; - ollama = { - # Bind to all interfaces so Docker containers can access Ollama - host = "0.0.0.0"; - # Smaller/faster models for quick tasks, LiteLLM handles heavy workloads - models = lib.mkForce ["qwen3.5:2b" "qwen3.5"]; - }; + vane = { enable = true; autoStart = true; - # Local Ollama for fast local models - ollamaUrl = "http://host.docker.internal:11434"; # LiteLLM base URL via 1Password (not hardcoded) openaiBaseUrlOpnixItem = "op://Justworks/LiteLLM/baseURL"; # Embedded SearxNG for web search @@ -132,15 +123,6 @@ }; }; }; - ollama = { - npm = "@ai-sdk/openai-compatible"; - name = "Ollama (local)"; - baseURL = "http://localhost:11434/v1"; - models = { - "qwen3.5:latest" = {name = "Qwen 3.5 (7B)";}; - "qwen3.5:2b" = {name = "Qwen 3.5 (2B)";}; - }; - }; }; }; claude-code = { diff --git a/tests/default.nix b/tests/default.nix index 1af34430..e458dd43 100644 --- a/tests/default.nix +++ b/tests/default.nix @@ -49,7 +49,6 @@ in role-composition = testRoles.allRoleTests; role-packages = testRoles.allRoleTests; role-cascades = testRoles.allRoleTests; - llm-host-shared-models = testRoles.allRoleTests; no-dead-development-option = testRoles.allRoleTests; entertainment-nixos = testRoles.allRoleTests; @@ -89,8 +88,6 @@ in sketchybar-entrypoint = testSketchybar.sketchybarEntryPointTest; # Service module tests - ollama-options = testServices.ollamaOptionsTest; - ollama-custom-options = testServices.ollamaCustomOptionsTest; vane-options = testServices.vaneOptionsTest; vane-custom-options = testServices.vaneCustomOptionsTest; openclaw-options = testServices.openclawOptionsTest; diff --git a/tests/test-coverage.nix b/tests/test-coverage.nix index edf17ffe..30af486c 100644 --- a/tests/test-coverage.nix +++ b/tests/test-coverage.nix @@ -47,7 +47,6 @@ "roles/entertainment.nix" "roles/foundation.nix" "roles/gaming.nix" - "roles/llm-host.nix" "roles/microvm-host.nix" "roles/opencode.nix" "roles/pi.nix" @@ -59,9 +58,6 @@ "nixos/ghostty-terminfo.nix" "nixos/streaming.nix" # services/ - "services/ollama/common.nix" - "services/ollama/darwin.nix" - "services/ollama/nixos.nix" "services/openclaw/default.nix" "services/microvm-host/default.nix" "services/higgs/darwin.nix" @@ -90,7 +86,6 @@ "roles/entertainment.nix" "roles/foundation.nix" "roles/gaming.nix" - "roles/llm-host.nix" "roles/microvm-host.nix" "roles/opencode.nix" "roles/pi.nix" @@ -112,10 +107,7 @@ # Tested via test-roles.nix (microvm-host added to allRoles) # services/microvm-host tracked via role imports "services/microvm-host/default.nix" - # Tested via test-services.nix (ollama, vane, openclaw option tests) - "services/ollama/common.nix" - "services/ollama/darwin.nix" - "services/ollama/nixos.nix" + # Tested via test-services.nix (vane, openclaw option tests) "services/openclaw/default.nix" "services/vane/common.nix" "services/vane/darwin.nix" diff --git a/tests/test-packages.nix b/tests/test-packages.nix index 6f851f6e..f7313436 100644 --- a/tests/test-packages.nix +++ b/tests/test-packages.nix @@ -131,7 +131,7 @@ ${pkgs.lib.concatMapStringsSep "\n" (name: ''echo " Role '${name}': defined"'') roleNames} # Verify expected roles are present - EXPECTED_ROLES="foundation developer creative gaming desktop workstation entertainment agent-skills opencode claude pi llm-host" + EXPECTED_ROLES="foundation developer creative gaming desktop workstation entertainment agent-skills opencode claude pi" ACTUAL_ROLES="${builtins.concatStringsSep " " roleNames}" for role in $EXPECTED_ROLES; do @@ -199,8 +199,6 @@ echo " users count: ${toString (builtins.length evaluatedConfig.users)}" echo " first user name: ${(builtins.head evaluatedConfig.users).name}" echo " isDarwin: ${builtins.toJSON evaluatedConfig.isDarwin}" - echo " ollama.enable: ${builtins.toJSON evaluatedConfig.ollama.enable}" - echo " ollama.port: ${toString evaluatedConfig.ollama.port}" echo " opencode.enable: ${builtins.toJSON evaluatedConfig.opencode.enable}" echo " zellij.enable: ${builtins.toJSON evaluatedConfig.zellij.enable}" diff --git a/tests/test-roles.nix b/tests/test-roles.nix index 84cf32e2..21718ecd 100644 --- a/tests/test-roles.nix +++ b/tests/test-roles.nix @@ -59,55 +59,6 @@ } ]; - # Evaluate llm-host role with default sharedModels - llmHostDefaultEval = - (lib.evalModules { - modules = - stubModules - ++ [ - { - config.myConfig = { - users = [ - { - name = "testuser"; - email = "test@example.com"; - fullName = "Test User"; - isAdmin = true; - sshIncludes = []; - } - ]; - roles.llm-host.enable = true; - }; - } - ]; - }) - .config; - - # Evaluate llm-host role with custom sharedModels - llmHostCustomEval = - (lib.evalModules { - modules = - stubModules - ++ [ - { - config.myConfig = { - users = [ - { - name = "testuser"; - email = "test@example.com"; - fullName = "Test User"; - isAdmin = true; - sshIncludes = []; - } - ]; - roles.llm-host.enable = true; - sharedModels = ["llama3.2" "mistral:7b"]; - }; - } - ]; - }) - .config; - # Helper: evaluate modules with a specific role enabled evalWithRole = roleName: (lib.evalModules { @@ -161,7 +112,6 @@ opencode.enable = true; claude.enable = true; pi.enable = true; - llm-host.enable = true; assistant.enable = true; email-backup.enable = true; microvm-host.enable = true; @@ -185,7 +135,6 @@ "opencode" "claude" "pi" - "llm-host" "assistant" "email-backup" "microvm-host" @@ -204,7 +153,7 @@ opencode = ["opencode" "rtk"]; claude = ["claude-code" "rtk"]; pi = ["pi-coding-agent" "rtk"]; - llm-host = ["ollama"]; + assistant = ["himalaya" "gmailctl"]; email-backup = ["isync" "notmuch" "restic"]; # microvm-host packages are NixOS-only (guarded by isNixOS check). @@ -223,7 +172,7 @@ "agent-skills.enable" = true; "pi.enable" = true; }; - llm-host = {"ollama.enable" = true;}; + assistant = {"email-agent.enable" = true;}; email-backup = {"email-backup.enable" = true;}; foundation = { @@ -381,35 +330,6 @@ echo "All role cascades work correctly" ''; - llmHostScript = let - defaultModels = llmHostDefaultEval.myConfig.sharedModels; - defaultOllamaModels = llmHostDefaultEval.myConfig.ollama.models; - customOllamaModels = llmHostCustomEval.myConfig.ollama.models; - in '' - echo "=== Testing llm-host sharedModels wiring ===" - ${ - if defaultModels == defaultOllamaModels - then "echo \" default sharedModels propagated to ollama.models: OK\"" - else '' - echo " sharedModels default should propagate to ollama.models!" - echo " sharedModels = ${builtins.toJSON defaultModels}" - echo " ollama.models = ${builtins.toJSON defaultOllamaModels}" - exit 1 - '' - } - ${ - if customOllamaModels == ["llama3.2" "mistral:7b"] - then "echo \" custom sharedModels reflected in ollama.models: OK\"" - else '' - echo " custom sharedModels should be reflected in ollama.models!" - echo " expected = [\"llama3.2\" \"mistral:7b\"]" - echo " got = ${builtins.toJSON customOllamaModels}" - exit 1 - '' - } - echo "All llm-host sharedModels tests passed" - ''; - deadDevOptionScript = let testEval = pkgs.lib.evalModules { modules = [ @@ -487,8 +407,6 @@ echo "" ${cascadeScript} echo "" - ${llmHostScript} - echo "" ${deadDevOptionScript} echo "" ${entertainmentNixosScript} @@ -503,6 +421,5 @@ in { rolePackageInclusionTest = allRoleTests; roleCascadeTest = allRoleTests; noDeadDevelopmentOptionTest = allRoleTests; - llmHostSharedModelsTest = allRoleTests; entertainmentNixosTest = allRoleTests; } diff --git a/tests/test-services.nix b/tests/test-services.nix index 193e2481..e9bbf486 100644 --- a/tests/test-services.nix +++ b/tests/test-services.nix @@ -1,5 +1,5 @@ # Service module option tests using evalModules -# Tests ollama, vane, and openclaw options without requiring platform-specific modules +# Tests vane and openclaw options without requiring platform-specific modules {pkgs, ...}: let inherit (pkgs) lib; @@ -17,36 +17,6 @@ } ]; - # Evaluate ollama options with defaults - ollamaDefaultEval = - (lib.evalModules { - modules = - stubModules - ++ [ - { - config.myConfig.ollama.enable = false; - } - ]; - }).config.myConfig.ollama; - - # Evaluate ollama with custom values - ollamaCustomEval = - (lib.evalModules { - modules = - stubModules - ++ [ - { - config.myConfig.ollama = { - enable = true; - host = "0.0.0.0"; - port = 12345; - models = ["llama3.2" "qwen3:4b"]; - acceleration = "metal"; - }; - } - ]; - }).config.myConfig.ollama; - # Evaluate vane options with defaults vaneDefaultEval = (lib.evalModules { @@ -207,94 +177,6 @@ ]; }).config.services.openclaw; in { - # Test ollama option defaults - ollamaOptionsTest = - pkgs.runCommand "test-ollama-options" - {} - '' - echo "=== Testing Ollama Option Defaults ===" - - ${ - if !ollamaDefaultEval.enable - then ''echo " enable default = false: OK"'' - else ''echo " enable should default to false!"; exit 1'' - } - - ${ - if ollamaDefaultEval.host == "127.0.0.1" - then ''echo " host default = 127.0.0.1: OK"'' - else ''echo " host should default to 127.0.0.1!"; exit 1'' - } - - ${ - if ollamaDefaultEval.port == 11434 - then ''echo " port default = 11434: OK"'' - else ''echo " port should default to 11434!"; exit 1'' - } - - ${ - if ollamaDefaultEval.models == [] - then ''echo " models default = []: OK"'' - else ''echo " models should default to empty list!"; exit 1'' - } - - ${ - if ollamaDefaultEval.acceleration == null - then ''echo " acceleration default = null: OK"'' - else ''echo " acceleration should default to null!"; exit 1'' - } - - ${ - if ollamaDefaultEval.environmentFile == null - then ''echo " environmentFile default = null: OK"'' - else ''echo " environmentFile should default to null!"; exit 1'' - } - - echo "All ollama option defaults verified" - touch $out - ''; - - # Test ollama custom option values - ollamaCustomOptionsTest = - pkgs.runCommand "test-ollama-custom-options" - {} - '' - echo "=== Testing Ollama Custom Options ===" - - ${ - if ollamaCustomEval.enable - then ''echo " enable = true: OK"'' - else ''echo " enable should be true!"; exit 1'' - } - - ${ - if ollamaCustomEval.host == "0.0.0.0" - then ''echo " host = 0.0.0.0: OK"'' - else ''echo " host should be 0.0.0.0!"; exit 1'' - } - - ${ - if ollamaCustomEval.port == 12345 - then ''echo " port = 12345: OK"'' - else ''echo " port should be 12345!"; exit 1'' - } - - ${ - if builtins.length ollamaCustomEval.models == 2 - then ''echo " models count = 2: OK"'' - else ''echo " models should have 2 entries!"; exit 1'' - } - - ${ - if ollamaCustomEval.acceleration == "metal" - then ''echo " acceleration = metal: OK"'' - else ''echo " acceleration should be metal!"; exit 1'' - } - - echo "All ollama custom options verified" - touch $out - ''; - # Test vane option defaults vaneOptionsTest = pkgs.runCommand "test-vane-options" From 3f9a42fe9d41cdea9a208aef0e54f01140d94b3e Mon Sep 17 00:00:00 2001 From: Will Weaver Date: Sat, 6 Jun 2026 17:26:58 -0400 Subject: [PATCH 02/14] fix: update monkey profile opencode model to glm47-flash-4bit --- profiles/monkey/profile.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/profiles/monkey/profile.nix b/profiles/monkey/profile.nix index 631e4cf9..ab1e80d9 100644 --- a/profiles/monkey/profile.nix +++ b/profiles/monkey/profile.nix @@ -17,7 +17,7 @@ }; opencode = { - model = "ollama/qwen3.5"; + model = "higgs/glm47-flash-4bit"; enableBrowserAgents = false; }; From 32acdc220a959ced322bcf9d1bc7e248f3b5913d Mon Sep 17 00:00:00 2001 From: Will Weaver Date: Sat, 6 Jun 2026 17:53:26 -0400 Subject: [PATCH 03/14] fix: add WatchPaths to Higgs launchd for auto-restart on config change --- modules/home-manager/shell.nix | 13 ++++++++----- modules/services/higgs/darwin.nix | 1 + 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/modules/home-manager/shell.nix b/modules/home-manager/shell.nix index 623043e3..cf55b4c9 100644 --- a/modules/home-manager/shell.nix +++ b/modules/home-manager/shell.nix @@ -10,11 +10,14 @@ programs.zsh = { enable = true; - initContent = '' - # Source switch-nix function (same source as system-wide install) - if [ -f /etc/nix-cloud-init/switch-nix ]; then - . /etc/nix-cloud-init/switch-nix - fi + initContent = '' + # pipx-installed CLI tools + export PATH="$PATH:$HOME/.local/bin" + + # Source switch-nix function (same source as system-wide install) + if [ -f /etc/nix-cloud-init/switch-nix ]; then + . /etc/nix-cloud-init/switch-nix + fi # Docker functions drm() { docker rm $(docker ps -q -a); } diff --git a/modules/services/higgs/darwin.nix b/modules/services/higgs/darwin.nix index 59bb3a0a..12985262 100644 --- a/modules/services/higgs/darwin.nix +++ b/modules/services/higgs/darwin.nix @@ -28,6 +28,7 @@ in { ]; RunAtLoad = true; KeepAlive = true; + WatchPaths = ["${darwinHomeDir}/.config/higgs/config.toml"]; StandardOutPath = "/tmp/higgs.log"; StandardErrorPath = "/tmp/higgs.err"; EnvironmentVariables = { From 0b41aaba032b370de783a2209aeb75c7df23fecd Mon Sep 17 00:00:00 2001 From: Will Weaver Date: Sat, 6 Jun 2026 18:11:15 -0400 Subject: [PATCH 04/14] feat: auto-download Higgs MLX models to HuggingFace cache on switch --- modules/home-manager/higgs.nix | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/modules/home-manager/higgs.nix b/modules/home-manager/higgs.nix index 001a6c42..08c75f76 100644 --- a/modules/home-manager/higgs.nix +++ b/modules/home-manager/higgs.nix @@ -147,8 +147,27 @@ with lib; let '') providerNames)} ''; + modelPaths = map (m: m.path) cfg.models; + + # Script that downloads models not yet in HuggingFace cache + downloadScript = pkgs.writeShellScript "download-higgs-models" '' + set -euo pipefail + CACHE_DIR="$HOME/.cache/huggingface/hub" + HUGGINGFACE_CLI="${pkgs.huggingface_hub}/bin/huggingface-cli" + ${concatStringsSep "\n" (map (path: '' + MODEL_PATH='${path}' + CACHE_NAME="models--$(echo "$MODEL_PATH" | tr '/' '--')" + if [ ! -d "$CACHE_DIR/$CACHE_NAME" ]; then + echo " Downloading $MODEL_PATH..." + $HUGGINGFACE_CLI download "$MODEL_PATH" + fi + '') + modelPaths)} + ''; in { config = mkIf cfg.enable { + home.packages = [pkgs.huggingface_hub]; + xdg.configFile."higgs/config.toml" = { source = tomlFormat.generate "config.toml" tomlConfig; force = true; @@ -167,6 +186,12 @@ in { '' ); + # Download missing models to HuggingFace cache before Higgs starts + home.activation.downloadHiggsModels = lib.hm.dag.entryAfter ["writeBoundary"] '' + echo "Checking Higgs model cache..." + ${downloadScript} + ''; + # Add higgs shell integration programs.zsh.initContent = mkAfter '' # Higgs shell integration From cc2d11adcd134fd85058783a0497efbe3a996387 Mon Sep 17 00:00:00 2001 From: Will Weaver Date: Sat, 6 Jun 2026 18:15:34 -0400 Subject: [PATCH 05/14] feat: manage Higgs MLX models as Nix packages (no runtime downloads) --- flake.nix | 2 +- modules/common/options.nix | 5 ++++ modules/home-manager/higgs.nix | 30 ++++-------------------- overlays/default.nix | 19 +++++++++++++++ packages/higgs-mlx/default.nix | 43 ++++++++++++++++++++++++++++++++++ 5 files changed, 72 insertions(+), 27 deletions(-) create mode 100644 packages/higgs-mlx/default.nix diff --git a/flake.nix b/flake.nix index a41984b0..7ef9e568 100644 --- a/flake.nix +++ b/flake.nix @@ -205,7 +205,7 @@ }; in { - inherit (pkgs) rtk yaks vane; + inherit (pkgs) rtk yaks vane glm47-flash-4bit glm47-flash-6bit glm47-flash-8bit; inherit (inputs.devenv.packages.${system}) devenv; installer = pkgs.callPackage ./packages/installer {}; } diff --git a/modules/common/options.nix b/modules/common/options.nix index 501b9069..f73d28a8 100644 --- a/modules/common/options.nix +++ b/modules/common/options.nix @@ -1361,6 +1361,11 @@ with lib; { type = types.str; description = "Model path or HuggingFace ID"; }; + package = mkOption { + type = types.nullOr types.package; + default = null; + description = "Nix package providing the model (overrides path with store path)"; + }; name = mkOption { type = types.nullOr types.str; default = null; diff --git a/modules/home-manager/higgs.nix b/modules/home-manager/higgs.nix index 08c75f76..50f09833 100644 --- a/modules/home-manager/higgs.nix +++ b/modules/home-manager/higgs.nix @@ -33,7 +33,10 @@ with lib; let modelsConfig = map (m: clean { - path = m.path; + path = + if m.package != null + then "${m.package}" + else m.path; name = m.name; mlx_profile = m.mlxProfile; batch = m.batch; @@ -147,27 +150,8 @@ with lib; let '') providerNames)} ''; - modelPaths = map (m: m.path) cfg.models; - - # Script that downloads models not yet in HuggingFace cache - downloadScript = pkgs.writeShellScript "download-higgs-models" '' - set -euo pipefail - CACHE_DIR="$HOME/.cache/huggingface/hub" - HUGGINGFACE_CLI="${pkgs.huggingface_hub}/bin/huggingface-cli" - ${concatStringsSep "\n" (map (path: '' - MODEL_PATH='${path}' - CACHE_NAME="models--$(echo "$MODEL_PATH" | tr '/' '--')" - if [ ! -d "$CACHE_DIR/$CACHE_NAME" ]; then - echo " Downloading $MODEL_PATH..." - $HUGGINGFACE_CLI download "$MODEL_PATH" - fi - '') - modelPaths)} - ''; in { config = mkIf cfg.enable { - home.packages = [pkgs.huggingface_hub]; - xdg.configFile."higgs/config.toml" = { source = tomlFormat.generate "config.toml" tomlConfig; force = true; @@ -186,12 +170,6 @@ in { '' ); - # Download missing models to HuggingFace cache before Higgs starts - home.activation.downloadHiggsModels = lib.hm.dag.entryAfter ["writeBoundary"] '' - echo "Checking Higgs model cache..." - ${downloadScript} - ''; - # Add higgs shell integration programs.zsh.initContent = mkAfter '' # Higgs shell integration diff --git a/overlays/default.nix b/overlays/default.nix index 9eb535cc..6550492c 100644 --- a/overlays/default.nix +++ b/overlays/default.nix @@ -4,6 +4,25 @@ final: _prev: { yaks = final.callPackage ../packages/yaks {}; lume = final.callPackage ../packages/lume {}; vane = final.callPackage ../packages/vane {}; + higgs-mlx = final.callPackage ../packages/higgs-mlx { + inherit (final) lib stdenv python313Packages; + }; + + glm47-flash-4bit = final.higgs-mlx.fetchModel { + name = "glm47-flash-4bit"; + modelPath = "mlx-community/GLM-4.7-Flash-4bit"; + outputHash = final.lib.fakeHash; + }; + glm47-flash-6bit = final.higgs-mlx.fetchModel { + name = "glm47-flash-6bit"; + modelPath = "mlx-community/GLM-4.7-Flash-6bit"; + outputHash = final.lib.fakeHash; + }; + glm47-flash-8bit = final.higgs-mlx.fetchModel { + name = "glm47-flash-8bit"; + modelPath = "mlx-community/GLM-4.7-Flash-8bit"; + outputHash = final.lib.fakeHash; + }; # Package Override Registry # See ../docs/reference/package-overrides.md for full documentation diff --git a/packages/higgs-mlx/default.nix b/packages/higgs-mlx/default.nix new file mode 100644 index 00000000..98325a29 --- /dev/null +++ b/packages/higgs-mlx/default.nix @@ -0,0 +1,43 @@ +# MLX model packages fetched from HuggingFace +# Each model is a fixed-output derivation for reproducibility and caching. +{ + lib, + stdenv, + python313Packages, + ... +}: let + huggingface-hub = python313Packages.huggingface-hub; + + # Fetch an MLX model from HuggingFace as a fixed-output derivation. + # To compute outputHash: + # 1. Set outputHash = lib.fakeHash and build + # 2. Nix will fail with the actual hash — copy it here + # 3. Rebuild — subsequent builds are cached + fetchModel = { + name, + modelPath, + outputHash, + }: + stdenv.mkDerivation { + pname = name; + version = "0"; + src = null; + nativeBuildInputs = [huggingface-hub]; + outputHashMode = "recursive"; + outputHashAlgo = "sha256"; + inherit outputHash; + buildPhase = '' + export HF_HOME="$PWD/.cache" + ${huggingface-hub}/bin/huggingface-cli download "${modelPath}" + mkdir -p $out + cp -r "$HF_HOME/hub/models--$(echo "${modelPath}" | tr '/' '--')/snapshots/"*/* "$out/" + ''; + installPhase = "true"; + meta = { + description = "MLX model: ${modelPath}"; + platforms = lib.platforms.darwin; + }; + }; +in { + inherit fetchModel; +} From 4e297548930911953d54e67c775778ca4d239c1b Mon Sep 17 00:00:00 2001 From: Will Weaver Date: Sat, 6 Jun 2026 18:16:00 -0400 Subject: [PATCH 06/14] feat: manage Higgs MLX models as Nix packages (no runtime downloads) --- overlays/default.nix | 2 +- packages/higgs-mlx/default.nix | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/overlays/default.nix b/overlays/default.nix index 6550492c..50ff2d54 100644 --- a/overlays/default.nix +++ b/overlays/default.nix @@ -5,7 +5,7 @@ final: _prev: { lume = final.callPackage ../packages/lume {}; vane = final.callPackage ../packages/vane {}; higgs-mlx = final.callPackage ../packages/higgs-mlx { - inherit (final) lib stdenv python313Packages; + inherit (final) lib stdenvNoCC python313Packages; }; glm47-flash-4bit = final.higgs-mlx.fetchModel { diff --git a/packages/higgs-mlx/default.nix b/packages/higgs-mlx/default.nix index 98325a29..9ba6a06d 100644 --- a/packages/higgs-mlx/default.nix +++ b/packages/higgs-mlx/default.nix @@ -2,12 +2,13 @@ # Each model is a fixed-output derivation for reproducibility and caching. { lib, - stdenv, + stdenvNoCC, python313Packages, ... }: let huggingface-hub = python313Packages.huggingface-hub; - + inherit (builtins) replaceStrings; +in { # Fetch an MLX model from HuggingFace as a fixed-output derivation. # To compute outputHash: # 1. Set outputHash = lib.fakeHash and build @@ -18,10 +19,10 @@ modelPath, outputHash, }: - stdenv.mkDerivation { + stdenvNoCC.mkDerivation { pname = name; version = "0"; - src = null; + src = builtins.toFile "src" "dummy"; nativeBuildInputs = [huggingface-hub]; outputHashMode = "recursive"; outputHashAlgo = "sha256"; @@ -38,6 +39,4 @@ platforms = lib.platforms.darwin; }; }; -in { - inherit fetchModel; } From ff3e37cb272cc42d8fd056d5da77cbbfbb514fe6 Mon Sep 17 00:00:00 2001 From: Will Weaver Date: Sat, 6 Jun 2026 18:16:16 -0400 Subject: [PATCH 07/14] feat: manage Higgs MLX models as Nix packages (no runtime downloads) --- packages/higgs-mlx/default.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/higgs-mlx/default.nix b/packages/higgs-mlx/default.nix index 9ba6a06d..4d8c86c9 100644 --- a/packages/higgs-mlx/default.nix +++ b/packages/higgs-mlx/default.nix @@ -22,11 +22,11 @@ in { stdenvNoCC.mkDerivation { pname = name; version = "0"; - src = builtins.toFile "src" "dummy"; nativeBuildInputs = [huggingface-hub]; outputHashMode = "recursive"; outputHashAlgo = "sha256"; inherit outputHash; + phases = ["buildPhase" "installPhase"]; buildPhase = '' export HF_HOME="$PWD/.cache" ${huggingface-hub}/bin/huggingface-cli download "${modelPath}" From 1eddead9cb3256683ecb816a0e632fc6bc10f01b Mon Sep 17 00:00:00 2001 From: Will Weaver Date: Sat, 6 Jun 2026 18:17:32 -0400 Subject: [PATCH 08/14] feat: manage Higgs MLX models as Nix packages (no runtime downloads) --- overlays/default.nix | 2 +- packages/higgs-mlx/default.nix | 23 +++++++++++++++++------ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/overlays/default.nix b/overlays/default.nix index 50ff2d54..4f741425 100644 --- a/overlays/default.nix +++ b/overlays/default.nix @@ -5,7 +5,7 @@ final: _prev: { lume = final.callPackage ../packages/lume {}; vane = final.callPackage ../packages/vane {}; higgs-mlx = final.callPackage ../packages/higgs-mlx { - inherit (final) lib stdenvNoCC python313Packages; + inherit (final) lib stdenvNoCC curl jq gnugrep gnused; }; glm47-flash-4bit = final.higgs-mlx.fetchModel { diff --git a/packages/higgs-mlx/default.nix b/packages/higgs-mlx/default.nix index 4d8c86c9..ad534c16 100644 --- a/packages/higgs-mlx/default.nix +++ b/packages/higgs-mlx/default.nix @@ -3,10 +3,12 @@ { lib, stdenvNoCC, - python313Packages, + curl, + jq, + gnugrep, + gnused, ... }: let - huggingface-hub = python313Packages.huggingface-hub; inherit (builtins) replaceStrings; in { # Fetch an MLX model from HuggingFace as a fixed-output derivation. @@ -22,16 +24,25 @@ in { stdenvNoCC.mkDerivation { pname = name; version = "0"; - nativeBuildInputs = [huggingface-hub]; + nativeBuildInputs = [curl jq gnugrep gnused]; outputHashMode = "recursive"; outputHashAlgo = "sha256"; inherit outputHash; phases = ["buildPhase" "installPhase"]; buildPhase = '' - export HF_HOME="$PWD/.cache" - ${huggingface-hub}/bin/huggingface-cli download "${modelPath}" + echo "Fetching file list for ${modelPath}..." + FILES=$(${curl}/bin/curl -sL "https://huggingface.co/api/models/${modelPath}" | \ + ${jq}/bin/jq -r '.siblings[] | select(.rfilename | test("\\.(safetensors|json)$")) | .rfilename') + mkdir -p $out - cp -r "$HF_HOME/hub/models--$(echo "${modelPath}" | tr '/' '--')/snapshots/"*/* "$out/" + + echo "$FILES" | while read -r FILE; do + [ -z "$FILE" ] && continue + echo " Downloading $FILE..." + ${curl}/bin/curl -sL "https://huggingface.co/${modelPath}/resolve/main/$FILE" \ + -o "$out/$FILE" + done + echo "Done." ''; installPhase = "true"; meta = { From 267c1b5a02c097fbef69529ddbff15ef2f2ea006 Mon Sep 17 00:00:00 2001 From: Will Weaver Date: Sat, 6 Jun 2026 18:17:52 -0400 Subject: [PATCH 09/14] feat: manage Higgs MLX models as Nix packages (no runtime downloads) --- overlays/default.nix | 2 +- packages/higgs-mlx/default.nix | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/overlays/default.nix b/overlays/default.nix index 4f741425..69493fb5 100644 --- a/overlays/default.nix +++ b/overlays/default.nix @@ -5,7 +5,7 @@ final: _prev: { lume = final.callPackage ../packages/lume {}; vane = final.callPackage ../packages/vane {}; higgs-mlx = final.callPackage ../packages/higgs-mlx { - inherit (final) lib stdenvNoCC curl jq gnugrep gnused; + inherit (final) lib stdenvNoCC curl jq gnugrep gnused cacert; }; glm47-flash-4bit = final.higgs-mlx.fetchModel { diff --git a/packages/higgs-mlx/default.nix b/packages/higgs-mlx/default.nix index ad534c16..4c745426 100644 --- a/packages/higgs-mlx/default.nix +++ b/packages/higgs-mlx/default.nix @@ -7,6 +7,7 @@ jq, gnugrep, gnused, + cacert, ... }: let inherit (builtins) replaceStrings; @@ -24,7 +25,8 @@ in { stdenvNoCC.mkDerivation { pname = name; version = "0"; - nativeBuildInputs = [curl jq gnugrep gnused]; + nativeBuildInputs = [curl jq gnugrep gnused cacert]; + SSL_CERT_FILE = "${cacert}/etc/ssl/certs/ca-bundle.crt"; outputHashMode = "recursive"; outputHashAlgo = "sha256"; inherit outputHash; From 3f0cd3287532834fe773c418f9c36b001eaf77c9 Mon Sep 17 00:00:00 2001 From: Will Weaver Date: Sat, 6 Jun 2026 18:43:59 -0400 Subject: [PATCH 10/14] feat: manage Higgs MLX models as Nix packages (no runtime downloads) --- overlays/default.nix | 6 +++--- targets/MegamanX/default.nix | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/overlays/default.nix b/overlays/default.nix index 69493fb5..f004e377 100644 --- a/overlays/default.nix +++ b/overlays/default.nix @@ -11,17 +11,17 @@ final: _prev: { glm47-flash-4bit = final.higgs-mlx.fetchModel { name = "glm47-flash-4bit"; modelPath = "mlx-community/GLM-4.7-Flash-4bit"; - outputHash = final.lib.fakeHash; + outputHash = "sha256-XxjuAtKsDkGuSROHYvj7Mv7IfgPj++4H3C6Qxhzj/g0="; }; glm47-flash-6bit = final.higgs-mlx.fetchModel { name = "glm47-flash-6bit"; modelPath = "mlx-community/GLM-4.7-Flash-6bit"; - outputHash = final.lib.fakeHash; + outputHash = "sha256-mKtbtBky4Nh3bqFTjo5i8+va4Om8ynS6utIgvUYSJMs="; }; glm47-flash-8bit = final.higgs-mlx.fetchModel { name = "glm47-flash-8bit"; modelPath = "mlx-community/GLM-4.7-Flash-8bit"; - outputHash = final.lib.fakeHash; + outputHash = "sha256-IoyDBLeU63aoDV8/E2lOcHNHmBEIo/uhyHWHlSFuve4="; }; # Package Override Registry diff --git a/targets/MegamanX/default.nix b/targets/MegamanX/default.nix index 74d54188..b41e6862 100644 --- a/targets/MegamanX/default.nix +++ b/targets/MegamanX/default.nix @@ -1,6 +1,7 @@ # MegamanX (personal desktop) target configuration { lib, + pkgs, mkUser, inputs, ... @@ -37,16 +38,19 @@ { path = "mlx-community/GLM-4.7-Flash-4bit"; name = "glm47-flash-4bit"; + package = pkgs.glm47-flash-4bit; } { path = "mlx-community/GLM-4.7-Flash-6bit"; name = "glm47-flash-6bit"; mlxProfile = "balanced"; + package = pkgs.glm47-flash-6bit; } { path = "mlx-community/GLM-4.7-Flash-8bit"; name = "glm47-flash-8bit"; mlxProfile = "throughput"; + package = pkgs.glm47-flash-8bit; } { path = "mlx-community/Qwen3-Embedding-4B-4bit-DWQ"; From b59e7a81a79f6ca03f702b86b6dedfbde1386a40 Mon Sep 17 00:00:00 2001 From: Will Weaver Date: Sat, 6 Jun 2026 19:29:04 -0400 Subject: [PATCH 11/14] feat: manage Higgs MLX models as Nix packages (no runtime downloads) --- flake.nix | 2 +- overlays/default.nix | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index 7ef9e568..5db80624 100644 --- a/flake.nix +++ b/flake.nix @@ -205,7 +205,7 @@ }; in { - inherit (pkgs) rtk yaks vane glm47-flash-4bit glm47-flash-6bit glm47-flash-8bit; + inherit (pkgs) rtk yaks vane glm47-flash-4bit glm47-flash-6bit glm47-flash-8bit qwen-embed; inherit (inputs.devenv.packages.${system}) devenv; installer = pkgs.callPackage ./packages/installer {}; } diff --git a/overlays/default.nix b/overlays/default.nix index f004e377..18154094 100644 --- a/overlays/default.nix +++ b/overlays/default.nix @@ -23,6 +23,11 @@ final: _prev: { modelPath = "mlx-community/GLM-4.7-Flash-8bit"; outputHash = "sha256-IoyDBLeU63aoDV8/E2lOcHNHmBEIo/uhyHWHlSFuve4="; }; + qwen-embed = final.higgs-mlx.fetchModel { + name = "qwen-embed"; + modelPath = "mlx-community/Qwen3-Embedding-4B-4bit-DWQ"; + outputHash = final.lib.fakeHash; + }; # Package Override Registry # See ../docs/reference/package-overrides.md for full documentation From f4d76d883bf70b600f86d240e2516a5900855a56 Mon Sep 17 00:00:00 2001 From: Will Weaver Date: Sat, 6 Jun 2026 19:30:05 -0400 Subject: [PATCH 12/14] feat: manage all Higgs MLX models as Nix packages --- overlays/default.nix | 2 +- targets/MegamanX/default.nix | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/overlays/default.nix b/overlays/default.nix index 18154094..1a25081c 100644 --- a/overlays/default.nix +++ b/overlays/default.nix @@ -26,7 +26,7 @@ final: _prev: { qwen-embed = final.higgs-mlx.fetchModel { name = "qwen-embed"; modelPath = "mlx-community/Qwen3-Embedding-4B-4bit-DWQ"; - outputHash = final.lib.fakeHash; + outputHash = "sha256-op+yFqs/ZaP8imito9jFYhSpjnFAq2wLMnZy5bo0tXw="; }; # Package Override Registry diff --git a/targets/MegamanX/default.nix b/targets/MegamanX/default.nix index b41e6862..e314329b 100644 --- a/targets/MegamanX/default.nix +++ b/targets/MegamanX/default.nix @@ -56,6 +56,7 @@ path = "mlx-community/Qwen3-Embedding-4B-4bit-DWQ"; name = "qwen-embed"; mlxProfile = "latency"; + package = pkgs.qwen-embed; } ]; providers = { From 657c1466c7575cadd78fa435845affc127409cdb Mon Sep 17 00:00:00 2001 From: Will Weaver Date: Sat, 6 Jun 2026 22:51:05 -0400 Subject: [PATCH 13/14] fix: format shell.nix (alejandra) --- modules/home-manager/shell.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/home-manager/shell.nix b/modules/home-manager/shell.nix index cf55b4c9..c102ed58 100644 --- a/modules/home-manager/shell.nix +++ b/modules/home-manager/shell.nix @@ -10,7 +10,7 @@ programs.zsh = { enable = true; - initContent = '' + initContent = '' # pipx-installed CLI tools export PATH="$PATH:$HOME/.local/bin" From 9d55f4741df3a5a0915409e2c6db39d4c1dd84d6 Mon Sep 17 00:00:00 2001 From: Will Weaver Date: Sun, 7 Jun 2026 00:07:39 -0400 Subject: [PATCH 14/14] fix: remove unused replaceStrings import in higgs-mlx package --- packages/higgs-mlx/default.nix | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/higgs-mlx/default.nix b/packages/higgs-mlx/default.nix index 4c745426..002d5bf4 100644 --- a/packages/higgs-mlx/default.nix +++ b/packages/higgs-mlx/default.nix @@ -10,7 +10,6 @@ cacert, ... }: let - inherit (builtins) replaceStrings; in { # Fetch an MLX model from HuggingFace as a fixed-output derivation. # To compute outputHash: