From 664dbf32a7beb2138cc3053fa92e14e92a2da68b Mon Sep 17 00:00:00 2001 From: "K. Isom" Date: Sat, 19 Sep 2026 17:50:35 -0700 Subject: [PATCH 01/11] removee gh --- hw/straylight/default.nix | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/straylight/default.nix b/hw/straylight/default.nix index 26a50cc..5d229df 100644 --- a/hw/straylight/default.nix +++ b/hw/straylight/default.nix @@ -326,7 +326,6 @@ in # Pinned to the upstream flake (v0.9.0); nixpkgs-unstable only has 0.7.1. environment.systemPackages = [ inputs.herdr.packages.x86_64-linux.default - gh llamaModelsCmd llamaUnloadCmd nodejs From e50f76c68c9b2d6a5e96a25611a9a86c91843747 Mon Sep 17 00:00:00 2001 From: "K. Isom" Date: Sat, 19 Sep 2026 17:51:12 -0700 Subject: [PATCH 02/11] install on all full desktops --- configs/desktop-packages-full.nix | 2 ++ hw/straylight/default.nix | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/configs/desktop-packages-full.nix b/configs/desktop-packages-full.nix index 68e9ca8..0160c4f 100644 --- a/configs/desktop-packages-full.nix +++ b/configs/desktop-packages-full.nix @@ -16,6 +16,7 @@ clang-tools elinks freeglut + gh glfw glm inkscape @@ -25,6 +26,7 @@ libGL libGL.dev mesa + nodejs nyxt opencode qmk diff --git a/hw/straylight/default.nix b/hw/straylight/default.nix index 5d229df..d385337 100644 --- a/hw/straylight/default.nix +++ b/hw/straylight/default.nix @@ -328,7 +328,6 @@ in inputs.herdr.packages.x86_64-linux.default llamaModelsCmd llamaUnloadCmd - nodejs whisperTranscribe whisperCpp ]; From e8c366b064016b34f01be11fb04f5d101551a769 Mon Sep 17 00:00:00 2001 From: "K. Isom" Date: Sat, 19 Sep 2026 20:54:16 -0700 Subject: [PATCH 03/11] llama-server: models-max 2 -> 3 Three residents (Laguna ~64G + ornith-1.5-35b ~21G + qwen3-vl-8b ~6G) fit the ~104G TTM window with KV headroom. Needed now that both Hermes hosts run their main loops off the router: straylight (laguna-s-2.1) and talos (ornith-1.5-35b-a3b) each want a resident slot, leaving the VLM as the third. Working-tree WIP (nix-ld libs for hermes desktop) intentionally left uncommitted. --- hw/straylight/default.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/straylight/default.nix b/hw/straylight/default.nix index d385337..20e23a1 100644 --- a/hw/straylight/default.nix +++ b/hw/straylight/default.nix @@ -224,7 +224,7 @@ in --host 0.0.0.0 \ --port 11434 \ --models-preset ${llamaModelsIni} \ - --models-max 2 \ + --models-max 3 \ --timeout 7200 ''; User = "llama-server"; From 72261df517c7faef069242b30b307bdf0a44af9a Mon Sep 17 00:00:00 2001 From: "K. Isom" Date: Sat, 19 Sep 2026 20:56:54 -0700 Subject: [PATCH 04/11] straylight: nix-ld libraries for Hermes Desktop (Electron) --- hw/straylight/default.nix | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/hw/straylight/default.nix b/hw/straylight/default.nix index 20e23a1..b54de72 100644 --- a/hw/straylight/default.nix +++ b/hw/straylight/default.nix @@ -394,6 +394,42 @@ in }; }; + # Hermes Desktop (`hermes desktop`) builds and launches an unpackaged + # Electron binary from ~/.hermes/hermes-agent/apps/desktop. It runs through + # nix-ld, so the Electron/Chromium runtime libraries have to be listed here. + programs.nix-ld.libraries = with pkgs; [ + glib + nspr + nss + dbus + at-spi2-atk + at-spi2-core + cups + cairo + gtk3 + pango + gdk-pixbuf + libx11 + libxcomposite + libxdamage + libxext + libxfixes + libxrandr + libxcb + libxkbcommon + libgbm + libdrm + libglvnd + mesa + vulkan-loader + expat + systemd # libudev + alsa-lib + libpulseaudio + libnotify + libsecret + ]; + # Headless Chromium exposing a CDP endpoint for Hermes browser tools. # Loopback only; browser.cdp_url in ~/.hermes/config.yaml points at it. # Ungoogled-chromium (already in desktop-packages-light.nix), no ad-block From 0543864f38ef3a83a92534a269bfa5b8bcfe3864 Mon Sep 17 00:00:00 2001 From: "K. Isom" Date: Sat, 19 Sep 2026 21:23:42 -0700 Subject: [PATCH 05/11] straylight: disable laguna, default to ornith --- configs/opencode.nix | 3 +-- hw/straylight/default.nix | 13 ++++++++----- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/configs/opencode.nix b/configs/opencode.nix index 75008e4..51eb0bd 100644 --- a/configs/opencode.nix +++ b/configs/opencode.nix @@ -17,7 +17,7 @@ let cfg = { "$schema" = "https://opencode.ai/config.json"; enabled_providers = [ "llama.cpp" "zai-coding-plan" ]; - model = "llama.cpp/laguna-s-2.1"; + model = "llama.cpp/ornith-1.5-35b-a3b"; small_model = "llama.cpp/ornith-1.5-9b-uncensored"; provider = { "zai-coding-plan" = { @@ -52,7 +52,6 @@ let chunkTimeout = 7200000; }; models = { - "laguna-s-2.1" = text "Laguna S 2.1"; "qwen3.6-35b-a3b-abliterated" = text "Qwen3.6 35B A3B"; "gemma4-26b-a4b-abliterated" = text "Gemma 4 26B A4B"; "ornith-1.0-35b" = text "Ornith 1.0 35B"; diff --git a/hw/straylight/default.nix b/hw/straylight/default.nix index b54de72..aef7cb7 100644 --- a/hw/straylight/default.nix +++ b/hw/straylight/default.nix @@ -42,14 +42,17 @@ let ; DFlash GGUF is on disk (laguna-s-2.1-DFlash-BF16.gguf). nixpkgs llama.cpp 0.4.0 ; rejects it at load ("expected 76, got 69" tensors); Poolside's file needs their ; laguna-branch loader. Leave unwired so Laguna still starts. - [laguna-s-2.1] - model = ${llamaModelsDir}/laguna-s-2.1-UD-Q4_K_S/Laguna-S-2.1-UD-Q4_K_S-00001-of-00003.gguf + ; DISABLED 2026-09-19: resident beside Ornith 35B it left ~15 GB free, and a third + ; model load then hit the 104 GiB TTM cap and OOM-killed the desktop session. + ; Weights stay on disk; uncomment to re-enable. + ; [laguna-s-2.1] + ; model = ${llamaModelsDir}/laguna-s-2.1-UD-Q4_K_S/Laguna-S-2.1-UD-Q4_K_S-00001-of-00003.gguf ; Two slots sharing one unified 131072-token KV pool: a second request (subagent, ; another client) runs alongside instead of queueing, and either one may still use ; the full 131072 as long as their combined context fits. - parallel = 2 - kv-unified = true - ctx-size = 131072 + ; parallel = 2 + ; kv-unified = true + ; ctx-size = 131072 ; Previous default model (a Qwen 3.5 derivative), kept for comparison runs. It was ; fetched by the old -hf flag into the HF cache; dedup hides the cache's own entry. From a893514708544d43b67d22758cef39ec18a24326 Mon Sep 17 00:00:00 2001 From: "K. Isom" Date: Sat, 19 Sep 2026 21:51:50 -0700 Subject: [PATCH 06/11] llama-server: revert models-max 3 -> 2 (OOM-killed desktop on rebuild) models-max 3 pulled all three residents into RAM and the OOM killer took the desktop (and Hermes) mid-switch. models-max 2 is the safe baseline; co-residency of all three is a future-optimization, not a today one. --- hw/straylight/default.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/straylight/default.nix b/hw/straylight/default.nix index aef7cb7..dc7ad21 100644 --- a/hw/straylight/default.nix +++ b/hw/straylight/default.nix @@ -227,7 +227,7 @@ in --host 0.0.0.0 \ --port 11434 \ --models-preset ${llamaModelsIni} \ - --models-max 3 \ + --models-max 2 \ --timeout 7200 ''; User = "llama-server"; From b3f66466bc15f5024cbe13f394273c3bf2bb394a Mon Sep 17 00:00:00 2001 From: "K. Isom" Date: Sun, 20 Sep 2026 13:08:20 -0700 Subject: [PATCH 07/11] add cliamp --- configs/desktop-packages-light.nix | 1 + hw/straylight/default.nix | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/configs/desktop-packages-light.nix b/configs/desktop-packages-light.nix index 54f83dd..19489f3 100644 --- a/configs/desktop-packages-light.nix +++ b/configs/desktop-packages-light.nix @@ -12,6 +12,7 @@ let system = pkgs.stdenv.hostPlatform.system; in bitwarden-cli bitwarden-desktop bluez + cliamp cmus deja-dup direnv diff --git a/hw/straylight/default.nix b/hw/straylight/default.nix index dc7ad21..aef7cb7 100644 --- a/hw/straylight/default.nix +++ b/hw/straylight/default.nix @@ -227,7 +227,7 @@ in --host 0.0.0.0 \ --port 11434 \ --models-preset ${llamaModelsIni} \ - --models-max 2 \ + --models-max 3 \ --timeout 7200 ''; User = "llama-server"; From ef4a3340621028cbef4224a0d8512bb3d04e5fc9 Mon Sep 17 00:00:00 2001 From: "K. Isom" Date: Sun, 20 Sep 2026 18:16:58 -0700 Subject: [PATCH 08/11] llama-server: per-model prompt cache limits; 4 unified slots for ornith --cache-ram is per resident model, so the 8 GiB default meant up to 24 GiB with --models-max 3. Default it to 2 GiB and give ornith-1.5-35b-a3b 16 GiB: worst case drops to 20 GiB while the model that thrashes gets twice the cache. ornith also goes from 2 slots of 131072 to 4 slots over one unified 262144 pool: same GPU memory, twice as many live prefixes. Measured over 30 h before this change: 235 cache evictions and ~196 minutes spent re-processing prompts over 20k tokens. Co-Authored-By: Claude Fable 5.1 --- hw/straylight/default.nix | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/hw/straylight/default.nix b/hw/straylight/default.nix index aef7cb7..c1849fd 100644 --- a/hw/straylight/default.nix +++ b/hw/straylight/default.nix @@ -25,6 +25,12 @@ let parallel = 2 ; Unload a model's weights and KV cache after six idle hours; the next request reloads it. sleep-idle-seconds = 21600 + ; Host-RAM prompt cache. This limit is PER RESIDENT MODEL, not global: each model's + ; child llama-server gets its own. The llama.cpp default is 8192 MiB, so with + ; --models-max 3 the worst case was 3 x 8 = 24 GiB. Helper, VL and comparison models + ; rarely reuse long prefixes, so they get 2 GiB; the model that does gets more in its + ; own section. Worst case is now 16 + 2 + 2 = 20 GiB. + cache-ram = 2048 ; Qwen3.6-35B-A3B, refusal-ablated (HauhauCS "Aggressive"). Benchmark candidate A. [qwen3.6-35b-a3b-abliterated] @@ -85,6 +91,23 @@ let top-k = 20 reasoning-budget = 8192 dedup-cache-models = true + ; Prompt-cache thrash (measured 2026-09-20, 30 h of logs): opencode, Hermes and its + ; delegation subagents shared 2 slots and an 8 GiB host cache whose entries are + ; 1-2 GiB each. 235 evictions; 138 prompt re-evaluations over 20k tokens costing + ; ~196 minutes; one 102,922-token prompt re-processed from scratch (~3.4 min). + ; + ; Four slots over ONE unified 262144-token KV pool: same GPU memory as before, but + ; four conversations keep their prefix live instead of two, and any one of them may + ; still use the whole pool when the others are idle. Cost: when all four decode at + ; once, each gets a smaller share of ~30 t/s. + parallel = 4 + kv-unified = true + ; 16 GiB holds about ten evicted conversations instead of five. + ; IF LAGUNA IS RE-ENABLED this must drop to 4096 (Laguna 8192, helpers 0) and + ; --models-max to 2: Laguna ~73 GiB + this model ~26 + a 9B helper ~9 + desktop and + ; services ~20 + the honcho CPU lanes ~9 is ~137 GiB on a 125 GiB machine before + ; any cache at all. That is the 2026-09-19 OOM. + cache-ram = 16384 ; Qwen 3.8 27B dense, refusal-ablated. Preferred uncensored coding agent. ; orcarouter/Qwen3.8-27B-Uncensored-GGUF is gated; huihui Q4_K_L keeps From 0a4bec8935b2ee640235a5833c52bebbe592a040 Mon Sep 17 00:00:00 2001 From: "K. Isom" Date: Sun, 20 Sep 2026 21:07:37 -0700 Subject: [PATCH 09/11] straylight: add tirith (Hermes pre-exec command scanner) Hermes resolves tirith from PATH before its self-downloaded ~/.hermes/bin/tirith. Taken from nixpkgs-unstable (0.4.1); nixos-26.05 only has 0.3.3. Co-Authored-By: Claude Fable 5.1 --- hw/straylight/default.nix | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hw/straylight/default.nix b/hw/straylight/default.nix index aef7cb7..f8b7245 100644 --- a/hw/straylight/default.nix +++ b/hw/straylight/default.nix @@ -333,6 +333,10 @@ in llamaUnloadCmd whisperTranscribe whisperCpp + # tirith: pre-exec command security scanner used by Hermes (resolved from + # PATH before its self-downloaded ~/.hermes/bin/tirith). From unstable: + # 26.05 only has 0.3.3, Hermes ships 0.4.x. + pkgsUnstable.tirith ]; services.open-webui = { From 09d16f2f394b5ece90b764dd4d13a8a58b6413d1 Mon Sep 17 00:00:00 2001 From: "K. Isom" Date: Mon, 21 Sep 2026 01:13:30 -0700 Subject: [PATCH 10/11] llama-server: cap ornith 9B helper output (runaway guard) As Hermes' auxiliary model it received requests with no max_tokens and a generation ran to 46k tokens (~70 min) after the client's 60 s timeout, starving the 35B. Cap thinking (reasoning-budget 2048) and total output (n-predict 4096) server-side; preset verified against a throwaway router. Co-Authored-By: Claude Fable 5.1 --- hw/straylight/default.nix | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/hw/straylight/default.nix b/hw/straylight/default.nix index c1849fd..83aaf03 100644 --- a/hw/straylight/default.nix +++ b/hw/straylight/default.nix @@ -71,6 +71,13 @@ let [ornith-1.5-9b-uncensored] hf-repo = mradermacher/Ornith-1.5-9B-uncensored-GGUF:Q4_K_M dedup-cache-models = true + ; Runaway guard (2026-09-21): as Hermes' auxiliary model (approval, title, web + ; extract) it got requests with no max_tokens, never converged, and one generation + ; ran to 46k tokens (~70 min at 11 t/s) after the client's 60 s timeout, starving the + ; 35B. Helper tasks need short answers: cap thinking and total output server-side. + ; A client that sends its own smaller max_tokens still wins. + reasoning-budget = 2048 + n-predict = 4096 ; Qwen3-VL-8B Instruct, refusal-ablated (prithivMLmods v2 / mradermacher). ; Dedicated VLM in the same size class as Ornith 1.5 9B. Explicit mmproj-url From b632e20fd610aba263c95ac29d861913c3296134 Mon Sep 17 00:00:00 2001 From: "K. Isom" Date: Mon, 21 Sep 2026 21:53:40 -0700 Subject: [PATCH 11/11] =?UTF-8?q?dixie:=20new=20host=20=E2=80=94=20Aurora?= =?UTF-8?q?=20R11=20helper-tier=20inference=20node?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Alienware Aurora R11 (i7-10700, 64 GB, one RTX 3060 12 GB today; second card when its fans are replaced). Headless, Wi-Fi only, unencrypted root by decision (always-on box that must come back from a power cut unattended). - llama.cpp router (CUDA, from unstable) on :11434 with the three helper models resident (--models-max 3): ornith 9B for the Hermes approval guardian / title / web_extract and Honcho deriver, qwen3-4b for Honcho dialectic, Qwen3-Embedding-0.6B for Honcho embeddings. Vision (qwen3-vl-8b) on its own on-demand server on :11433 since it does not fit beside them in 12 GB. - Both servers tailnet-only (tailscale0 firewall); GPUs capped at 140 W (thermal hour 2026-09-21: 75 C plateau, no throttling). - Model weights on the USB cache stick (ext4 label dixie-cache) bind-mounted into /var/lib/llama-server/models; filled from straylight with dixie-push. - 6.12 LTS kernel (mt7921u for the AX9L USB Wi-Fi arriving 2026-09-24). - SSH keys baked in: no console after install to add them from. Co-Authored-By: Claude Fable 5.1 --- flake.nix | 1 + hw/dixie/authorized_keys.pub | 4 + hw/dixie/default.nix | 186 ++++++++++++++++++++++++++++ hw/dixie/disk-config.nix | 38 ++++++ hw/dixie/hardware-configuration.nix | 18 +++ 5 files changed, 247 insertions(+) create mode 100644 hw/dixie/authorized_keys.pub create mode 100644 hw/dixie/default.nix create mode 100644 hw/dixie/disk-config.nix create mode 100644 hw/dixie/hardware-configuration.nix diff --git a/flake.nix b/flake.nix index a4cda7b..842afba 100644 --- a/flake.nix +++ b/flake.nix @@ -67,6 +67,7 @@ lib = nixpkgs.lib; in { nixosConfigurations = lib.genAttrs [ + "dixie" "imladris" "ono-sendai" "orion" diff --git a/hw/dixie/authorized_keys.pub b/hw/dixie/authorized_keys.pub new file mode 100644 index 0000000..fed5d3a --- /dev/null +++ b/hw/dixie/authorized_keys.pub @@ -0,0 +1,4 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDXu7ME91tLfU+Q3fNFe8VyIouVvoktoYy8xVNpObxuv kyle@titan.local +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGea83yMIdCi0QUUPgmhRgIrii7lS1dYxZ6LSxSsDOph kyle@europa +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHukZAxnlMSoTlRtRF14mLbC0x+rb1zlxnSLVLg+6Xbh kyle@vade +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILw318jrtFJw1Cn3WnOk17Gkr8bo7NOACQwMQ7S4hvoL kyle@straylight diff --git a/hw/dixie/default.nix b/hw/dixie/default.nix new file mode 100644 index 0000000..3ef26eb --- /dev/null +++ b/hw/dixie/default.nix @@ -0,0 +1,186 @@ +{ inputs, pkgs, lib, config, ... }: +let + # Unstable instantiated with unfree allowed: CUDA is unfree, and legacyPackages does not + # inherit the host's nixpkgs.config (straylight's Vulkan build never hit this). + pkgsUnstable = import inputs.nixpkgs-unstable { + system = pkgs.stdenv.hostPlatform.system; + config = { allowUnfree = true; cudaSupport = true; }; + }; + # llama.cpp with the CUDA backend, from unstable to match straylight's build (same model + # files, same router semantics). Built once on straylight and shipped with dixie-push + # --closure, or pulled from the cache when Dixie's link allows. + llama-cpp = pkgsUnstable.llama-cpp.override { cudaSupport = true; }; + modelsDir = "/var/lib/llama-server/models"; + + # Dixie is the fleet's helper tier: everything that is latency-sensitive, small, and was + # starving on straylight's CPU (2026-09-21). One RTX 3060 (12 GB) today; card 2 joins + # when its fans are replaced. + # + # Router: the three models that must never be swapped out — approval guardian / Honcho + # deriver (9B), Honcho dialectic (4B, non-thinking), Honcho embeddings — resident together: + # 5.6 + 2.5 + 0.7 GB weights, ~3 GB left for KV. Vision does NOT go here: 5 GB + 1.2 GB + # mmproj does not fit beside them, so it gets its own on-demand process below. + llamaModelsIni = pkgs.writeText "llama-models.ini" '' + version = 1 + [*] + jinja = true + flash-attn = on + cache-type-k = q8_0 + cache-type-v = q8_0 + n-gpu-layers = 999 + ; three resident models share 12 GB: keep contexts modest + ctx-size = 16384 + parallel = 2 + cache-ram = 512 + + ; Ornith 1.5 9B, refusal-ablated. Hermes auxiliary model (approval guardian, title, + ; web_extract) for all agents and Honcho's deriver/summary/dream model. + [ornith-1.5-9b-uncensored] + model = ${modelsDir}/ornith-1.5-9b-uncensored/Ornith-1.5-9B-uncensored.Q4_K_M.gguf + ; Runaway guard carried over from straylight: helper tasks need short answers. + reasoning-budget = 2048 + n-predict = 4096 + + ; Honcho dialectic: non-thinking instruct model so answers are short and fast. + [honcho-dialectic] + model = ${modelsDir}/qwen3-4b-instruct-2507/Qwen3-4B-Instruct-2507-Q4_K_M.gguf + n-predict = 1024 + + ; Honcho embeddings (1024-dim; EMBEDDING_VECTOR_DIMENSIONS=1024 on rift). + [honcho-embed] + model = ${modelsDir}/qwen3-embedding-0.6b/Qwen3-Embedding-0.6B-Q8_0.gguf + embedding = true + pooling = cls + ubatch-size = 8192 + ctx-size = 8192 + parallel = 4 + ''; + + # Vision (auxiliary.vision for all agents): its own server on :11433, loaded on first + # request and dropped again after an idle hour so the router's three keep their VRAM. + visionModelsIni = pkgs.writeText "llama-vision.ini" '' + version = 1 + [*] + jinja = true + flash-attn = on + n-gpu-layers = 999 + ctx-size = 16384 + parallel = 1 + sleep-idle-seconds = 3600 + + [qwen3-vl-8b-abliterated] + model = ${modelsDir}/qwen3-vl-8b-abliterated/Qwen3-VL-8B-Instruct-abliterated-v2.0.Q4_K_M.gguf + mmproj = ${modelsDir}/qwen3-vl-8b-abliterated/Qwen3-VL-8B-Instruct-abliterated-v2.0.mmproj-f16.gguf + ''; + + llamaService = { description, port, preset, modelsMax }: { + inherit description; + wantedBy = [ "multi-user.target" ]; + after = [ "network-online.target" "var-lib-llama\\x2dserver-models.mount" ]; + wants = [ "network-online.target" ]; + environment.HOME = "/var/lib/llama-server"; + serviceConfig = { + ExecStart = '' + ${llama-cpp}/bin/llama-server \ + --host 0.0.0.0 \ + --port ${toString port} \ + --models-preset ${preset} \ + --models-max ${toString modelsMax} \ + --timeout 7200 + ''; + User = "llama-server"; + Group = "llama-server"; + StateDirectory = "llama-server"; + WorkingDirectory = "/var/lib/llama-server"; + SupplementaryGroups = [ "video" ]; + Restart = "on-failure"; + RestartSec = "10s"; + TimeoutStartSec = "600"; + }; + }; +in +{ + imports = [ + ./hardware-configuration.nix + ./disk-config.nix + ]; + + config = { + # Headless. The base configuration.nix has no desktop; nothing GUI is added here. + boot.loader.systemd-boot.enable = true; + boot.loader.efi.canTouchEfiVariables = true; + # 6.12 LTS: mt7921u (the AX9L USB Wi-Fi) is in-tree from 5.18; avoids the 6.17/6.18 + # mt7921 monitor-mode regression for good measure. + boot.kernelPackages = pkgs.linuxPackages_6_12; + + # NVIDIA, compute only: no X, no modesetting needed for CUDA. + hardware.graphics.enable = true; + services.xserver.videoDrivers = [ "nvidia" ]; + hardware.nvidia = { + open = false; + modesetting.enable = false; + nvidiaPersistenced = true; + package = config.boot.kernelPackages.nvidiaPackages.production; + }; + hardware.enableRedistributableFirmware = true; + + # Power cap for the 3060(s): thermal hour on 2026-09-21 held 75 °C at 140 W, case closed. + systemd.services.nvidia-power-cap = { + description = "Cap GPU power (thermals in the Aurora chassis)"; + wantedBy = [ "multi-user.target" ]; + after = [ "nvidia-persistenced.service" ]; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + ExecStart = "${config.hardware.nvidia.package.bin}/bin/nvidia-smi -pl 140"; + }; + }; + + # Headless and Wi-Fi only: there is no console to add a key from after install, so the + # keys go in with the system. Same set the live ISO used (~/src/dixie-iso). + users.users.kyle.openssh.authorizedKeys.keyFiles = [ ./authorized_keys.pub ]; + users.users.root.openssh.authorizedKeys.keyFiles = [ ./authorized_keys.pub ]; + + users.users.llama-server = { isSystemUser = true; group = "llama-server"; home = "/var/lib/llama-server"; }; + users.groups.llama-server = { }; + + # Model weights live on the USB cache stick (ext4, label dixie-cache), populated from + # straylight with dixie-push. Both servers wait for the mount. + fileSystems."/mnt/cache" = { + device = "/dev/disk/by-label/dixie-cache"; + fsType = "ext4"; + options = [ "noatime" "nofail" "x-systemd.device-timeout=30s" ]; + }; + fileSystems."/var/lib/llama-server/models" = { + device = "/mnt/cache/models"; + fsType = "none"; + options = [ "bind" "nofail" "x-systemd.requires=/mnt/cache" ]; + }; + + systemd.services.llama-server = llamaService { + description = "llama.cpp router: helper tier (9B guardian/deriver, dialectic, embeddings)"; + port = 11434; preset = llamaModelsIni; modelsMax = 3; + }; + systemd.services.llama-vision = llamaService { + description = "llama.cpp vision server (qwen3-vl-8b, on demand)"; + port = 11433; preset = visionModelsIni; modelsMax = 1; + }; + + # Wi-Fi only host. NetworkManager comes from the base config; the AX9L (mt7921u) becomes + # the primary once plugged in and the internal CNVi radio stays as fallback. Connection + # profiles are copied from the live-USB session at install time (see the install notes), + # not stored in this repo. + networking.networkmanager.wifi.backend = "wpa_supplicant"; + + # Reachable only over the tailnet: 11434 (router) and 11433 (vision) on tailscale0, and + # SSH from the LAN (base config opens 22) for bring-up. + networking.firewall.interfaces.tailscale0.allowedTCPPorts = [ 11433 11434 ]; + + environment.systemPackages = with pkgs; [ + llama-cpp + pciutils usbutils lm_sensors dmidecode nvme-cli smartmontools ethtool iw wpa_supplicant + htop tmux git jq curl rsync nvtopPackages.nvidia + ]; + + }; +} diff --git a/hw/dixie/disk-config.nix b/hw/dixie/disk-config.nix new file mode 100644 index 0000000..c28dbb3 --- /dev/null +++ b/hw/dixie/disk-config.nix @@ -0,0 +1,38 @@ +## (dixie) disko config +## Alienware Aurora R11: Samsung PM9A1 1 TB NVMe is the system disk. The 6 TB SATA HDD and the +## USB cache stick are left alone here (the stick is mounted by label in default.nix). +## Unencrypted on purpose: headless box that must come back from a power cut with nobody +## at the console to unlock it. + +{ lib, ... }: + +{ + disko.devices.disk.main = { + type = "disk"; + device = "/dev/disk/by-id/nvme-eui.36355630521205220025384500000001"; + content = { + type = "gpt"; + partitions = { + ESP = { + size = "1G"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + mountOptions = [ "umask=0077" ]; + }; + }; + root = { + size = "100%"; + content = { + type = "filesystem"; + format = "ext4"; + mountpoint = "/"; + mountOptions = [ "noatime" ]; + }; + }; + }; + }; + }; +} diff --git a/hw/dixie/hardware-configuration.nix b/hw/dixie/hardware-configuration.nix new file mode 100644 index 0000000..a26f3e0 --- /dev/null +++ b/hw/dixie/hardware-configuration.nix @@ -0,0 +1,18 @@ +# Do not modify this file! It was generated by ‘nixos-generate-config’ +# and may be overwritten by future invocations. Please make changes +# to /etc/nixos/configuration.nix instead. +{ config, lib, pkgs, modulesPath, ... }: + +{ + imports = + [ (modulesPath + "/installer/scan/not-detected.nix") + ]; + + boot.initrd.availableKernelModules = [ "xhci_pci" "ahci" "nvme" "usbhid" "usb_storage" "sd_mod" ]; + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ "kvm-intel" ]; + boot.extraModulePackages = [ ]; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; +}