--- type: reference title: Dotfiles deployment tier description: How dotfiles/ packages become live configuration — stow-equivalent symlinks, host override packages, and the two laws about theme media and systemd enable symlinks. tags: - dotfiles - deployment - systemd - noctalia timestamp: 2026-10-20 verified: 2026-10-20 --- # Dotfiles deployment tier `dotfiles/` holds home-relative trees and `scripts/deploy.sh` is a stow-equivalent: the repo checkout **is** the deployment, and deploying replaces live files with symlinks into the repo, so `git pull` + `deploy.sh` is the whole propagation story. One directory per tool (`niri`, `ghostty`, `gtk-3.0`, `systemd-user`, …); a package named `zz-$(hostname)` is stowed last and its files replace symlinks coming from base packages. | Mode | Effect | |---|---| | `deploy.sh --check` | dry run — adopts identicals, reports what would be linked, lists divergents, writes nothing. Run this first, always | | `deploy.sh` (sync) | adopt identicals, link new, quarantine divergents into `.quarantine/` and replace them | | `deploy.sh --adopt` | like sync, but divergents are reported and skipped rather than quarantined | Two package shapes are not symlinks: `dconf/dump.txt` is loaded with `dconf load /`, and `systemd-user` units get `daemon-reload` plus `enable --now` only when their `ExecStart` binary resolves on the current machine, so a unit belonging to another box stays inert instead of crash-looping. **The tracked unit is the file, not the directory.** A live directory can be a real directory and still be fully tracked, because every file inside it is a symlink into the repo (`niri` is 12 tracked / 1 box-only; `gtk-3.0` is 3/0). Any audit that classifies by directory mislabels the tree — classify per file with `readlink -f`. The live census and its classifier command are in [home-config-census](/inventory/home-config-census.md). ## Law: media the theme pipeline consumes is content, not config Wallpapers live at `dotfiles/noctalia/.local/share/noctalia/wallpapers/` and are gitignored. They were tracked until 2026-10-20 — 23 files, 80 MiB — which meant every clone of a *configuration* repo carried a media library no diff can review, and the payload only ever grows because deleting a tracked blob from the tree does not delete it from history. [Noctalia](noctalia-shell.md) reads `~/.local/share/noctalia/wallpapers/`, which is a set of symlinks into that directory, so the files stay on disk and untracking them broke nothing on this box. Restore on a fresh box: every filename is `wallhaven_.` and the ID is the whole address — `curl -L -o "https://wallhaven.cc/w/"` puts the library back, then `deploy.sh` relinks it. Losing the set is an acceptable outcome; 80 MB per clone forever is not. ## Law: never `systemctl --user enable` a unit from a worktree `enable` writes `~/.config/systemd/user/default.target.wants/` as a symlink to the unit path it was handed, and that path is absolute. The heartbeat reaps `wt/*` worktrees older than seven days ([live-sync](live-sync.md)), so a unit enabled from a worktree turns into a dangling symlink while `systemctl --user is-enabled` still answers `enabled` — the unit is dead and the status lies about it. Found on 2026-10-20: `blankpad-desk-autoswitch.service` pointed into the reaped `wt/de-redesign-20261009`, so desk auto-switching had been silently off since the reap. Check the link target before the unit file: ```bash ls -l ~/.config/systemd/user/default.target.wants/ # every target must resolve; a dangling one is a reaped worktree, not a config bug ``` Fix is to relink into the deployment checkout (`~/.omp/dotfiles/…`), `systemctl --user daemon-reload`, then confirm with `is-active` — `is-enabled` proves nothing.