TacidOS
Developers
Documentation

Workstation preparation; physical validation pending

Ryzen/Radeon/NVIDIA Windows workstation preparation

Radeon display, separate NVIDIA compute GPUs, Windows virtualization and safe initial installation.

Physical validation is pending. TacidOS is the permanent host. This guide prepares Ryzen 9 9950X, ASRock X870E Taichi OCF, 128 GB DDR5, two separate 4 TB NVMe SSDs, and two RTX 5080 cards with 16 GB VRAM each. Applications may distribute work across cards; this is never one physical 32 GB GPU. There is no motherboard driver: UEFI configuration, kernel drivers, microcode and firmware come through NixOS.

ModeWindowsLinux computeTacidOS display
Linux AI (initial)stopped, no active PCI ownershipboth NVIDIA cardsRadeon motherboard output
Parallelone complete GPU IOMMU groupother NVIDIA cardRadeon motherboard output
Windows Computeboth complete GPU groupsno NVIDIA card; CPU inference availableRadeon motherboard output

Inspection findings and changes

Before this branch, workstation enabled core, Hyprland/its existing shell, CLI tools, Bluetooth, iwd/networkd/resolved and firewall. It did not enable libvirt or AI by itself. The reference workstation evaluated with redistributable firmware disabled; this branch enables it in the installed workstation profile for Radeon/network controllers. AI selected the core inference tier and llama-cpp; package acceleration was derived from the display profile. Detection enumerated PCI display devices by class and kept each slot separately, even for identical vendor/device IDs, but genesis selected NVIDIA ahead of AMD. Inference permitted only /dev/nvidia0, control and UVM nodes and an ineffective directory grant for DRM. Libvirt existed only as a curated optional service with /var/lib/libvirt persistence.

Now AMD+NVIDIA proposes AMD display and NVIDIA compute, including a reviewed AMD PCI address for a stable DRM symlink. The generated proposal and detected slots are shown before installation. This is a vendor heuristic, not proof that a particular AMD card is integrated. Use --body to override any assignment. Existing NVIDIA-only profiles retain their display drivers and compute defaults. Radeon display places amdgpu in the initrd; compute NVIDIA modules load in stage 2. An Aquamarine device selection restricts Hyprland to the declared display DRM node. Plymouth/UEFI output selection still requires a motherboard-output boot and LUKS prompt test.

Pinned nixpkgs is 3ed67ec0a4d3c7ab4ae1f04f8ee8df07bfa506a2. Evaluation reports Linux 6.18.48, NVIDIA stable 595.99.02, CUDA runtime 12.9.79, llama-cpp 0.3.0, OVMF 202608 and swtpm 0.10.1-unstable-2026-05-21. CUDA uses package-local overrides, not a global rebuild of nixpkgs with CUDA enabled. NVIDIA open kernel modules still require unfree userspace; CUDA also requires license acceptance. This branch fixes the driver assertion to accept allowUnfreePredicate as well as allowUnfree. A predicate must admit all required CUDA/driver packages, not just the kernel module. The documented initial owner choice is explicit nixpkgs.config.allowUnfree = true; Tacid does not silently make it for you. Evaluation/build evidence and limitations are in validation. Version availability does not establish RTX reset, CUDA execution or motherboard support.

Safe first installation: choose only one SSD

First build and write the netinstall USB. This PR’s ISO has not been built here; verify the image’s source revision before relying on its installer.

  1. In UEFI enable SVM (AMD virtualization), AMD-Vi/IOMMU and integrated graphics; select integrated graphics as primary and keep it enabled with discrete cards. Connect the Linux monitor input to the motherboard. Record firmware version; firmware updates are a separate owner decision, not an installer action.

  2. Boot the Tacid netinstall medium. Check wired networking first. Inventory with lsblk -d -o NAME,SIZE,MODEL,SERIAL,WWN and ls -l /dev/disk/by-id. Match the entire selected NVMe by serial/model, stable ID and size, not nvme0n1 discovery order. With two equal-sized SSDs, size alone is not identity. Keep the other SSD untouched; do not supply it as a VM raw disk. Physically disconnecting the second SSD for installation is an optional additional precaution.

  3. Create a reviewed workstation-owner.nix body module on the live medium:

    { lib, ... }: {
      # Explicit owner decision: NVIDIA driver and CUDA userspace are unfree.
      nixpkgs.config.allowUnfree = true;
      # Package-local CUDA llama.cpp through the normal package surface.
      tacid.packages.ai = [ "llama-cpp" ];
      tacid.core.infer.profile = "core";
      # Review generated gpu.profile/computeProfile/displayPciAddress first.
      # If correcting them here, use lib.mkForce with your actual observed values.
      # Optional CUDA user access; replace USER with the installer username.
      users.users.USER.extraGroups = [ "video" "render" "libvirtd" ];
    }

    Membership in libvirtd grants broad local virtualization authority. It does not grant an agent this permission. Review it explicitly; reconnect/login again after group changes. TacidOS does not run a graphical password agent here; the reviewed libvirtd group avoids depending on an unavailable authentication dialog. Polkit remains enabled for the local management policy.

  4. Run tacid install --device /dev/disk/by-id/YOUR_SELECTED_ENTIRE_NVME --body workstation-owner.nix with the normal hostname/user/keyboard/owner-key answers. Do not add --yes yet. Read the graphics facts, PCI slots, resolved disk path, byte size, full generated configuration, disk layout, encryption and swap plan. Passphrase/PIN files follow the existing installer procedure in the CLI manual.

  5. Only when the serial and complete plan are correct, rerun the same command with the existing --yes explicit confirmation and required secret files. Keeper physical confirmation/genesis-only execution still applies. The system is built before disk operations. The second SSD is not automatically selected or modified. Change the published initial login password immediately after first boot.

Do not copy example PCI addresses from tests. Missing IOMMU information is a reason to leave passthrough disabled, never to guess addresses or groups. Model storage and VM disks start as files on the installed SSD. Provisioning the second SSD later is another explicit, reviewed storage operation, outside this preparation PR.

ISO, drivers and boot recovery

The netinstall ISO uses the existing minimal live configuration: terminal/nervous system, installer and disk/repair tools, UEFI and BIOS medium boot, iwd/networking, and NixOS firmware for networking/recovery. It excludes the graphical closure, model weights, CUDA toolkit and workstation virtualization closure. NVIDIA/CUDA, Hyprland, virt-manager, QEMU and model engines are downloaded/built into the installed system through pinned Nix packages. Do not prune linux-firmware based on assumptions about the motherboard’s network controller. No uncontrolled driver download is added. AMD microcode is selected from observed AuthenticAMD CPU facts; AMD display firmware and amdgpu are NixOS mechanisms. Confirm the actual controller IDs after assembly.

If graphics fails, switch to a TTY (Ctrl+Alt+F2), use the Tacid CLI/TUI, or boot the previous NixOS generation in the firmware boot menu. Preserve working generations until hardware validation is complete. SSH recovery is opt-in via the existing tacid.services.openssh service, authorized keys and reachable-service confirmation; password/root SSH is disabled and host keys live under /persist/etc/ssh. Verify SSH from another machine before relying on it. If neither desktop nor TTY boots, boot the live medium, unlock/mount the selected SSD using its stable identity and use existing NixOS rescue/nixos-enter procedures to select/rebuild the previous pinned generation. Do not repartition as a driver repair. Driver changes remain boot-class transactions; a rollback restores matching kernel/module/configuration.

Inference and CUDA

tacid-infer keeps DevicePolicy=closed and admits only DRM and NVIDIA frontend/UVM character classes. NVIDIA frontend includes all numbered card nodes and nvidiactl; UVM includes ordinary and tools nodes. /dev/nvidia-caps is not granted as a directory; consumer RTX cards do not need a MIG capability grant. No USB/storage devices are admitted. Inference keeps its video/render groups and no network route.

A CUDA service must be restarted when ownership changes: stop inference before Windows starts, then start it after ownership settles. Class rules resolve at service start; zero NVIDIA cards means CPU fallback, one card means one available CUDA device, two means both. A particular model may need reducing or unloading when only one card remains. Other user CUDA jobs must also finish; they are never killed by the guard. In Parallel mode launch Linux CUDA jobs only after Windows has claimed its card. The conservative guard checks all NVIDIA character and NVIDIA DRM nodes; an active job on even the retained card blocks a new ownership transition. This costs some convenience while the hardware’s recovery behavior is unknown.

Use nvidia-smi -L and query PCI bus IDs after every ownership change; ordinals may change. Set application GPU visibility from the currently observed devices, not persistent assumptions about GPU index 0. On hardware run a CUDA sample on each card and jointly, then test llama-cli -m /path/to/reviewed.gguf -ngl 99 --split-mode layer --tensor-split 1,1 -c 4096 -p 'Explain the GPU split' (confirm these flags with the installed engine’s --help). Select a licensed, checksum-verified GGUF whose quantized weights exceed one card’s available VRAM but leave room in the combined separate memories for context and buffers; observe allocations on both cards. Do not place a model or download credentials in this repository.

Model file size is disk usage; it is not a VRAM budget. Loaded tensors, temporary compute buffers and KV cache consume memory separately. KV cache grows with context, sequences and concurrency. Concurrent agents may share one server/model but require additional cache slots; separate servers often duplicate weights. Plan each card’s 16 GB limit, system RAM and concurrency independently. The existing inference capacity policy defaults to zero declared VRAM and conservatively describes the largest single-card budget, not an automatically measured sum. Do not declare 32 GB as one physical card; a distributed model needs its own per-card checks. The policy does not promise that every multi-card model will fit.

Windows 11 Pro through the virtual console first

Workstation now enables the curated libvirt service, local Polkit and programs.virt-manager. It installs QEMU/KVM via libvirt, virt-manager (with its existing desktop launcher), OVMF, swtpm, the VirtIO driver media package and a read-only Windows VM/GPU status launcher. Firmware discovery in this nixpkgs is provided by QEMU automatically; the old qemu.ovmf.enable option is removed. No TCP/TLS management listener is enabled. Default NAT offers DNS/DHCP to guests; the service remains marked reachable in Tacid’s allowlist. Do not bridge a physical LAN or expose libvirt over the network as part of this procedure.

  1. Supply your Windows 11 Pro ISO and license outside the repository. Open Virtual Machine Manager, connect to local QEMU/KVM system (qemu:///system). Check virsh -c qemu:///system capabilities for KVM, firmware with virsh -c qemu:///system domcapabilities, and create/start the local default NAT network if absent/inactive. Do not enable VM autostart during passthrough testing.
  2. Create domain windows11, select Windows 11, Q35 and UEFI Secure Boot-capable OVMF. Allocate a conservative starting budget such as 16 vCPUs, 32 GB RAM and a 200 GB qcow2 disk in /var/lib/libvirt/images, leaving RAM/CPU/disk for Linux. Use host-passthrough CPU. No PCI host devices yet.
  3. Customize before installation: virtual TPM emulated, version 2.0, model CRB; virtual display/console (SPICE and virtual video); VirtIO disk and VirtIO network on the default NAT; virtual USB keyboard/tablet for console interaction. If selecting Secure Boot firmware, verify its keys/enrollment with the actual firmware presented to the guest rather than assuming the host’s keys apply.
  4. Locate driver ISO with find /run/current-system/sw/share -iname '*virtio*.iso' (or inspect nix build nixpkgs#virtio-win --print-out-paths, making sure it is your pinned nixpkgs). Attach it as a second CD-ROM. In Windows setup load the VirtIO storage driver for Windows 11/amd64, then install networking and guest tools. Windows media and its license remain yours, not shipped with TacidOS.
  5. Complete installation and verify virtual console, storage/networking and clean shutdown/restart before enabling GPU passthrough. Export reviewed XML with virsh -c qemu:///system dumpxml windows11 for repeatability. Back up the offline VM disk, XML, NVRAM and TPM state together; do not clone a running vTPM.

/var/lib/libvirt keeps domain/network definitions, disks, OVMF NVRAM and libvirt’s swtpm state; /var/lib/swtpm is also explicitly persisted. Both are part of the curated service’s /persist binds on ephemeral-root systems. Keep disks/ISOs in a persistent location, not /tmp or ephemeral /var paths outside these directories. Homes and the genome have their existing persistence. Firmware store paths can change between generations: verify existing domain firmware/emulator paths during updates; stable /run/libvirt/nix-ovmf and nix-emulators paths are regenerated by NixOS. Persistent guest state does not itself pin an obsolete firmware store path.

Reviewed passthrough and switching modes

Passthrough is disabled by default. After assembly inspect lspci -nnk, find /sys/kernel/iommu_groups -type l, and each card’s PCI GPU and audio functions. Record complete groups, including bridges/other devices; do not use ACS override to pretend an isolation group has split. If a group includes the Radeon display, boot disk, or other host-critical devices, refuse that topology and investigate slots/firmware. Hardware feasibility is unresolved until this inventory is done.

In owner.nix enable tacid.virtualisation.passthrough.enable = true and set pciAddresses to the actual, owner-approved complete groups. This enables the NixOS VFIO modules and AMD IOMMU kernel parameters; it does not pre-bind anything by vendor/device ID or assign a GPU automatically. Stage the change through the normal owner/boot transaction and reboot to verify AMD-Vi. A missing group or unapproved address is refused by the libvirt prepare hook. This owner-only module is outside the agent’s writable surface.

For each transition:

  1. Cleanly shut down Windows; wait for virsh domstate windows11 to say shut off. Never edit hostdev ownership or live-hotplug a GPU into a running VM.
  2. Finish CUDA/rendering jobs yourself, stop their autostart sources and stop tacid-infer through authorized owner service administration (sudo systemctl stop tacid-infer from the owner account; no new agent root operation). Inspect sudo fuser -v /dev/nvidia* and the NVIDIA DRM nodes identified in /sys/class/drm/*/device/vendor, plus nvidia-smi. Radeon desktop clients are excluded by the guard. Keep new jobs from starting until the transition ends. The prepare hook refuses active device users, unknown idleness or incomplete groups; it does not terminate them. The hook is a point-in-time check, not a scheduler lock against concurrent new processes.
  3. In virt-manager add PCI host devices for one entire RTX group (Parallel) or both (Windows Compute), including audio functions. Use managed hostdevs; confirm dumped XML has managed='yes' and the reviewed source BDFs. Do not globally bind 10de:device IDs; identical cards would both be taken. Never select Radeon.
  4. Explicitly start Windows. Libvirt performs managed detach/bind. Retain the virtual console for administration. If start fails, inspect logs and driver state; do not force removal of an in-use module. Check the status launcher and actual sysfs driver links before restarting Linux inference on retained cards.
  5. Shut Windows down cleanly. Libvirt attempts managed reattach. Verify the driver is nvidia, nvidia-smi works, and the CUDA sample works on every returned card. Only then restart inference/user jobs. For Linux AI leave Windows stopped. For changing one-card to two-card assignment, edit the stopped domain and repeat.
  6. Return to Linux without reboot is unproven. If a card stays on VFIO/unbound or CUDA fails, leave inference stopped, disable Windows autostart, shut down Windows and reboot the host into the last working generation. Check both cards before resuming jobs. A hung VM may require a host reboot; forced VM termination risks guest filesystem/TPM state and is an explicit owner recovery action.

The libvirt group/Polkit path authorizes VM operations. Tacid does not gain a new agent-owned GPU control verb. Avoid automatic VM start, save/resume or GPU hotplug. NixOS is configured to shut guests down on host shutdown and not restore previously running guests at boot; disable any individual guest autostart separately.

Physical output and controls

Virtual display is a Windows console inside a TacidOS window for installation, configuration and administration. Direct gaming output is HDMI/DisplayPort from the assigned RTX card to another input on the monitor or a suitable KVM switch. Switch that input yourself. Hyprland workspaces do not switch physical GPU inputs.

Keep a Linux keyboard available for recovery. Initially use the virtual console’s keyboard/mouse and audio. For gaming explicitly configure dedicated USB devices (persistent vendor/product/serial identities), a reviewed entire USB-controller IOMMU group, or a physical USB/KVM switch. Decide between GPU HDMI/DP audio, dedicated USB audio or virtual audio; include GPU audio hostdevs for physical output. Do not pass through the only host keyboard/controller without another recovery path. Looking Glass is a future investigation, not provided here.

The status launcher reads libvirt state and PCI driver links. A stopped VM whose card is still VFIO reports recovery required, not success. Unknown authorization or missing domain is displayed as unknown. It does not switch ownership or stop jobs.

No website source exists in this checkout; no external website deployment or hardware-support claim was made. The acceptance checklist is the evidence required before promoting any physical claims.