Three things were in history that should not have been, all invisible to the tool that deploys them: - `home/dank/.omp/dotfiles/**` — 3 files re-hosting `niri/cfg/autostart.kdl`, `niri/cfg/keybinds.kdl` and `systemd-user/…/swayidle-lock.service` under a prefix `scripts/deploy.sh` never reads (it walks `dotfiles/<pkg>/`). The live package is deployed and symlinked, so the copy asserted nothing; it only misled. Moved to `.AGENTTRASH/20261020-tracked-debt/`. - `.pre-pull-backup/**` — 2 managed-skill files, a local backup in history, which `.gitignore` itself declares must stay on disk only. Same destination. - `dotfiles/noctalia/.local/share/noctalia/wallpapers/` — 23 images, 80.4 MiB. Untracked, files left in place: `~/.local/share/noctalia/wallpapers` symlinks into this directory and the theme reads it, so deleting them would have gone black. Every filename carries its wallhaven ID, so a fresh box restores the set with one `curl` per file plus `deploy.sh`; losing the set is an acceptable outcome, 80 MiB per clone forever is not. New page `omp-docs/tools/dotfiles-deploy.md` owns the deploy contract (the `--check`/sync/`--adopt` modes, `zz-$(hostname)` override semantics, the dconf and systemd-user special cases) because nothing documented it, plus two laws: media the pipeline consumes is content not config, and `systemctl --user enable` snapshots an absolute path — so enabling from a worktree means the seven-day reap silently kills the unit while `is-enabled` keeps answering `enabled`. That second law is not theoretical: `default.target.wants/blankpad-desk-autoswitch.service` pointed into the reaped `wt/de-redesign-20261009` and desk auto-switching had been off since. It is relinked to `dotfiles/zz-blankpad/` and left inactive rather than started mid- session; starting it applies a desk profile. Refs #40
73 lines
3.7 KiB
Markdown
73 lines
3.7 KiB
Markdown
---
|
|
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_<id>.<ext>` and the ID is the whole
|
|
address — `curl -L -o <name> "https://wallhaven.cc/w/<id>"` 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/<unit>` 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.
|