dotfiles
Log

Arch parity audit

Edit on GitHub

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.

Promoted on 12/10/2026. nixos was renamed to main. The old Arch main was folded into arch and tagged archive/arch-final, so the main:<path> references below now resolve as archive/arch-final:<path>. The arch branch itself was deleted on 13/10/2026, once the tail was decided; the tag is the same commit. The tail of 16 areas was NOT decided first, on purpose: with the Arch tree still one branch away, it stopped blocking the rename, and re-measuring it is its own task.

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:

RefFilesWhat it holds
main659The FULLEST Arch snapshot: arch plus 2 commits (the netextender NAT gateway and one VS Code tweak)
arch656The same tree, 2 commits behind main. Nothing exclusive
nixos296Today'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. It forks off main at 2ccecf9, so the LAST 4 Arch commits are not in it

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.

Re-measured on 13/10/2026

The same sweep, a month and the rename later. Of the 16 tail areas, most closed on their own while other work went by, and the rest were decided one by one with the Arch tree open in arch. The sections below this one are left as measured on 08/09, so read this table first.

AreaNowWhere, or why
atuinPortedprograms.atuin in modules/home/shell/cli.nix, on Ctrl+R
easyeffectsReplacedThe speaker EQ is a PipeWire filter-chain in modules/nixos/hardware/audio.nix
spicetifyReplacedSpotify itself gave way to Spotifast, its colors from the palette, in modules/home/apps/spotifast.nix
nanoPorted, as a decisionEDITOR=nano in zsh.nix. Its syntax files come with nano 9.2; the Arch .nanorc only pulled a third-party set whose nixpkgs copy is from 2020
neovimDroppedStock LazyVim boilerplate, nothing personal in it (see the corrected entry below)
zshClosedPorted: Ctrl+arrows, double-Esc sudo, the YouTube aliases (ytmix is the shuffled playlist), grep --color=auto. Replaced: fhome/froot by fzf's Alt+C and Ctrl+T through fd (the aliases ran cd . on Esc and walked all of /); the ssh TERM alias by SetEnv TERM per host in ssh.nix. Dropped: fastfetch at startup (measured: 0.09 s on a 0.12 s shell, and it would print in every VS Code and agent shell too; fastfetch is one command away) and nrd, since toolchains live in devShells
kittyClosedOnly cursor_shape beam came back. The rest was kitty's own defaults (wheel_scroll_multiplier 5.0, repaint_delay, input_delay, sync_to_monitor, disable_ligatures never), and F8/F9/F10 were refused: they duplicate binds that exist and steal F9/F10 from htop and btop
btopPorted, and betterArch ran Default; now tokyo-night, set in place because btop owns its file (rule 14). bat and delta followed in the same pass
vlcNothing to portvlcrc held one active line, qt-privacy-ask=0
ghPortedprograms.gh in modules/home/shell/git.nix
zen-browserRewrittenA minimal palette theme on Zen's own variables, modules/home/apps/zen/theme.nix. zen-sync is the activation now. Refining it is an open item
hypr: wallpaper rotationPortedThe september wallpaper work, per monitor, from my own pools
hypr: 3-minute idle dimDroppedNot used and not wanted. It lived in Arch's idle-dim.sh, a listener that zeroed the gamma at 180 s before the lock at 300 s
hypr: lockscreen notification countDroppedNot wanted. Arch's lockscreen_notifs.sh read it over IPC; the notif count IPC verb that waited for it in Notifs.qml went too, since nothing called it
bin/Closedvpn, wake-workstation ported; hypr-quick's wallpaper actions went with the rotation; zen-sync became the theme's activation
scripts/ClosedArch by nature, as measured below
homelab and the Caddy setDroppedEvery absent service decided NOT to come back (13/10/2026): what covers each one is in the section below. The 9 vhosts declared now are the whole set
polychromaticReplacedThe OpenRGB service already in place for the Arc B580 DETECTS the Razer DeathAdder V2 (measured with openrgb --client --list-devices), so no openrazer GUI is needed. Setting the mouse's color from Nix would be new work, not a gap
opencodePortedmodules/home/shell/opencode.nix (25/10/2026), from pkgs.unstable. The Arch MCP list was not carried over: it pointed at /opt and project-specific servers
lazydockerPortedmodules/nixos/services/docker.nix, only where the engine is enabled. Ten containers run here, so a TUI over them earns its place

The verdict

53 configuration areas on the Arch side, and the split is what a finished migration looks like with a tail:

VerdictAreasMeaning
Migrated25Declared on NixOS, same job, usually a superset
Replaced9A different tool doing the same job, on purpose
Dropped on purpose2Decided against, with the reasoning already written down
Arch-only1Meaningless outside pacman
Partial8The app came across, some of its config did not
Missing8Nothing 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.

Nothing is left since 13/10/2026. Every one of those 16 areas now has a final verdict in the re-measured table above (ported, replaced, closed or dropped), the homelab being the last, so the migration is DONE. What stays open after it is ordinary work, such as refining the Zen theme, and lives in open-items.md like anything else.

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 areaWhere it lives now
main:hypr/ (37 files)modules/home/desktop/hypr.nix plus 7 Lua files. Two deltas, below
main:quickshell/ (17)modules/home/desktop/quickshell.nix plus 25 QML files, a superset
main:vscode/ (8)modules/home/apps/vscode.nix: settings, keybindings, MCP and the extension mirror
main:netextender/ (12)modules/nixos/network/vpn.nix (nxBender) plus modules/nixos/network/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)modules/nixos/network/network.nix plus the generated jail in modules/nixos/services/caddy.nix
main:ssh/ (4)network.nix (port 2222, now with TOTP) plus modules/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/hosts/cudy-wr3000/uci/, because the tunnel moved to the router
main:system/ (14)modules/nixos/core/core.nix (locale, timezone, br-abnt2), hostName per host, modules/nixos/core/boot.nix
main:swap/zramSwap.enable in modules/nixos/hardware/hardware.nix
main:fontconfig/modules/nixos/desktop/fonts.nix, a superset: CJK plus corefonts plus vista-fonts
main:gtk-3.0/, main:gtk-4.0/modules/home/desktop/theme.nix plus modules/home/desktop/palette.nix
main:rofi/replaced by Vicinae on 13/10/2026: modules/home/desktop/vicinae/, themed from the palette
main:kitty/modules/home/shell/kitty.nix. Small deltas, below
main:starship/modules/home/shell/starship.nix
main:git/modules/home/shell/git.nix
main:fastfetch/modules/home/shell/fastfetch/
main:flameshot/modules/home/apps/flameshot.nix, with the sc1/sc2 aliases by monitor NAME
main:mpv/programs.mpv in modules/home/apps/media.nix
main:uv/The package in modules/nixos/packages.nix; the receipt is state (rule 6)
main:autostart/modules/home/apps/dropbox.nix plus modules/home/desktop/autostart.nix, one unit per app
main:claude/claude-desktop-fhs in modules/home/packages.nix
main:.claude/.claude/settings.json, plus the managed layer of modules/nixos/services/claude-code.nix
The root .md filesThe 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 areaWhat does the job nowWhy
main:waybar/ (23)The Quickshell barThe port happened while still on Arch; the bar is QML now
main:swaync/Quickshell's notification serviceOne daemon fewer, and it is already the tray owner
main:xsettingsd/gtk plus dconf in theme.nixThe idiomatic home-manager path; no X11 daemon
main:greetd/ (7)LightDM plus autologin in modules/nixos/desktop/desktop.nixSunshine captures a LIVE session, so the machine has to log itself in
main:kwallet/gnome-keyring in the same desktop.nixIt is the org.freedesktop.secrets provider VS Code asks for
main:openrazer/hidraw plus razer-dpi in modules/nixos/hardware/deathadder-v2.nixopenrazer does not build on kernel 7.1 or newer
main:cloudflare-ddns/ (4)ddns-scripts on the router, hosts/cudy-wr3000/uci/ddns.confThe anchor stopped depending on this machine being awake
main:docker/modules/nixos/services/docker.nix, the prune policyThe 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 areaDecision
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 was the biggest gap by far, and the only one that would have been 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.

SubdomainPortOn NixOS
jellyfin8096Yes, and NATIVE now instead of a container
torrent8080Yes, native (modules/nixos/services/qbittorrent.nix)
ai11434Yes, expose = "lan" (modules/nixos/services/ollama.nix)
duo3010Yes (modules/nixos/services/duo.nix)
chat3000Dropped. open-webui: Ollama stays in ai, and the chat I use is Claude and agy
jellyseerr5055Dropped, with the whole *arr stack: no media is fetched on a schedule anymore
prowlarr9696Dropped (*arr)
radarr7878Dropped (*arr)
sonarr8989Dropped (*arr)
bazarr6767Dropped (*arr)
spendflow3001Dropped. My own project, not in use; it can come back like credit and pos if it is
ap3005Dropped. ufscar-housing-radar (V1C-68), idle since 30/06/2026
dash3003Dropped. Homepage: the Quickshell dash is the status page now, and it needed the docker socket
files3004Dropped. FileBrowser: Dolphin, SSH and rclone cover it, without files on the web

Two containers had no subdomain and were dropped too: flaresolverr (the *arr stack's captcha solver, gone with the stack) and the RustDesk server (hbbs/hbbr), which Sunshine/Moonlight and RDP replace.

Decided on 13/10/2026: none of them comes back. Each one was weighed on its own (what it did, what covers it now, what it would expose), and the answer was the same for all. Their loopback ports were released from the map in notes/network/caddy.md. A service that does come back one day starts as a new project, with a free port and a vhost; the DNS records of the old ones were already removed in august, so nothing is waiting for it.

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 .zshrc bound Ctrl+R to atuin-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. bindkey does not exist in this branch: Home, End, Delete, Ctrl+arrow word jumps, the double-Esc that prefixes sudo, 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.
  • fastfetch at 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 pinned nano, which is also not installed here; vim is.
  • The YouTube and mpv aliases: yttui, ytmix, ytvideo, ytaudio, ytwatch, with the playlist URL and the format strings. yt-dlp and mpv are both declared, so this is five aliases and one URL.
  • fhome and froot, the fd plus fzf jump-to-any-file pair.
  • Small ones: grep --color=auto, nrd, and ssh forcing TERM=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/

ScriptStatus
vpn, vpn-offThe vpn CLI in modules/nixos/network/vpn.nix, and it needs no password (polkit)
wake-faiwake-workstation in modules/home/network/fai-workstation.nix, with three WoL paths instead of one
dark-mode, tokyo-nightObsolete by construction: the theme is a Nix palette applied at build time (rule 11, decision 0001)
hypr-quickMissing. Mostly subsumed by the binds, EXCEPT its wallpaper actions
zen-syncMissing, 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.sh and change_wallpapers.sh implemented 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. Here hyprpaper serves two fixed images and SUPER+I is the scrolling layout's consume. 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. modules/home/desktop/hyprsunset.nix dims 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 modules/home/desktop/lockscreen/default.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 modules/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 modules/nixos/core/sync-secrets.sh plus sops-nix, the wireguard and WoL router scripts became hosts/cudy-wr3000/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:

  1. 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 the mkOrder in modules/home/shell/cli.nix is the place to read first.
  2. easyeffects (main:easyeffects/, 4 files). CORRECTED on 08/09/2026, because the first pass of this page called these "presets" and they are not: equalizerrc and compressorrc are EMPTY, bassEnhancerrc holds one line (floorActive=true), and easyeffectsrc only records which three plugins were in the chain. So the chain was enabled and never tuned. Worse for porting, easyeffectsrc pins input and output to alsa_output.usb-Jieli_Technology_HECATE_G1500_MAX-00, a headset that no longer appears in wpctl status. There is no tuning to carry over, only the decision to build a chain again.
  3. 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.
  4. 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.lua and autocmds.lua have ZERO active lines, all three being comment-only stubs, and lua/plugins/example.lua opens with if 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 the lazy-lock.json pins plugins for a config that does not exist.
  5. spicetify (main:spicetify/). Spotify theming. Spotify is declared (with --no-zygote baked 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.
  6. 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.
  7. lazydocker (main:lazydocker/). A docker TUI. Neither package nor config.
  8. nano (main:nano/). The .nanorc, and nano itself is not installed. If EDITOR gets 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:

  1. The default branch never gets swapped to force anything. That is the lesson of the contributions incident: main and nixos are ORPHAN histories, so pointing the default at the wrong one zeroed the graph. The promotion has to be the deliberate, final one.
  2. 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.
  3. The refs that were retired: the old main on 12/10/2026, after arch caught up with it, and arch itself on 13/10/2026, once the tail below was decided. The nix-flake-skeleton tag, which points at a commit whose whole content is the pivot doc, was left alone.
  4. The tag to KEEP, and this is the one that must not be swept up with the rest: archive/pre-nix-2026-07-16 is the only ref holding the 493 pre-Nix commits. It is NOT the last anchor of the Arch tree, though, which this page claimed until 12/10/2026: it forks off main at 2ccecf9, and the 4 commits after that (the netextender NAT gateway among them) lived only on main. That is why archive/arch-final was tagged on the old main tip (ecbaa32) before it was deleted, and arch was fast-forwarded to the same commit.
  5. 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-antigo mount reads. Retiring the git refs does not touch it.