I Planned a Windows → Linux Migration With an AI Coding Assistant

Real-world experiment · 2025–2026

I Planned a Windows → Linux Migration With an AI Coding Assistant.

Here's what actually happened — including the rollback, the retry, and what finally worked.

Fair warning up front: one of the two machines in this story ended up back on Windows-only. I'm going to tell you exactly why, because that outcome is more useful than a tidy success story where everything worked first try.

Over the past few weeks I used an AI coding assistant to plan and execute a real Windows → Linux migration on a custom-built desktop PC — three times. The third consolidated into one OS covering research, creative work, development, and gaming — that's where things stand now, in active daily use and still in a validation period. Getting there took three attempts: the first was a full dual-boot that ran for several days before a deliberate rollback; the second was a narrower retry focused on creative work and GPU development that worked but didn't cover the full scope needed. In parallel, assessment work is underway on a second machine — a laptop — which hasn't reached the install phase yet.

This post covers the whole arc: why migrate at all, how an AI assistant helps with this kind of project (and where it falls short), what the install and configuration process actually looks like with concrete commands, how to honestly assess whether it's working for you specifically, how to roll back cleanly when it isn't, and what happened across three attempts with progressively better outcomes.

Desktop — Iteration 1
CachyOS → Rolled back
Broad dual-boot scope including daily use. Anti-cheat blockers and daily-use friction caused rollback.
Desktop — Iteration 2
Ubuntu → Replaced
Narrow creative/dev scope. Worked but the broader consolidated use case — research, creative work, dev, and gaming — needed a different approach.
Desktop — Iteration 3
CachyOS → Validating ✅
Research, creative work, dev, and gaming. In daily use. Decision pending.
Laptop
Assessment in progress
Hardware profiled, software inventoried, distro selected. Install phase not yet started.

One thing this is not: a generic "Linux is great, you should try it" enthusiasm piece. There are plenty of those. This is what happens when you run the experiment on real machines, with real software, under a real deadline on your patience.


1. Why migrate to Linux at all

The honest reasons people consider this generally fall into a few buckets, and it's worth being clear-eyed about which ones actually apply to you before you start.

🛠️ Development and research
Containers, GPU compute, research tooling, anything server-shaped — Linux is often where the tooling is built first and works most naturally. The gap has narrowed with WSL2, but it hasn't closed.
💰 Cost and control
No license fees, no telemetry you didn't explicitly opt into, and a package manager that installs and removes software cleanly — no registry sprawl, no mystery folders left behind.
🔍 Curiosity
Some of us just like understanding how the machine actually works. Linux rewards that curiosity in a way Windows doesn't.
🎮 Gaming — genuinely improved
A compatibility layer developed by a major gaming platform has turned Linux gaming from a hobbyist niche into something that covers the majority of a typical game library without configuration. If you last tested this in 2018, it's a different world now.
⚠️ The hard blockers no one likes to say plainly

Some software explicitly refuses to run under any virtualization or compatibility layer — by deliberate policy, not as a bug. The clearest examples are competitive online games with kernel-level anti-cheat systems, but proprietary enterprise software and certain hardware management tools can fall into the same category. No amount of compatibility-layer cleverness works around a deliberate policy decision. If something like that is part of your routine, partial migration (dual-boot) is the realistic path, not full replacement.

Ask yourself one question before starting: am I trying to replace Windows entirely, or carve out a Linux partition for everything except a short, named list of exceptions? Those are different projects with different partition plans, different risk profiles, and different definitions of success.

2. Using an AI assistant for migration planning

The useful work an AI assistant does here isn't "tell me how to install Linux" — you can find that anywhere. It's turning a vague intention into a current, personalized plan based on what's actually on your specific machine, not a hypothetical one.

I used a terminal-based coding assistant with direct file access and shell execution capability, rather than a plain chat window. Several stages below need to actually look at your machine — list installed software, check disk layout, read partition tables — not just talk about it abstractly.

✅ The single most important habit

Always ask it to check real, current state before recommending anything. Actual disk usage. Actual installed software. Actual partition tables. Every time I skipped this and reasoned from assumptions, something went wrong. The AI is only as accurate as the information it's working from.

Here's the stage-by-stage flow with the kind of prompt that worked well at each step:

STAGE 1 — INVENTORY
Pull a full list of installed software on this machine and the key hardware
(CPU, GPU, storage layout, RAM). I want to assess Linux migration feasibility.
Don't assume anything — read the actual state from the system.
STAGE 2 — COMPATIBILITY RESEARCH
For each app and game in this list, tell me its Linux compatibility status:
native support, works via a compatibility layer, partial support with caveats,
or no viable path. Flag anything you're not fully confident about as needing
a live check — compatibility status changes frequently, and I'd rather verify
than rely on a stale fact stated confidently.
STAGE 3 — DISTRO SELECTION
My use cases span work, research, development, creative work, and gaming —
with the balance shifting depending on the day. Compare two or three Linux
distributions across all of these dimensions: productivity and office suite
compatibility, research tooling (Python, LaTeX, Jupyter, citation managers),
package ecosystem depth, stability versus rolling-release risk, creative
software support, and gaming readiness. Give me one clear recommendation
with reasoning that holds across all these use cases, not just a feature
table. Flag any trade-offs where a distribution is strong in some areas
but weak in others that I should know about before deciding.
STAGE 4 — PARTITION PLANNING
Before recommending a partition layout, check what's actually using space
on my drives right now — don't estimate, show me real numbers. Then propose
a dual-boot partition split that leaves meaningful headroom on both sides.
Flag anything that needs verifying: encryption status, which disk actually
boots the OS, any fast-startup or hibernation state that would make NTFS
partitions read-only from Linux.
STAGE 5 — SAFETY CHECKLIST
Before we partition anything: confirm disk encryption status on every volume
involved, confirm which physical disk is the actual boot disk, confirm
fast-startup and hibernation are disabled, and lay out a backup plan.
Treat this as a mandatory checklist, not optional pre-work.
STAGE 6 — POST-INSTALL AUTOMATION
Write me a setup script that installs the following categories of software
using this distro's package manager, organized by category with comments.
Flag anything that can't be scripted and needs manual follow-up — I'd
rather know about those up front than hit them mid-setup.
STAGE 7 — TROUBLESHOOTING
The new OS isn't booting. Here's the exact error message: [paste it].
Help me determine whether this is a partition problem, a bootloader
configuration problem, or something else — before suggesting any fix.
I want to understand the cause, not just apply a remedy that might not fit.
STAGE 8 — ROLLBACK
I've decided to revert this machine to Windows-only. Write me a precise,
step-by-step rollback procedure for my exact current partition layout.
Include a clearly-marked point of no return, and a safety check before
each irreversible step. I want to understand what each command does,
not just run it blind.
🤖 Where the AI got things wrong

Path syntax in a bootloader config file. A flag that didn't exist in the installed version of a tool. A compatibility claim that had gone stale. The AI is a capable planning partner, not an oracle. Treat its outputs as hypotheses to verify, not facts to execute. The sessions where I pushed back and asked it to check reasoning against actual documentation went better than the ones where I just ran what it suggested.

How the prompts evolved after the rollback

One of the less obvious benefits of a documented rollback is that it changes how you prompt the AI on the next attempt. Iteration 1 prompts started from scratch — broad scope, open questions, no prior context. Iteration 2 prompts started from a risk register, a lessons-learned list, and a clear decision to narrow the scope. The difference in how the AI responded was significant.

Prompt stage Iteration 1 framing Iteration 2 framing
Distro selection Compare distros across all my use cases, give one recommendation DaVinci Resolve's library sensitivity is the deciding factor — explain why rolling-release is a recurring cost, not a one-time fix
Partition planning Propose a dual-boot split that leaves headroom on both sides Carve a small 150–200GB purpose-specific partition — gaming and daily use stay on Windows
Prior context None — starting fresh Read the risk register first — don't re-derive decisions already made and documented
Post-install scripts Write scripts for dev, creative, research, gaming, hardware Write Ubuntu apt-based scripts only — include fix scripts for known failure modes before they occur

Here are the key Iteration 2 prompts that produced meaningfully different results:

ITERATION 2 — DISTRO RE-EVALUATION
Re-evaluate the distro choice from Iteration 1. The new scope is
creative work (DaVinci Resolve + CUDA), development (CUDA/PyTorch/Docker
GPU), and research (Jupyter/LaTeX/Zotero) only — gaming is explicitly
out of scope for this partition.

The critical constraint this time: DaVinci Resolve's library-version
sensitivity. On a rolling-release distro, a routine system update can
silently break Resolve until a workaround is found. Evaluate whether
that's a one-time fix or a recurring maintenance cost, and let that
drive the stability vs. rolling-release trade-off for this specific
partition's purpose.

Compare CachyOS (current, Arch-based rolling), Fedora (original
first-pass pick for CUDA stability), and Ubuntu 24.04 LTS. Give one
recommendation with reasoning specific to this narrower scope.
Update 03-distro-recommendation.md with the revised assessment and
document the reasoning shift explicitly.
ITERATION 2 — PARTITION PLANNING
Plan a smaller, purpose-specific partition — not a full dual-boot
replacement. Target: 150–200GB Linux root + 4GB dedicated /boot,
carved from the existing Windows D: drive. Gaming and daily use
stay on Windows entirely.

Cross-reference the 7-item pre-install checklist in 04-migration-plan.md
(EFI sizing, ntfs3/ntfs-3g conflict, bash-not-fish for fstab heredocs,
bootloader config regeneration, distro chroot helpers, blkid UUID
verification, Fast Startup re-check) and confirm each item is
addressed in the install plan before we touch any partitions.
ITERATION 2 — RESUMING A SESSION WITH STALE REPO DOCS
Before doing anything: read CLAUDE.md and desktop-pc/04-migration-plan.md
and desktop-pc/05-risk-register.md from the repo. Don't re-derive
decisions that are already made and documented there.

Then verify actual machine state against what the docs say — confirm
OS version, partition layout, and driver versions directly from the
system rather than trusting what a previous session claimed.
If the docs and the machine disagree, flag the discrepancy and update
the docs before running any commands. Don't act on stale context.
ITERATION 2 — ANTICIPATE FAILURE MODES BEFORE RUNNING SCRIPTS
Before running post-install scripts, check each one for assumptions
that may not hold on this specific OS version:
- Hardcoded distro version strings in apt repo URLs (e.g. ubuntu2404
  vs ubuntu2604)
- pip install calls that will fail on Python 3.12+ due to PEP 668
- PyTorch wheel index versions that may not have wheels for the
  installed Python version
- Any sudo calls that require interactive TTY input

For each failure mode identified: fix the script before running it,
not after. Write fix scripts for known issues (e.g. DaVinci Resolve
glib mismatch) as separate files so they can be run immediately
when the anticipated crash occurs.
💡 What changed most between iterations

The Iteration 2 prompts gave the AI a risk register to read rather than a blank slate to fill. That single change — starting from documented prior failures instead of a fresh question — produced more targeted recommendations, fewer wrong turns, and scripts that anticipated their own failure modes before running. The repo wasn't just version control; it was the AI's memory between sessions.


3. How the install and configuration actually went

3.1Pre-flight checks — do these before touching a partition

From an elevated Windows terminal, before anything else:

# Confirm encryption status on every drive involved.
# If anything shows "Protection On", save the recovery key before continuing.
manage-bde -status

# Confirm which physical disk actually boots Windows. Don't assume.
bcdedit /enum firmware

# See real, current free and used space per volume.
Get-Volume | Select-Object DriveLetter, FileSystemLabel, SizeRemaining, Size

# Find what's actually using disk space — often reveals hundreds of GB
# in stale downloads, abandoned installs, and un-emptied recycle bins
Get-ChildItem C:\ -Directory | ForEach-Object {
    $size = (Get-ChildItem $_.FullName -Recurse -ErrorAction SilentlyContinue |
             Measure-Object -Property Length -Sum).Sum
    [PSCustomObject]@{ Folder = $_.Name; SizeGB = [math]::Round($size/1GB, 2) }
} | Sort-Object SizeGB -Descending

# Disable fast startup — critical before mounting NTFS from Linux
powercfg /h off
Why fast startup matters: If fast startup is on, Windows leaves the NTFS partition in a partially-written state on shutdown — and Linux will mount it read-only to protect against corruption. This is correct behaviour, not a Linux bug. But it will silently prevent you from writing to your Windows drives from Linux until you turn it off.

3.2The EFI partition problem — what most guides skip

This is where the desktop installation hit its first real problem. It's worth being explicit because most guides skip it entirely.

📦 The EFI space problem, explained

Modern Linux bootloaders that copy the kernel and initramfs directly onto the EFI partition need significantly more space than the 100MB Windows creates by default. On my machine, two kernels plus their initramfs images totalled well over 200MB. A 100MB EFI partition cannot hold that.

The fix: Create a dedicated Linux boot partition — 512MB minimum, 1GB recommended — set as /boot during manual partitioning. Do not share the Windows EFI partition.

3.3Manual partitioning — the layout that worked

Partition Size Type Mount Action
Windows EFI ~100MB FAT32 none Leave untouched
Windows system varies NTFS none Leave untouched
Windows data varies NTFS none Leave untouched
Linux boot 1–4 GB FAT32 /boot Create fresh
Linux root remaining Btrfs / ext4 / Create fresh

3.4Live-USB verification before installing

# From a terminal inside the live environment:

ip a                      # network came up?
lspci | grep -i vga       # GPU detected?
nvidia-smi                # NVIDIA GPU — confirms driver + GPU communicate
                          # before you commit to the install

If you have a discrete GPU with no integrated graphics fallback and nvidia-smi fails here — stop. Resolve it before installing. This is the least-expensive point to catch a hardware support problem.

3.5The bootloader problem — what happened, and how it was fixed

First boot failed with a cryptic error. The cause: the bootloader installer had auto-detected a Windows boot partition and written an incorrect chainload entry pointing at the wrong partition. The fix required booting the live USB again and chrooting into the installed system:

# Mount the installed root partition (adjust path to your actual layout)
sudo mount -o subvol=@ /dev/sdXN /mnt/root
sudo mount /dev/sdXM /mnt/root/boot

# Mount pseudo-filesystems for chroot
sudo mount --bind /proc /mnt/root/proc
sudo mount --bind /sys /mnt/root/sys
sudo mount --bind /dev /mnt/root/dev
sudo mount --bind /sys/firmware/efi/efivars /mnt/root/sys/firmware/efi/efivars

# Enter the installed system and regenerate bootloader config
sudo chroot /mnt/root
limine-mkinitcpio        # command varies by bootloader
💡 Budget time for this. A first-boot bootloader issue is a common class of problem, not a sign the installation failed. The ability to chroot into an installed system from a live USB and repair it is a genuinely useful skill that comes up more than once.

3.6Mounting Windows drives from Linux — the details that matter

# Install the NTFS userspace driver
sudo pacman -S ntfs-3g       # Arch / CachyOS
# sudo apt install ntfs-3g  # Debian / Ubuntu

# Check UUIDs of Windows partitions
sudo blkid /dev/nvme0n1p3 /dev/sda3

# Create mount points
sudo mkdir -p /mnt/windows-c /mnt/windows-d

# Add to /etc/fstab — use bash, not fish shell, for heredoc syntax
bash
sudo tee -a /etc/fstab << 'EOF'
UUID=YOUR-C-UUID  /mnt/windows-c  ntfs-3g  remove_hiberfile,uid=1000,gid=1000,dmask=022,fmask=133,windows_names,auto,nofail  0  0
UUID=YOUR-D-UUID  /mnt/windows-d  ntfs-3g  remove_hiberfile,uid=1000,gid=1000,dmask=022,fmask=133,windows_names,auto,nofail  0  0
EOF

# Test
sudo mount -a
findmnt -o TARGET,OPTIONS /mnt/windows-c   # should show "rw"
Driver conflict to watch for: The kernel's built-in ntfs3 driver and the userspace ntfs-3g driver can both attempt to mount the same partition, resulting in a read-only kernel mount layered under the read-write userspace mount. Fix: blacklist the kernel driver.
echo "blacklist ntfs3" | sudo tee /etc/modprobe.d/disable-ntfs3.conf
sudo reboot

3.7Post-install automation script

#!/usr/bin/env bash
set -euo pipefail

# ── GPU driver + compute ─────────────────────────────────────
sudo pacman -S --needed --noconfirm nvidia-dkms nvidia-utils nvidia-settings cuda

# ── Development tools ────────────────────────────────────────
sudo pacman -S --needed --noconfirm docker git python nodejs
sudo systemctl enable --now docker
sudo usermod -aG docker $USER   # re-login required

# ── Gaming stack ─────────────────────────────────────────────
sudo pacman -S --needed --noconfirm steam lutris wine winetricks
# Enable compatibility layer for all titles in the gaming client settings

# ── Creative tools ───────────────────────────────────────────
yay -S --needed --noconfirm davinci-resolve
sudo pacman -S --needed --noconfirm audacity obs-studio

# ── Peripheral / RGB control ─────────────────────────────────
sudo pacman -S --needed --noconfirm openrgb lm_sensors
sudo sensors-detect --auto

echo ""
echo "Manual follow-up required:"
echo "  Gaming client → Settings → Compatibility → enable compatibility layer for all titles"
echo "  Docker    → log out and back in for group membership"
echo "  OpenRGB   → test each device individually"
echo "  DaVinci   → verify GPU acceleration in Preferences → Memory and GPU"

4. How to test whether it actually works for you

This is the step people skip, and it matters more than any other. Generic articles about "does Linux work in 2026" are not a substitute for testing your specific software on your specific hardware with your specific workflow.

🖥️
GPU and driver
nvidia-smi should show your GPU with a sane driver version. glxinfo | grep "OpenGL renderer" confirms what's actually rendering — not a software fallback.
🐳
GPU in containers
docker run --rm --gpus all nvidia/cuda:12.0.0-base-ubuntu22.04 nvidia-smi — the GPU must be visible from inside the container, not just on the host.
🔊
Audio — both output AND input
Test microphone input specifically. Output-only testing misses half the common failure modes. arecord -d 5 -f cd /tmp/test.wav && aplay /tmp/test.wav
🎮
Gaming — performance, not just "does it launch"
Run a real session in something you actually play and compare the experience to Windows. Some titles run within a few percent of Windows performance; others have a noticeable gap. You won't know which without running it.
📅
Your actual daily workflow, for a week
Use the new OS as your primary machine for a defined period and note every point of friction — not to fix each one immediately, but to build an honest picture of total accumulated friction versus total benefit. Some friction is one-time setup cost; some is recurring. Those are different problems with different weights.

5. How to roll back cleanly

🟢 Soft rollback

Change UEFI boot order so Windows boots by default. Linux install stays intact on disk, accessible anytime via one-time boot menu (F8/F11/Esc). Use this if you might return to Linux later.

🔴 Full rollback

Delete Linux partitions and restore Windows partition to original size. Not reversible without a full Linux reinstall. Use only when you're certain.

Full rollback commands — from elevated Windows Command Prompt

⛔ Point of no return — verify the partition layout below matches exactly what you expect before running delete partition. This cannot be undone.
diskpart
list disk                    # identify disk by SIZE — do not guess by number
select disk N

list partition               # VERIFY layout matches what you expect
                             # this is your last non-destructive checkpoint

select partition X           # Linux root partition
delete partition override    # "override" required for EFI/protected types
select partition Y           # Linux boot partition
delete partition override

select volume D              # Windows volume to restore
extend                       # grow back into freed space
exit

Then clean up the dead boot entry:

bcdedit /enum firmware       # find the Linux bootloader entry's {GUID}
bcdedit /delete {that-guid}
bcdedit /set {fwbootmgr} displayorder {bootmgr} /addfirst
Two things worth knowing:
  • Windows' Disk Management GUI will refuse to delete EFI System Partitions — that's what the override flag in diskpart is for. It's an intentional guard rail.
  • bcdedit /enum firmware occasionally fails with a misleading "not enough space" error that refers to UEFI firmware variable storage, not your drive. If that happens, delete the stale entry directly from your BIOS/UEFI setup screen instead.

6. Honest lessons learned — Iteration 1

Verify real state before trusting any recommendation
Whether from the AI, a forum post, or your own memory — check actual disk layout, actual partition sizes, actual software versions before acting on any assumption. Every time I skipped this, it cost time. Every time I insisted on it first, it saved time. This habit matters more than any specific technical knowledge.
Cross-OS file sharing is more friction than it sounds
Sharing a data drive is theoretically clean and practically workable — but the day-to-day experience of context-switching between two filesystems, managing mount state, and dealing with NTFS driver conflicts has real ongoing friction. Not prohibitive, but not invisible either.
Compatibility layers are not free
For some workloads, a compatibility layer is indistinguishable from native. For others, there's a measurable performance cost. For a few, there are missing features that matter in practice. You won't know which category your software falls into without testing it.
Multiple package ecosystems add real cognitive overhead
Native packages, AUR packages, compatibility-layer prefixes, AppImages, Flatpaks — instead of one consistent way to install and update things, you end up with several. If you value a lean, predictable system, that fragmentation is a real ongoing cost.
Some workflows transitioned beautifully; others didn't
Research and development workflows ran well end-to-end. Creative work also transitioned cleanly. Gaming via compatibility layer worked better than expected for most titles — the compatibility landscape has improved significantly in recent years. Anything touching the hard blockers didn't work at all, as expected. The question isn't "does Linux work?" in the abstract — it's "does Linux work for the specific things I do most?"
Switching costs are not just technical
An existing, comfortable, already-debugged setup has real value that's easy to underweight when you're excited about a new project. A few days of setup and troubleshooting is a few days not spent on other things. That's not a reason to never switch — it's a reason to be clear-eyed about the full cost.
A well-documented "no" is a successful outcome
The desktop ended up back on Windows-only — for now, for this set of use cases. That's not a failure. Having a clear record of what was tested, what worked, what didn't, and specifically why the rollback happened means the project wasn't wasted effort. The laptop assessment continues, informed by everything the desktop revealed.

↓ Iteration 2 begins here ↓

7. Iteration 2 — narrower scope, different distro, what actually worked

After the Iteration 1 rollback, the question wasn't whether to try again — it was whether a different scope would change the outcome. The blockers that caused the rollback were specific: general daily-use friction from trying to replace Windows entirely, and a small number of hobby applications with hard compatibility walls that no workaround could address. Neither of those goes away. But they're also not the only reason to run Linux.

The reframe: instead of replacing Windows as the primary OS, carve out a small, purpose-specific Linux partition for GPU compute, content creation tools, and research tooling — the things Linux handles most naturally — and leave everything else on Windows. Same machine, same drives, much narrower scope.

Iteration 1 — rolled back Iteration 2 — replaced Iteration 3 — validating ✅
Distro CachyOS (rolling) Ubuntu 26.04 LTS CachyOS (rolling)
Root partition ~977GB Btrfs 319GB ext4 533GB Btrfs
Scope Full replacement incl. daily use Creative/CUDA/research only Research, creative work, dev, and gaming
Bootloader Limine (manual repair needed) GRUB (out of the box) Limine (lessons from iter 1 applied)
Video editor Not tested DaVinci Resolve — working (glib fix) ⚠️ DaVinci shelved (audio) → ✅ Kdenlive
Gaming (compatibility layer) Attempted, anti-cheat blockers Out of scope ✅ Working via Proton/Lutris
Video recording (OBS) Not tested Installed, not used for recording ✅ Configured, validating
Outcome Rolled back Replaced by iter 3 In daily use — decision pending

Why Ubuntu LTS over CachyOS this time

Iteration 1 used CachyOS — an Arch-based rolling-release distro — primarily for tooling reuse across machines. For a general-purpose dual-boot that made sense. For a partition whose primary purpose is running DaVinci Resolve, it doesn't.

DaVinci Resolve ships its own bundled libraries and is sensitive to the exact system library versions it finds. On a rolling-release distro, a routine system update can silently break Resolve until a workaround is found. On an LTS release, that system library landscape is frozen for years. The first launch of Resolve on Ubuntu confirmed the reasoning: it failed immediately with a glib version mismatch — a known issue, a prepared fix script, and it was working within minutes. On a rolling release, that same mismatch would recur after every major system update.

💡 The distro choice proved itself immediately

The glib crash on first launch wasn't a surprise — it was in the pre-install documentation as the most likely failure point. Having a fix script ready meant it went from "crash on launch" to "working project" in under five minutes. Anticipating known failure modes and scripting the fix in advance is worth more than hoping the install goes cleanly.

What the post-install scripts actually encountered

Four scripts, run in order, covering NVIDIA/CUDA, development tools, content creation software, and research tooling. Not everything went to plan:

🔧
Stale CUDA repo path
Scripts were written targeting Ubuntu 24.04 but the installed OS was 26.04. The NVIDIA apt repo path hardcoded ubuntu2404 — fixed by verifying ubuntu2604 existed before running.
🐍
PEP 668 — system Python blocks pip
Ubuntu 26.04's system Python (3.14) refuses pip install --user by default. Fixed both affected scripts to use a shared venv at ~/.venvs/dev rather than the --break-system-packages override.
🔥
PyTorch wheel index mismatch
The cu124 PyTorch index has no wheels for Python 3.14. Switched to cu128 — confirmed via dry-run, installed cleanly. torch.cuda.is_available() returns True, RTX 4070 SUPER detected.
🎬
DaVinci Resolve glib crash — fixed, but not the last problem
Symbol lookup error on first launch (undefined symbol: g_once_init_leave_pointer). Fix script moved Resolve's bundled glib libs aside so it falls back to system versions. Relaunched cleanly and project creation worked — but a deeper, unfixable problem was waiting in the audio pipeline. See Section 11.
🐳
Docker GPU passthrough — group membership
usermod -aG docker ran successfully but group changes require a full logout/reboot to take effect — a new terminal in the same session doesn't re-read group membership. Resolved after reboot.

What's confirmed working

✅ NVIDIA driver + CUDA 13.2
✅ PyTorch (GPU confirmed)
⚠️ DaVinci → Kdenlive
✅ Audacity 3.7.7
✅ OBS Studio 32.1.2
✅ JupyterLab 4.6.0
✅ TeX Live 2025
✅ Zotero 9.0.4
✅ Docker + GPU passthrough
✅ VS Code + Claude Code
✅ Both Windows drives rw
✅ Git + GitHub CLI

The Windows app that didn't make it — and what comes next

One Windows-only application was assessed for Wine compatibility: a Quran reader with no Linux equivalent, dependent on an ActiveX/WebView2 rendering component for its core functionality. The pre-install documentation had flagged WebView2 as the highest-risk dependency — WebView2 runs a real Chromium-based Edge process, which has a weak reliability record under Wine even when it installs successfully.

The live test confirmed the prediction exactly: COM/OLE marshalling failures, Wine's RPC service unavailable, an iexplore.exe helper process spawning in wow64 mode and dying, leaving the main process waiting indefinitely. No window ever appeared. The time-boxed fix attempt (checking for a WebView2 winetricks verb — none exists; investigating the standalone installer — download URL is JavaScript-generated, not fetchable headlessly) confirmed this is a genuine compatibility wall, not a configuration problem.

🍷 Wine verdict: blocked, stays on Windows

The blocker isn't the application's data or logic — it's the ActiveX/WebView2 rendering layer it uses to display content. The underlying assets (page rendering data, SQLite database, audio files) are intact and accessible from Linux.

Next chapter: Rather than continuing to fight Wine compatibility, the more interesting path is building a native Linux application that reuses those existing assets directly — bypassing the Windows rendering layer entirely. That's a separate project, scoped and documented, waiting for the right moment.


8. What Iteration 2 taught that Iteration 1 didn't

Scope is the variable that matters most
Iteration 1 failed not because Linux failed, but because the scope was too broad. Trying to replace Windows entirely for a machine with hard anti-cheat blockers is the wrong problem to solve. Iteration 2 worked because the scope matched Linux's actual strengths: GPU compute, creative tools, research. The machine didn't change. The question did.
Distro stability matters more for some software than others
For general development and gaming workloads, a rolling-release distro is fine and often better. For software like DaVinci Resolve that bundles its own libraries and is sensitive to system library versions, an LTS release isn't just a preference — it's a recurring maintenance cost you avoid. Match the distro to the software, not to a general philosophy.
Anticipate failure modes and script the fixes in advance
The glib crash on DaVinci Resolve was documented as the most likely failure point before the install happened. Having a fix script ready meant zero debugging time when it occurred. Time spent on pre-install research and scripted fixes pays back faster than time spent diagnosing the same problem from scratch during the install.
A rollback isn't a failure — it's data
Iteration 1's rollback produced the exact information needed to make Iteration 2 work: which blockers are real, which friction is scope-dependent, which distro choice matters for which software. Without the rollback, Iteration 2 would have been guesswork. With it, it was an informed retry with a much higher prior probability of success.
The AI assistant's value compounds across iterations
The same repo that tracked Iteration 1's decisions, failures, and rollback became the starting context for Iteration 2. The AI could read the risk register, understand what had already been tried, and avoid re-deriving decisions that were already made. A well-documented first attempt doesn't just teach you — it makes the second attempt faster and more precise.

↓ Iteration 3 — consolidated ↓

9. Iteration 3 — one OS for everything that doesn't need Windows

Iteration 2 worked as designed but exposed friction across three distinct areas that each contributed to the case for a different approach.

The first was the Python and development tooling stack. Ubuntu's strict PEP 668 enforcement — blocking pip outside virtual environments — is the right default for system stability, but it also means every project needs its own venv recreated from scratch on Linux, even when the source code and a requirements.txt are already on the shared drive. More significantly, Ubuntu LTS ships a fixed Python version for the release lifetime. When PyTorch's wheel index had no builds for the installed Python version, the fix required switching indexes rather than updating Python itself. On CachyOS, the entire toolchain — Python, CUDA, PyTorch, pacman's python- prefixed packages — moves together as a rolling release, keeping the stack coherent without manual version management. For research and development work where the tooling matters as much as the code, that coherence is a real day-to-day advantage.

The second was content creation workflow friction: capturing footage in one OS and editing in another means transferring large video files between partitions on every session. That's a recurring cost, not a one-time setup cost.

The third was the subtler overhead of maintaining two Linux partitions with different package managers, different Python environments, and different update cadences. Ubuntu for stability; CachyOS as the intended long-term daily driver. That split made sense as a transitional arrangement but not as a permanent one.

The question became whether CachyOS could carry research, creative work, development, and gaming on a single partition — and whether its rolling-release risks were manageable enough for that to be the right long-term answer. The DaVinci Resolve glib fix, already scripted from Iteration 2, meant the main rolling-release risk was documented and handled. Everything else pointed toward consolidation.

The answer, so far, is yes — with clear scope boundaries. Two games remain permanent Windows-only exceptions: those with kernel-level anti-cheat that explicitly refuses to run under any compatibility layer. That boundary is documented, accepted, and not revisited. Everything else moved to Linux.

✅ IN SCOPE — Linux
Research tools
Video editing (Kdenlive)
Video recording (OBS)
CUDA / PyTorch dev
Docker + GPU passthrough
Games via compatibility layer
❌ PERMANENT EXCEPTIONS — Windows only
Competitive games with kernel-level anti-cheat
Not revisited. Not a workaround target.
Documented and accepted.

What was carried forward from Iterations 1 and 2

One of the less obvious compounding benefits of documented iterations is that each one produces a concrete checklist for the next. Iteration 3's pre-install checklist had thirteen items derived directly from things that went wrong in Iterations 1 and 2 — not from general Linux advice, but from specific failures on this specific machine.

4GB /boot partition — from Iteration 1's 100MB EFI failure. Already in place from Iteration 2.
ntfs3 blacklisted day one — from Iterations 1 and 2's read-only Windows drive issue.
DaVinci glib fix pre-scripted — from Iteration 2's first-launch crash. Script ran before first launch this time, though a separate audio issue later proved unfixable — see Section 11.
Game files on Btrfs — Some game launchers don't work correctly on NTFS. Large game installs need to live on the native Linux filesystem.
Game library on Btrfs — The compatibility layer creates files with names illegal on NTFS. The compatibility prefix directory must be on a native Linux filesystem.
Recordings and projects to /mnt/d — Video recordings and editor exports go to the NTFS D: drive to keep the Linux partition free.

The boot hang that wasn't random

After the install settled, there was an intermittent multi-second hang on the boot splash — the spinning animation would sit there, and the only escape was forcing a reboot with Ctrl+Alt+Del. The instinct with intermittent symptoms is to reboot past them and hope they stop. That's the wrong call.

🔍 What journalctl showed from the failed boot

The login screen's compositor (kwin_wayland) was losing a race with the NVIDIA GPU driver for the display device — then segfaulting in its own cleanup code. With the compositor dead, nothing took over from the Plymouth boot splash, so the spinner sat there indefinitely.

Root cause: the NVIDIA KMS driver was loading after boot rather than during it (no nvidia-drm.modeset=1 in the kernel cmdline, no NVIDIA modules in the initramfs). This created a timing race every boot — sometimes the compositor won, sometimes it didn't.

The fix removed the race entirely rather than narrowing it: load the NVIDIA driver in the initramfs so it's present before the compositor starts, and enable DRM modeset on the kernel command line.

# Add NVIDIA to initramfs modules
sudo sed -i 's/^MODULES=().*/MODULES=(nvidia nvidia_modeset nvidia_uvm nvidia_drm)/' /etc/mkinitcpio.conf

# Enable DRM modeset on kernel cmdline
echo 'KERNEL_CMDLINE[default]+=nvidia-drm.modeset=1 nvidia-drm.fbdev=1' | sudo tee -a /etc/default/limine

# Rebuild and update bootloader
sudo mkinitcpio -P
sudo limine-update
💡 The lesson: "sometimes it's slow" during boot is rarely actually random — it's usually a timing race between two specific things, discoverable from the boot log, with a clean fix once you know what's racing. Don't reboot past a recurring symptom without reading journalctl -b -1 from the bad boot first.

The fix held across multiple subsequent reboots with no recurrence, and was folded directly into the post-install script — so a fresh install on this hardware won't hit the same race condition at all.

Current status

The system is in active daily use across all use cases — research, creative work, development, and gaming. The validation period is ongoing; the keep-vs-rollback decision is not yet final. What's clear so far: the scope boundary is the right one, the pre-scripted fixes worked, and the per-iteration documentation paid back its cost in the reduced time spent re-diagnosing the same problems.


10. What Iteration 3 taught — and what the whole arc looks like

The scope boundary is the most important decision you make
Iteration 1 failed because the scope included things Linux genuinely cannot do (kernel-level anti-cheat games). Iteration 3 works because those exceptions are explicitly named, accepted, and not revisited. A clear "this stays on Windows forever" list isn't a compromise — it's what makes the Linux partition stable and purposeful instead of perpetually incomplete.
Intermittent boot issues are not random — read the log
The NVIDIA KMS race looked like flakiness. It was a deterministic timing issue with a clean, permanent fix. The only reason it took any time at all was resisting the urge to reboot past it. journalctl -b -1 — the log from the previous failed boot — told the exact story within a minute of reading it.
Each iteration's failures become the next iteration's checklist
Iteration 3's thirteen-item pre-install checklist came entirely from things that went wrong in Iterations 1 and 2. Not from general Linux documentation — from specific, named failures on this specific machine. That's the compounding value of keeping a risk register across iterations rather than starting fresh each time.
Native Linux tooling for research and development is a genuine advantage
GPU compute frameworks, containerised workloads, and research tooling like Jupyter and TeX Live run more naturally on Linux than on Windows — not because they don't work on Windows, but because Linux is the environment they're built for first. The difference shows up in setup time, driver integration, and the absence of the WSL2 translation layer between your code and the hardware.
Python virtual environments don't cross OS boundaries — and the distro choice affects how the whole toolchain fits together
A virtual environment created on Windows or Ubuntu cannot be moved to CachyOS — it contains hardcoded paths and OS-specific binaries. The portable unit is requirements.txt, not the venv folder itself. Each OS needs its own venv recreated from that file, even when the source code lives on a shared drive accessible from both systems.

The deeper difference: Ubuntu LTS pins Python for the release lifetime, which means pip wheel indexes built for newer Python versions may not have compatible builds — exactly what happened when PyTorch's index had no wheels for the installed Python version. CachyOS/Arch moves Python, CUDA, and the python- prefixed package namespace together as a rolling release. For a research and development setup where the toolchain is central, that coherence reduces the version mismatch surface significantly. The trade-off is that a Python major version bump in pacman invalidates existing venvs — but recreating a venv from requirements.txt is a one-command fix, not a debugging session.
NTFS has real constraints for compatibility-layer workloads — know them before you plan
One game launcher doesn't work correctly when installed on NTFS. The compatibility layer creates files with names that are illegal on NTFS — so its prefix directory must live on a native Linux filesystem. These aren't edge cases — they're documented constraints that affect partition planning. A large game install that was originally planned to stay on the Windows NTFS drive needed to move to the Linux Btrfs partition once these constraints were understood.
The repo is the AI's memory — and yours
Across three iterations and months of work, the git repository with its migration plan, risk register, and validation log became the primary continuity mechanism — not just for the AI assistant, but for picking up where a session left off, for making decisions informed by what had already been tried, and ultimately for writing this account of the process. The overhead of maintaining it was low; the value of having it was high every single time it was referenced.

11. When the fix is the wrong question — DaVinci Resolve's audio problem and the switch to Kdenlive

The glib fix in Section 9 made DaVinci Resolve launch and open projects cleanly. It did not make DaVinci Resolve work. No sound played in the timeline at all — not a quality issue, not a crackle, nothing. Investigating that turned into a genuine lesson about when persistence stops being the right strategy.

Two bugs, stacked

The first problem was mundane: the application's install directory was owned by root, silently blocking its own audio engine from writing its configuration. A permissions fix — nothing remarkable, the kind of thing any Linux install can hit.

The second problem was not fixable by changing a permission. DaVinci Resolve's Linux build always opens an 8-channel audio stream regardless of what's selected in settings — but the system has a standard 2-channel stereo output. The audio service responsible for connecting application output to hardware output has a genuine bug handling that specific 8-to-2 channel mismatch: it fails to link the streams and enters a crashing retry loop instead of simply downmixing or rejecting cleanly.

⚠️ A fix attempt that made things worse

One attempted workaround — forcing the system's default audio output to 2 channels system-wide — backfired. It didn't fix DaVinci's audio; it broke general system audio entirely, including browser playback and system sounds. The regression was caught, diagnosed, and fully reverted, but it's a useful data point: a fix aimed at one application's edge case touched a shared system setting and broke everything else that depended on the previous default.

No upstream fix exists for the underlying channel-mismatch bug. At that point the choice was binary: keep escalating into deeper, riskier system-level audio configuration changes chasing a bug in someone else's closed-source application, or stop.

The decision: shelve it

DaVinci Resolve was fully uninstalled — roughly 7GB reclaimed, launcher entries removed. Not a partial disable, not "we'll revisit this later with a workaround" — a clean removal, because the honest assessment was that continuing to chase this particular bug carried more risk to the rest of the system than benefit to the editing workflow.

The replacement: Kdenlive

Kdenlive — KDE's own video editor — installed from the official package repository in seconds. No manual download, no compatibility script, no library fix needed. The actual target editing workflow was tested immediately afterward: one video track, one separate audio track, with each clip's embedded sound removed so only the separate audio track plays. It worked cleanly on the first attempt.

The contrast, side by side
DaVinci Resolve
glib fix → permissions fix → channel-mismatch investigation → failed workaround → system audio regression → revert → uninstall
Kdenlive
install → test target workflow → working

The carry-over to the laptop

The laptop migration had been deliberately paused at this exact point — waiting to see how the desktop's DaVinci problem resolved before testing the same application on a second machine. That pause was the right call: testing blind on the laptop would have meant either hitting the identical audio bug a second time and re-diagnosing it from scratch, or worse, misattributing it as laptop-specific hardware trouble when it was actually the same application-level bug.

With the desktop's result confirmed, the laptop's plan now uses Kdenlive from the outset — a known-working result carried directly from one machine's validation into another machine's plan, before that plan had even reached a live-USB boot. This is the documentation structure paying for itself again, in a different form than the boot-hang fix or the partition checklist: not a technical workaround being reused, but a negative result — "don't bother with this app, here's why, here's what works instead" — saving a second machine from repeating the same multi-step dead end.

💡 The lesson

Sometimes the right call isn't finding the fix — it's recognising when an application is fighting the platform at a level that can't be reasonably resolved, and switching to a tool that doesn't have that fight built in. Two regressions and a full troubleshooting session later, the actual solution wasn't a deeper hack. It was a different, simpler piece of software that didn't carry the same architectural baggage.


Where things stand

Three iterations in, with a real boot-reliability fix folded permanently into the install process and one application-level dead end traded for a working replacement. The desktop runs Windows for the applications that require it, and CachyOS for everything else — research, creative work, development, and gaming on one consolidated partition. The validation period is ongoing. The laptop migration, paused while this exact DaVinci question was being resolved, now carries the answer forward. The story isn't finished — but each chapter has produced something the next one used.

Along the way, some findings deserve their own treatment — office suite compatibility on Linux turned out to have a more nuanced answer than expected, with the document engine architecture mattering far more than the feature list. That's the subject of the next piece.

Iter 1: rolled back ✓
Iter 2: replaced ✓
Iter 3: validating →
Laptop: next →

A clean success, a rollback, or a work-in-progress — doing it with structured documentation means you'll know exactly why, with a record that makes the next attempt faster than the last.

Comments