Arch parity audit¶
The measurement that says whether the migration is DONE. Measured on 08/09/2026, before
promoting nixos to the default branch and retiring the Arch refs.
This is not the same page as arch-linux.md, and the difference matters: that one is the pointer to the restic ARCHIVE (the 44.6 GiB snapshot of the old machine); this one is the diff of the CONFIGURATION that still lives in this repo's own Arch branches. The archive answers "where is my old data"; this answers "what did I never port".
It is a SNAPSHOT and not a note kept current (rule 16 draws that line): a re-measure is one sweep of the same greps, and the number that ages is the count, not the method. Whatever gets ported closes here and moves to open-items.md or to history/, the same as any other work.
What was compared¶
Every ref in the repo, because "check all the branches" was the ask and three of the six carry no configuration of their own:
| Ref | Files | What it holds |
|---|---|---|
main |
659 | The FULLEST Arch snapshot: arch plus 2 commits (the netextender NAT gateway and one VS Code tweak) |
arch |
656 | The same tree, 2 commits behind main. Nothing exclusive |
nixos |
296 | Today's config. An ORPHAN history: no merge base with main or arch |
backup-ptbr-msgs |
- | Branched off nixos. Only pt-BR commit messages, no config of its own |
salvaguarda-voz |
- | Branched off nixos. Same thing, the voice safeguard of rule 17 |
fix/jellyfin-wait-ipv4 |
- | Already merged into nixos (0 commits ahead) |
tag archive/pre-nix-2026-07-16 |
- | It preserves the 493 pre-Nix COMMITS, but its TREE is the post-reset clean slate |
So the real comparison is main against nixos, and the tag is a history anchor rather
than a source of files. The wallpapers dominate main's count (369 of the 659), which is why
the file totals say less than the area totals below.
The verdict¶
53 configuration areas on the Arch side, and the split is what a finished migration looks like with a tail:
| Verdict | Areas | Meaning |
|---|---|---|
| Migrated | 25 | Declared on NixOS, same job, usually a superset |
| Replaced | 9 | A different tool doing the same job, on purpose |
| Dropped on purpose | 2 | Decided against, with the reasoning already written down |
| Arch-only | 1 | Meaningless outside pacman |
| Partial | 8 | The app came across, some of its config did not |
| Missing | 8 | Nothing on this side at all |
The 16 areas in the last two rows are the whole of what is left, and none of them holds the machine back: the desktop, the network, the boot, the backup, the secrets and the remote access are all on this side. What is left is a self-hosted stack, some comfort in the shell, and a handful of app configs.
Area by area¶
Arch paths are written main:<path> on purpose, the git-rev form, so the docs link checker
does not read them as paths that should exist on this branch.
Migrated¶
| Arch area | Where it lives now |
|---|---|
main:hypr/ (37 files) |
home/desktop/hypr.nix plus 7 Lua files. Two deltas, below |
main:quickshell/ (17) |
home/desktop/quickshell.nix plus 25 QML files, a superset |
main:vscode/ (8) |
home/apps/vscode.nix: settings, keybindings, MCP and the extension mirror |
main:netextender/ (12) |
system/net/vpn.nix (nxBender) plus system/net/fai-gateway.nix; the WoL scripts became wake-workstation |
main:networkmanager/ |
The UFSCar profile became openconnect/GlobalProtect in the same vpn.nix |
main:fail2ban/ (5) |
system/net/network.nix plus the generated jail in system/services/caddy.nix |
main:ssh/ (4) |
network.nix (port 2222, now with TOTP) plus home/shell/ssh.nix |
main:caddy/ (3) |
caddy.nix, with the vhosts GENERATED from my.ingress. The subdomain SET is smaller, see Partial |
main:wireguard/ |
router/uci/, because the tunnel moved to the router |
main:system/ (14) |
system/core/core.nix (locale, timezone, br-abnt2), hostName per host, system/core/boot.nix |
main:swap/ |
zramSwap.enable in system/hardware/hardware.nix |
main:fontconfig/ |
system/hardware/fonts.nix, a superset: CJK plus corefonts plus vista-fonts |
main:gtk-3.0/, main:gtk-4.0/ |
home/desktop/theme.nix plus home/desktop/palette.nix |
main:rofi/ |
home/desktop/launcher.nix plus home/desktop/clipboard.nix, themed from the palette |
main:kitty/ |
home/shell/kitty.nix. Small deltas, below |
main:starship/ |
home/shell/starship.nix |
main:git/ |
home/shell/git.nix |
main:fastfetch/ |
home/shell/fastfetch.nix |
main:flameshot/ |
home/apps/flameshot.nix, with the sc1/sc2 aliases by monitor NAME |
main:mpv/ |
programs.mpv in home/apps/media.nix |
main:uv/ |
The package in system/packages.nix; the receipt is state (rule 6) |
main:autostart/ |
home/apps/dropbox.nix plus home/desktop/autostart.nix, one unit per app |
main:claude/ |
claude-desktop-fhs in home/packages.nix |
main:.claude/ |
.claude/settings.json, plus the managed layer of system/services/claude-code.nix |
The root .md files |
The whole of docs/. ANOTACOES.md was 1949 lines and became this tree |
Replaced¶
Same job, a different tool, and each one has its reasoning already recorded:
| Arch area | What does the job now | Why |
|---|---|---|
main:waybar/ (23) |
The Quickshell bar | The port happened while still on Arch; the bar is QML now |
main:swaync/ |
Quickshell's notification service | One daemon fewer, and it is already the tray owner |
main:xsettingsd/ |
gtk plus dconf in theme.nix |
The idiomatic home-manager path; no X11 daemon |
main:greetd/ (7) |
LightDM plus autologin in system/desktop/desktop.nix |
Sunshine captures a LIVE session, so the machine has to log itself in |
main:kwallet/ |
gnome-keyring in the same desktop.nix |
It is the org.freedesktop.secrets provider VS Code asks for |
main:openrazer/ |
hidraw plus razer-dpi in system/hardware/razer.nix |
openrazer does not build on kernel 7.1 or newer |
main:cloudflare-ddns/ (4) |
ddns-scripts on the router, router/uci/ddns.conf |
The anchor stopped depending on this machine being awake |
main:docker/ |
system/services/docker.nix, the prune policy |
The only content was the nvidia runtime, and the GPU is an Arc now |
main:bash/ |
zsh as the login shell | .bashrc was already vestigial |
Dropped on purpose¶
| Arch area | Decision |
|---|---|
main:wallpapers/ (369 files) |
pkgs.nixos-artwork instead, so no binary lives in git. Recorded in the july history. The images went; the ROTATION went with them, which is a delta and not a decision, see below |
main:cloudflare/ (the tunnel) |
expose = "public" works without it. Written down in the august history: "there is no need for cloudflared" |
main:pacseek/ is the one area that has no NixOS meaning at all.
The eight partial areas¶
main:homelab/ plus the Caddy subdomain set¶
This is the biggest gap by far, and the only one that is a project rather than a chore. Arch
served 14 subdomains; this branch declares 5, and one of those (pos, GradRadar) is new
and never existed over there.
| Subdomain | Port | On NixOS |
|---|---|---|
jellyfin |
8096 | Yes, and NATIVE now instead of a container |
torrent |
8080 | Yes, native (system/services/qbittorrent.nix) |
ai |
11434 | Yes, expose = "lan" (system/services/ollama.nix) |
duo |
3010 | Yes (system/services/duo.nix) |
chat |
3000 | No. open-webui |
jellyseerr |
5055 | No |
prowlarr |
9696 | No |
radarr |
7878 | No |
sonarr |
8989 | No |
bazarr |
6767 | No |
spendflow |
3001 | No |
ap |
3005 | No. ufscar-housing-radar (V1C-68) |
dash |
3003 | No. Homepage, plus its docker-socket-proxy |
files |
3004 | No. FileBrowser, and its fail2ban jail went with it |
Two containers had no subdomain and are also absent: flaresolverr (the *arr stack's captcha
solver) and the RustDesk server (hbbs/hbbr).
The port table in notes/network/caddy.md already RESERVES every one of
those numbers, and notes/services/jellyfin.md says the *arr apps
"come later, one module at a time", so this is a queue and not an oversight. The one thing to
know before working it: the DNS records for bazarr, prowlarr, radarr, sonarr,
jellyseerr, spendflow, chat, dash and files were REMOVED from the zone and from the
router's dnsmasq during the august cleanup. The wildcard covers them again the moment a vhost
exists, but a stale mental model of "the DNS is already there" is not true anymore.
main:zsh/¶
The structure came across whole (history options, autosuggestions, syntax highlighting, the zoxide-goes-last trick, the eza and screenshot aliases, and the Claude accounts, which are better here). What did not:
- atuin. The Arch
.zshrcbound Ctrl+R toatuin-search; here Ctrl+R is fzf's. Atuin is a searchable, statistics-keeping, syncable history, and it appears NOWHERE on this branch. It is its own Missing entry below. - The keybindings.
bindkeydoes not exist in this branch: Home, End, Delete, Ctrl+arrow word jumps, the double-Esc that prefixessudo, and Alt+R for the fzf history widget. The word jumps and the sudo trick are certainly gone; whether Home/End still work depends on what terminfo gives zsh under kitty, so that one is worth TESTING rather than assuming. fastfetchat shell startup. The module is configured and nothing ever calls it, so the summary that used to greet every terminal does not.EDITOR. Unset anywhere on this branch. Arch pinnednano, which is also not installed here;vimis.- The YouTube and mpv aliases:
yttui,ytmix,ytvideo,ytaudio,ytwatch, with the playlist URL and the format strings.yt-dlpandmpvare both declared, so this is five aliases and one URL. fhomeandfroot, the fd plus fzf jump-to-any-file pair.- Small ones:
grep --color=auto,nrd, andsshforcingTERM=xterm-256color.
Deliberately gone, and correctly so: the pacman update/clean aliases, the arch-update
wrapper with its AUR supply-chain gate, stow-sync, and the .zprofile that started Hyprland
through uwsm on TTY1. The toolchain PATH exports (dotnet, pnpm, conda, dart, opencode) are
gone by policy, since toolchains live in a devShell reached by direnv now.
main:bin/¶
| Script | Status |
|---|---|
vpn, vpn-off |
The vpn CLI in system/net/vpn.nix, and it needs no password (polkit) |
wake-fai |
wake-workstation in home/net/fai-workstation.nix, with three WoL paths instead of one |
dark-mode, tokyo-night |
Obsolete by construction: the theme is a Nix palette applied at build time (rule 9) |
hypr-quick |
Missing. Mostly subsumed by the binds, EXCEPT its wallpaper actions |
zen-sync |
Missing, and it is the delivery half of the Zen customization below |
main:hypr/, the two deltas¶
Everything else in Hyprland is at parity or better: input is a line-for-line port, the window
rules and workspace rules match, the appearance block matches (and gained the scrolling
layout), the keybinds are a superset with a generated cheatsheet, and 16 of the 18 loose scripts
became either a writeShellApplication or a systemd timer. The two that did not:
- The wallpaper rotation.
auto_wallpaper.shandchange_wallpapers.shimplemented a smart random walk with a 20-entry history, weights for never-used images and validation before use, on SUPER+I, SUPER+SHIFT+I and SUPER+CTRL+I. Herehyprpaperserves two fixed images and SUPER+I is the scrolling layout'sconsume. Dropping the 369 images was a decision; dropping the FEATURE was not written down as one. - The 3-minute idle dim. Arch had a listener that zeroed the gamma at 180s, before the lock
at 300s, through
idle-dim.sh. This branch has ONLY the 300s lock listener.home/desktop/hyprsunset.nixdims by time of day, which covers the evening but not "I walked away at noon".
One more, cosmetic: the lockscreen's notification COUNT label (lockscreen_notifs.sh, reading
qs ipc call notif count) has no counterpart in
home/desktop/lockscreen.nix. The clock, date, user, quote
and weather labels are all there, and the quotes got better (a ZenQuotes plus DeepL timer
replaced the vendored TSV).
main:kitty/¶
Parity on everything that matters, with a rewrite rather than a port, so a few settings simply
were not carried: cursor_shape beam, hide_window_decorations, wheel_scroll_multiplier 5.0,
the repaint_delay/input_delay tuning, disable_ligatures never, and the F8/F9/F10 plus
Ctrl+Alt+A/C maps. The font went 11 to 12, the opacity 0.92 to 0.95, the scrollback 15000 to
10000 and the padding 12 to 8, which read as choices, not losses.
main:btop/, main:vlc/, main:gh/¶
The same shape three times: the PACKAGE is declared and the CONFIG is not. btop.conf (the
theme and the layout), vlcrc and gh/config.yml. All three are small and all three are the
kind of file the app rewrites itself, so rule 14 decides the form: an activation script or an
immutability marker, not a managed file.
main:zen-browser/¶
The browser is declared and is the default ($BROWSER, and the mime associations in
home/desktop/xdg.nix). Its CUSTOMIZATION is not: userChrome.css
(618 lines) and user.js (18 prefs). This is the pair zen-sync used to deliver.
main:scripts/¶
47 files, and most of them are Arch by nature: the pacman and AUR package sync with its systemd
timer, the AUR supply-chain checker, stow-sync.sh, the rEFInd menu cleanup, and one deploy.sh
per service, which is what "no declarative layer" costs. What had real content came across:
the secrets backup became scripts/sync-secrets.sh plus sops-nix,
the wireguard and WoL router scripts became router/uci/, and the VPN scripts became the vpn
CLI. Nothing here needs porting; it needs deleting along with the branch.
The eight missing areas¶
Ordered by what I would actually miss, not alphabetically:
- atuin (
main:atuin/). The shell history with search, stats and sync. Nothing on this branch. It has a home-manager module (programs.atuin), and the trap is already documented next door: whatever initializes last fights zoxide's doctor, so themkOrderinhome/shell/cli.nixis the place to read first. - easyeffects (
main:easyeffects/, 4 files). CORRECTED on 08/09/2026, because the first pass of this page called these "presets" and they are not:equalizerrcandcompressorrcare EMPTY,bassEnhancerrcholds one line (floorActive=true), andeasyeffectsrconly records which three plugins were in the chain. So the chain was enabled and never tuned. Worse for porting,easyeffectsrcpins input and output toalsa_output.usb-Jieli_Technology_HECATE_G1500_MAX-00, a headset that no longer appears inwpctl status. There is no tuning to carry over, only the decision to build a chain again. - polychromatic (
main:polychromatic/, 6 files). The Razer RGB GUI, and it is absent for the same reason openrazer is: no daemon. This connects to the OpenRGB item already open in open-items.md, which is about the Arc B580's RGB rather than the mouse's, but it is the same missing layer. - Neovim (
main:nvim/, 13 files). CORRECTED on 08/09/2026, and this one reverses the verdict: the first pass called it "a full LazyVim setup", and it is STOCK BOILERPLATE.options.lua,keymaps.luaandautocmds.luahave ZERO active lines, all three being comment-only stubs, andlua/plugins/example.luaopens withif true then return {} end, LazyVim's own early return, so its 134 remaining lines never execute. What is in there is the distributed example, gruvbox and a lualine that returns an emoji included. There is nothing personal to port, and thelazy-lock.jsonpins plugins for a config that does not exist. - spicetify (
main:spicetify/). Spotify theming. Spotify is declared (with--no-zygotebaked into the package); the theme is not. There is a community flake for it, and it patches the app, so it argues with rule 14 and deserves reading before doing. - opencode (
main:opencode/). One config file for an agent CLI that is not declared here at all. Claude Code, codex and agy are; this one has to be a decision, since three is already a lot of them. - lazydocker (
main:lazydocker/). A docker TUI. Neither package nor config. - nano (
main:nano/). The.nanorc, and nano itself is not installed. IfEDITORgets set (see zsh above), this is the same decision seen twice.
Before the cutover¶
The branch promotion is not blocked by anything above; it is blocked by one thing that is not in this repo. Recording the order so it does not get improvised:
- The default branch never gets swapped to force anything. That is the lesson of the
contributions incident:
mainandnixosare ORPHAN histories, so pointing the default at the wrong one zeroed the graph. The promotion has to be the deliberate, final one. - Decide the 16 tail areas first. Each one is either a port or a struck-through decision. What gets ported closes here; what gets dropped gets a line saying why, because "it is in the old branch" stops being an answer the day the old branch is gone.
- The refs to retire, once the tail is decided: the
archandmainbranches, and thenix-flake-skeletontag, which points at a commit whose whole content is the pivot doc. - The tag to KEEP, and this is the one that must not be swept up with the rest:
archive/pre-nix-2026-07-16is the only ref holding the 493 pre-Nix commits. Deleting it loses them, since the branches it hangs off are the ones being deleted. If the branches go, that tag is the last anchor, and a tag is enough to keep the objects alive. - The restic archive is a separate question and it is already answered in
arch-linux.md: the offsite copy is the only copy, it passed
check --read-data, and it is what the/mnt/arch-antigomount reads. Retiring the git refs does not touch it.