You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Option A (per-host stow overlay). Chezmoi (Option D) tracked separately as a parallel spike in #4.
2
Stale branches
origin/xps, origin/alt, origin/master deleted. Local danklinux deleted (rejected dank niri experiment). pc/xps retained until migration extracts portable commits.
3
Waybar split
Try the DRYer split (base + per-host fragment merged at setup). Fall back to whole-file overlay if it gets painful.
4
mpd
Used on all machines → not host-specific. Belongs as a base systemd enable, not in the xps overlay.
5
yay vs paru
Justfile standardizes on paru (CachyOS default — guaranteed present on fresh install). User keeps yay separately as muscle-memory for interactive use; optional install-yay recipe.
6
systemd *.target.wants/* symlinks
Gitignore them. Repo tracks unit files (what exists); a services-enable justfile recipe tracks intent (what's enabled). Uses the proper systemctl enable API.
7
mise per-host catalog
conf.d/ per-host overlay — base shared in terminal/, host-specific tools in hosts/<host>/dot-config/mise/conf.d/<host>.toml. Tool tables merge additively.
pc/xps has been the working branch on the XPS machine; main has continued to receive general updates. They've drifted and need reconciling. Before doing that, we should pick a per-host model so this doesn't keep happening.
Target universe: two CachyOS notebooks, daisy (AMD Ryzen) and xps (Intel i7). No Fedora, no WSL — those paths are obsolete.
Current state (snapshot)
Merge base: 3eab9cc
main is 8 commits ahead of the merge base
pc/xps is 5 commits ahead of the merge base
Net diff: 21 files changed, 396 insertions(+), 83 deletions(-)
Classifying the 5 pc/xps commits
Commit
Subject
Verdict
ec93a6d
solaar: add [Install] section so it can be enabled
Portable — fixes a missing section, belongs on main
aca17a9
lazy updt
Lock-file churn — fold into next main update
617aab2
nvim: switch to claudecode, add fff.nvim
Portable — belongs on main
5504ce0
tmux F12 toggle for nested sessions (+ fish ssh wrapper)
Portable — belongs on main
837a18a
xps mods
Mixed — see below
Breaking down 837a18a ("xps mods"):
home/dot-local/share/applications/*.desktop (BoxySVG, JetBrains Toolbox, Tidewave, 3 WebApps, Zoom) → host-specific (apps installed only on XPS)
home/dot-local/share/applications/mimeinfo.cache → shouldn't be tracked at all (regenerated by update-desktop-database)
niri/dot-config/systemd/user/default.target.wants/mpd.service, sockets.target.wants/mpd.socket → shouldn't be tracked as symlinks. mpd is used on all machines; the enable step belongs in the base setup (justfile recipe), not as an xps-only artifact.
niri/dot-config/waybar/config.jsonc → toggles thermal-zone: 8 and critical-threshold: 90 → genuinely host-specific (XPS exposes a different sensor index than daisy)
lazy-lock.json updates → lock-file churn
So the truly host-specific surface area on XPS is small: a handful of .desktop shortcuts and one waybar block. Everything else either belongs on main, belongs in the base setup, or shouldn't be in git.
Options (Option A chosen — kept for context)
Option A — Single main, per-host stow package ✅ chosen
Extend the existing GNU Stow workflow with a hosts/<hostname>/ package that gets stowed only on machines with that hostname. The base packages stay machine-agnostic.
This formalizes what's already happening informally — the stow and stow-daisy recipes in the justfile are de-facto per-host overlays, just smushed into the build system instead of the file tree.
Layout:
```
hosts/
xps/
home/dot-local/share/applications/ # XPS-only .desktop shortcuts
niri/dot-config/waybar/ # XPS waybar fragment (DRY split)
dot-config/mise/conf.d/xps.toml # XPS-only mise tools
daisy/
niri/dot-config/waybar/ # daisy waybar fragment (if any)
dot-config/mise/conf.d/daisy.toml # daisy-only mise tools
```
A single stow recipe stows base packages, then runs stow hosts/$(hostname) if that directory exists.
For waybar: split config.jsonc into a base file + per-host fragment, concatenated at setup time (or via waybar's include directive if available — needs verification). Fall back to whole-file override if splitting proves painful.
Pros: one branch, the existing stow model just grows one level, adding a new machine = mkdir hosts/<name>/ and stow.
Cons: a few configs (waybar) don't have native include — need a small build step.
Option B — Single main, runtime detection in configs
Keep one tree, but configs detect host at load time (fish conf.d/host-$(hostname).fish, tmux if-shell, etc.).
Pros: zero per-host bookkeeping at install time. Cons: only works for configs that support conditional/include syntax; clutters base configs for everyone.
Option C — Keep pc/xps as a long-lived branch, codify the workflow
Status quo with rules. Pros: minimal refactor. Cons: pure discipline; this is exactly the workflow that already drifted.
Option D — Migrate to chezmoi
Tracked separately in #4 as a parallel spike. Decision between A and D will happen after that spike runs.
Promote portable commits to main (cherry-pick): ec93a6d (solaar Install), 617aab2 (claudecode + fff.nvim), 5504ce0 (tmux F12 + fish ssh wrapper), and the pt.utf-8.spl spellfile from 837a18a. Roll lock-file updates into the next normal lazy updt on main.
Stop tracking generated/state files and add to .gitignore:
Create hosts/xps/ with the remaining XPS-only bits (.desktop shortcuts + waybar thermal fragment + xps-only mise conf.d/ file).
Refactor the stow recipes in the justfile (see Justfile section) — collapse stow / stow-daisy / stow-check into a single host-aware recipe.
Audit and split mise [tools] table between shared base and per-host conf.d/ files (see mise section).
Delete pc/xps once steps 1–6 are merged on main.
Execution plan — both machines (the runbook)
This is the per-machine runbook. The order matters: Phase 0 (prep on daisy) → Phase 1 (validate on daisy) → Phase 2 (validate on xps) → Phase 3 (merge + cleanup). Don't migrate both machines in parallel — daisy's first apply is also the test of the new tooling, and if anything is broken you want to find out before xps repeats the mistake.
Work happens on a migration branch; main stays untouched until both machines have validated.
Phase 0 — Prep (on daisy, in the dotfiles repo, no machine state changes)
All git/file work — nothing touches ~/.config yet. This produces a migration branch that can be reviewed on GitHub before any machine state changes.
Create migration branch from main
Cherry-pick portable commits from pc/xps: ec93a6d, 617aab2, 5504ce0
Extract just the spellfile from 837a18a (the rest of that commit's contents are split between hosts/xps/ and .gitignore):
```bash
git checkout pc/xps -- lazyvim/dot-config/nvim-light/spell/pt.utf-8.spl
git commit -m "lazyvim: add Portuguese spellfile (from pc/xps)"
```
Refactor niri/dot-config/waybar/config.jsonc to remove the inline temperature block and reference the per-host fragment (mechanism TBD: waybar include if supported; otherwise concat at setup time via a justfile recipe)
Refactor justfile:
Single host-aware stow recipe: stow base packages with -R (restow), then stow hosts/$(hostname)/ if present
Verify no uncommitted changes: cd ~/.dotfiles && git status should be clean
Pull and check out the migration branch:
```bash
cd ~/.dotfiles && git fetch origin && git checkout migration
```
Restow with the new layout (host-aware recipe):
```bash
just stow
```
Apply service state:
```bash
just services-enable
```
Pull any new mise tools (additive, doesn't remove):
```bash
mise install
```
Reload niri-related services and shell:
```bash
just wpaper-reload mako-reload waybar-reload swayidle-reload
exec fish
```
Smoke test:
tmux F12 toggles status bar to red and disables prefix locally
ssh somehost (any host) flips tmux into REMOTE mode for the duration of the session
waybar temperature widget shows daisy's thermal zone (the non-XPS branch)
systemctl --user is-active mpd.service → active
mise ls shows the same tool set as before (plus any new ones from the merged config)
claudecode / fff.nvim work in nvim
just doctor — should be all green
If anything's broken: git checkout main && just stow (old recipe still works pre-merge), restore from tarball if needed
Commit any tweaks discovered during validation; push to migration
Phase 2 — Validate on xps
The order on xps matters because of the dangling-symlink trap. Do this from a TTY (Ctrl+Alt+F2) so a niri/waybar restart mid-stream doesn't lose your terminal.
Verify on pc/xps with no uncommitted changes:
```bash
cd ~/.dotfiles && git status
```
Stash or commit anything important.
CRITICAL: unstow with the OLD package list while the source files for pc/xps are still in the working tree. Skipping this leaves dangling symlinks for mimeinfo.cache and the *.target.wants/ symlinks once the migration branch removes them:
```bash
cd ~/.dotfiles
stow --dotfiles -D home idea git scripts terminal lazyvim vim systemd niri
```
Verify no dotfile-owned dangling symlinks remain in ~/.config:
```bash
find ~/.config ~/.local/share/applications ~/.tmux.conf -xtype l 2>/dev/null | grep dotfiles
```
(No output expected. If any show up, rm them — they're orphans from the old layout.)
Stow with the new host-aware recipe (auto-detects xps):
```bash
just stow
```
Apply service state — mpd should already be enabled but this verifies:
```bash
just services-enable
systemctl --user is-enabled mpd.service mpd.socket
```
Pull xps-only mise tools:
```bash
mise install
```
Cross-check: anything in mise ls that isn't in the post-split files should be either added to conf.d/xps.toml (forgotten) or actively removed via mise uninstall <tool>
Switch back to graphical session (Ctrl+Alt+F1 or restart niri)
Smoke test:
waybar shows XPS thermal zone (thermal-zone: 8, threshold 90)
BoxySVG / JetBrains Toolbox / WebApps / Tidewave appear in launcher (sourced from hosts/xps/)
tmux F12, ssh wrapper, claudecode, fff.nvim all work
mpd active and playing
just doctor — all green
If anything's broken: git checkout pc/xps && stow --dotfiles -S home idea git scripts terminal lazyvim vim systemd niri (and restore tarball if needed)
Phase 3 — Merge and clean up
After both machines have green Phase 1 and Phase 2.
Open PR migration → main on GitHub; review the diff one more time
Squash-merge to main (cleaner history than fast-forward)
On daisy: git fetch && git checkout main && git pull (no working-tree changes — main now matches what was on migration)
On xps: same
Delete pc/xps from origin: gh api -X DELETE repos/rdlu/dotfiles/git/refs/heads/pc/xps
Delete local migration and remote migration on both machines: git branch -d migration && git push origin --delete migration
Update README.md to document the two-machine + per-host overlay model and the new just stow / just services-enable / just update / just doctor recipes
Risk points to keep in mind
The unstow→checkout→stow dance on xps (Phase 2) is the single highest-risk moment. If you skip the unstow on pc/xps first, the source files for mimeinfo.cache and *.target.wants/* symlinks disappear when you check out migration, and stow -D can't clean them up by name → dangling symlinks in ~/.config. Mitigation: the find ~/.config -xtype l check after unstow.
mpd silent disable on xps: removing the tracked *.target.wants/ symlinks without systemctl --user enable would silently disable mpd. just services-enable covers this — don't skip it. Verify with systemctl --user is-enabled mpd.service.
Mid-migration display flicker on xps: wpaperd/waybar/mako/swayidle get restarted as part of stow. Do Phase 2 from a TTY, not inside a niri terminal.
mise current state vs new files: mise install adds, doesn't remove. Run mise ls on each machine before splitting and cross-check after — anything installed but not in the post-split files was forgotten OR should be actively removed.
Sequential, not parallel: don't migrate both machines simultaneously. Daisy's first apply is the test of the new tooling.
Day delay between machines: if days pass between Phase 1 and Phase 2 and fixups land on migration in between, xps must git pullbefore its checkout step (the Phase 2 commands already include the fetch).
TPM clone on fresh-only: if ~/.tmux/plugins/tpm already exists on a machine, the (now gated) clone is a no-op. New machines get a fresh clone.
Pacman + mise overlap is intentional — see Justfile section. Don't try to dedupe.
Justfile improvements (folded in from review)
Per-host divergence already leaking into the justfile
Three near-identical stow recipes (stow, stow-daisy, stow-check) that disagree on package list. Collapse into a single stow HOST=$(hostname) recipe that stows base packages then stow hosts/<HOST>/ if present.
No restow / unstow / adopt recipes — first-install conflicts (real files where stow wants symlinks) have no escape hatch.
Distro coverage (cleanup)
README claims Fedora support but the justfile is Arch-only. Drop Fedora from README, delete setup/fedora-base.fish. WSL is also gone — delete setup/archlinux-wsl2.fish and the gnupg/ directory (which is just the WSL win-gpg-agent-relay.sh setup).
AUR helper standardization
packages recipe currently runs pacman -Sy paru. Keep it as a defensive no-op (already present on CachyOS); standardize every other recipe on paru -S (was yay -S). The user keeps yay for daily interactive use as a separate, optional install-yay recipe.
Pacman + mise overlap is intentional, not a bug
(Correcting an earlier note.)dev-setup installs nodejs npm python3 rustup zig erlang elixir via pacman, AND mise's config.toml pins versions for several of the same tools. This is deliberate two-tier:
Pacman = system-integrity floor (always distro-current, available at /usr/bin/... for anything system-level).
Mise = user-controlled project pin (mise activate shadows pacman in interactive shells).
Both coexist without conflict. The actionable item: ensure dev-setup ends with mise install so the user-pinned versions are bootstrapped on a fresh machine instead of waiting for first interactive use.
Idempotency / re-run safety
git clone .../tpm ~/.tmux/plugins/tpm fails on re-run (gate with test -d ... || …).
chsh -s /usr/bin/fish runs every time — check $SHELL first.
read -p is a bash-ism; recipes inherit sh/the user shell unless set shell := [\"bash\", \"-uc\"] is at the top of the justfile.
Manual edits in packages (reflector.conf, pacman.conf[chaotic-aur] block) could be made idempotent: grep -q '\\[chaotic-aur\\]' /etc/pacman.conf || sudo tee -a ....
Redundant work
stow --dotfiles -S terminal runs in fish-shell, kitty-terminal, and yazi-file-manager. Harmless but noisy. One stow: prereq, or stow at the end, would be cleaner.
Architecture-specific hard-coding
rustup toolchain add stable-x86_64-unknown-linux-gnu — fine for both current machines (both x86_64) but rustup default stable is more portable.
Missing day-2 recipes
update: re-stow, fisher update, ya pkg upgrade, nvim Lazy sync, mise upgrade, paru -Syu. Currently no single command brings an existing machine up to date.
doctor: check that fish/tmux/stow/mise are installed, that key symlinks exist, that the user shell is fish, that expected systemd user services are enabled, that mise tools resolve.
services-enable: consolidate systemctl --user enable calls into one recipe (replaces the tracked *.target.wants/ symlinks).
Small ergonomic wins
Use just's built-in [confirm] attribute on destructive recipes instead of read -p.
Add set shell := [\"bash\", \"-uc\"] and set dotenv-load at the top.
Mise per-host catalog (folded in)
Mise currently manages 30+ tools across cargo/pipx/ubi/native backends, with the config stowed via terminal/dot-config/mise/config.toml — both machines install the same set today. Goal: shared base + per-host overlays.
Mechanism: conf.d/ overlay
mise loads ~/.config/mise/config.toml plus everything in ~/.config/mise/conf.d/*.toml and merges the [tools] tables additively. Layout:
Stow handles the overlay the same way it would for waybar or .desktop files. Each machine ends up with a merged [tools] view; mise install pulls everything new.
Side benefit: conf.d/ also gives a clean place to drop temporary project tools without polluting the shared base.
Catalog audit (one-time, manual — happens during Phase 1/2)
The current [tools] table is one undifferentiated list. Splitting it requires deciding per-tool which file it belongs in. First-pass guesses (user to confirm):
Status / Decisions (resolved)
origin/xps,origin/alt,origin/masterdeleted. Localdanklinuxdeleted (rejected dank niri experiment).pc/xpsretained until migration extracts portable commits.yayseparately as muscle-memory for interactive use; optionalinstall-yayrecipe.*.target.wants/*symlinksservices-enablejustfile recipe tracks intent (what's enabled). Uses the propersystemctl enableAPI.conf.d/per-host overlay — base shared interminal/, host-specific tools inhosts/<host>/dot-config/mise/conf.d/<host>.toml. Tool tables merge additively.Open
Context
pc/xpshas been the working branch on the XPS machine;mainhas continued to receive general updates. They've drifted and need reconciling. Before doing that, we should pick a per-host model so this doesn't keep happening.Target universe: two CachyOS notebooks,
daisy(AMD Ryzen) andxps(Intel i7). No Fedora, no WSL — those paths are obsolete.Current state (snapshot)
3eab9ccmainis 8 commits ahead of the merge basepc/xpsis 5 commits ahead of the merge base21 files changed, 396 insertions(+), 83 deletions(-)Classifying the 5
pc/xpscommitsec93a6d[Install]section so it can be enabledaca17a9617aab25504ce0837a18aBreaking down
837a18a("xps mods"):home/dot-local/share/applications/*.desktop(BoxySVG, JetBrains Toolbox, Tidewave, 3 WebApps, Zoom) → host-specific (apps installed only on XPS)home/dot-local/share/applications/mimeinfo.cache→ shouldn't be tracked at all (regenerated byupdate-desktop-database)home/dot-local/share/applications/mimeapps.list(empty) → noiseniri/dot-config/systemd/user/default.target.wants/mpd.service,sockets.target.wants/mpd.socket→ shouldn't be tracked as symlinks. mpd is used on all machines; theenablestep belongs in the base setup (justfile recipe), not as an xps-only artifact.lazyvim/.../nvim-light/spell/pt.utf-8.spl→ portable (Portuguese spellfile, useful anywhere)niri/dot-config/waybar/config.jsonc→ togglesthermal-zone: 8andcritical-threshold: 90→ genuinely host-specific (XPS exposes a different sensor index than daisy)lazy-lock.jsonupdates → lock-file churnSo the truly host-specific surface area on XPS is small: a handful of
.desktopshortcuts and one waybar block. Everything else either belongs onmain, belongs in the base setup, or shouldn't be in git.Options (Option A chosen — kept for context)
Option A — Single
main, per-host stow package ✅ chosenExtend the existing GNU Stow workflow with a
hosts/<hostname>/package that gets stowed only on machines with that hostname. The base packages stay machine-agnostic.This formalizes what's already happening informally — the
stowandstow-daisyrecipes in the justfile are de-facto per-host overlays, just smushed into the build system instead of the file tree.Layout:
```
hosts/
xps/
home/dot-local/share/applications/ # XPS-only .desktop shortcuts
niri/dot-config/waybar/ # XPS waybar fragment (DRY split)
dot-config/mise/conf.d/xps.toml # XPS-only mise tools
daisy/
niri/dot-config/waybar/ # daisy waybar fragment (if any)
dot-config/mise/conf.d/daisy.toml # daisy-only mise tools
```
A single
stowrecipe stows base packages, then runsstow hosts/$(hostname)if that directory exists.For waybar: split
config.jsoncinto a base file + per-host fragment, concatenated at setup time (or via waybar'sincludedirective if available — needs verification). Fall back to whole-file override if splitting proves painful.Pros: one branch, the existing stow model just grows one level, adding a new machine =
mkdir hosts/<name>/and stow.Cons: a few configs (waybar) don't have native include — need a small build step.
Option B — Single
main, runtime detection in configsKeep one tree, but configs detect host at load time (fish
conf.d/host-$(hostname).fish, tmuxif-shell, etc.).Pros: zero per-host bookkeeping at install time. Cons: only works for configs that support conditional/include syntax; clutters base configs for everyone.
Option C — Keep
pc/xpsas a long-lived branch, codify the workflowStatus quo with rules. Pros: minimal refactor. Cons: pure discipline; this is exactly the workflow that already drifted.
Option D — Migrate to
chezmoiTracked separately in #4 as a parallel spike. Decision between A and D will happen after that spike runs.
Migration plan (Option A) — what
High-level: cherry-pick portable commits, untrack generated files, formalize host overlay, refactor justfile, then validate per-machine.
main(cherry-pick):ec93a6d(solaar Install),617aab2(claudecode + fff.nvim),5504ce0(tmux F12 + fish ssh wrapper), and thept.utf-8.splspellfile from837a18a. Roll lock-file updates into the next normallazy updton main..gitignore:home/dot-local/share/applications/mimeinfo.cache**/systemd/user/*.target.wants/mimeapps.listservices-enablejustfile recipe — declarative "what's enabled" usingsystemctl --user enable --now mpd.socket mpd.service syncthing.service solaar.service .... Idempotent. Replaces the tracked*.target.wants/symlinks.hosts/xps/with the remaining XPS-only bits (.desktopshortcuts + waybar thermal fragment + xps-only miseconf.d/file).stow/stow-daisy/stow-checkinto a single host-aware recipe.[tools]table between shared base and per-hostconf.d/files (see mise section).pc/xpsonce steps 1–6 are merged on main.Execution plan — both machines (the runbook)
This is the per-machine runbook. The order matters: Phase 0 (prep on daisy) → Phase 1 (validate on daisy) → Phase 2 (validate on xps) → Phase 3 (merge + cleanup). Don't migrate both machines in parallel — daisy's first apply is also the test of the new tooling, and if anything is broken you want to find out before xps repeats the mistake.
Work happens on a
migrationbranch;mainstays untouched until both machines have validated.Phase 0 — Prep (on daisy, in the dotfiles repo, no machine state changes)
All git/file work — nothing touches
~/.configyet. This produces amigrationbranch that can be reviewed on GitHub before any machine state changes.migrationbranch frommainpc/xps:ec93a6d,617aab2,5504ce0837a18a(the rest of that commit's contents are split betweenhosts/xps/and.gitignore):```bash
git checkout pc/xps -- lazyvim/dot-config/nvim-light/spell/pt.utf-8.spl
git commit -m "lazyvim: add Portuguese spellfile (from pc/xps)"
```
.gitignoreentries for generated/state files:```
home/dot-local/share/applications/mimeinfo.cache
home/dot-local/share/applications/mimeapps.list
**/systemd/user/*.target.wants/
```
hosts/xps/skeleton:hosts/xps/home/dot-local/share/applications/— relocateWebApp-OctoChat4985.desktop,WebApp-WeatherMerryChrome4325.desktop,WebApp-WeatherMerrySky1749.desktop,com.boxy_svg.BoxySVG.desktop,jetbrains-toolbox.desktop,tidewave.desktop,Zoom-*.desktop(sourced frompc/xps)hosts/xps/niri/dot-config/waybar/temperature.jsonc— XPS thermal fragment (thermal-zone: 8,critical-threshold: 90)hosts/xps/dot-config/mise/conf.d/xps.toml— empty placeholder; populated during Phase 2 audithosts/daisy/skeleton:hosts/daisy/niri/dot-config/waybar/temperature.jsonc— daisy thermal fragment (critical-threshold: 80)hosts/daisy/dot-config/mise/conf.d/daisy.toml— empty placeholderniri/dot-config/waybar/config.jsoncto remove the inline temperature block and reference the per-host fragment (mechanism TBD: waybarincludeif supported; otherwise concat at setup time via a justfile recipe)justfile:stowrecipe: stow base packages with-R(restow), thenstow hosts/$(hostname)/if presentservices-enable:systemctl --user enable --now mpd.socket mpd.service syncthing.service solaar.service swayidle.service waybar.service wpaperd.service mako.serviceupdate:paru -Syu,mise upgrade,fisher update,ya pkg upgrade,nvim --headless \"+Lazy! sync\" +qadoctor: check fish/tmux/stow/mise installed,$SHELLis fish, expected services enabled,mise lsresolves, key symlinks liveset shell := [\"bash\", \"-uc\"]at topyay -S→paru -Sgit clone .../tpmon[ -d ~/.tmux/plugins/tpm ], gatechshon$SHELLcheckfish-shell/kitty-terminal/yazi-file-manager)setup/fedora-base.fish,setup/archlinux-wsl2.fish, and thegnupg/directorymise installtodev-setupmigrationto originmainlooks right; no surprisesPhase 1 — Validate on daisy
Daisy first because instant feedback, and current state is closer to
mainthanpc/xpsis.```bash
tar czf ~/dotfiles-backup-$(date +%F-%H%M).tgz ~/.config ~/.tmux.conf ~/.local/share/applications ~/.tmux 2>/dev/null
```
cd ~/.dotfiles && git statusshould be clean```bash
cd ~/.dotfiles && git fetch origin && git checkout migration
```
```bash
just stow
```
```bash
just services-enable
```
```bash
mise install
```
```bash
just wpaper-reload mako-reload waybar-reload swayidle-reload
exec fish
```
ssh somehost(any host) flips tmux into REMOTE mode for the duration of the sessionsystemctl --user is-active mpd.service→activemise lsshows the same tool set as before (plus any new ones from the merged config)just doctor— should be all greengit checkout main && just stow(old recipe still works pre-merge), restore from tarball if neededmigrationPhase 2 — Validate on xps
The order on xps matters because of the dangling-symlink trap. Do this from a TTY (
Ctrl+Alt+F2) so a niri/waybar restart mid-stream doesn't lose your terminal.Ctrl+Alt+F2) and log in```bash
tar czf ~/dotfiles-backup-$(date +%F-%H%M).tgz ~/.config ~/.tmux.conf ~/.local/share/applications ~/.tmux 2>/dev/null
```
pc/xpswith no uncommitted changes:```bash
cd ~/.dotfiles && git status
```
Stash or commit anything important.
pc/xpsare still in the working tree. Skipping this leaves dangling symlinks formimeinfo.cacheand the*.target.wants/symlinks once the migration branch removes them:```bash
cd ~/.dotfiles
stow --dotfiles -D home idea git scripts terminal lazyvim vim systemd niri
```
~/.config:```bash
find ~/.config ~/.local/share/applications ~/.tmux.conf -xtype l 2>/dev/null | grep dotfiles
```
(No output expected. If any show up,
rmthem — they're orphans from the old layout.)```bash
git fetch origin && git checkout migration
```
xps):```bash
just stow
```
```bash
just services-enable
systemctl --user is-enabled mpd.service mpd.socket
```
```bash
mise install
```
mise lsthat isn't in the post-split files should be either added toconf.d/xps.toml(forgotten) or actively removed viamise uninstall <tool>Ctrl+Alt+F1or restart niri)thermal-zone: 8, threshold 90)hosts/xps/)just doctor— all greengit checkout pc/xps && stow --dotfiles -S home idea git scripts terminal lazyvim vim systemd niri(and restore tarball if needed)Phase 3 — Merge and clean up
After both machines have green Phase 1 and Phase 2.
migration→mainon GitHub; review the diff one more timemain(cleaner history than fast-forward)git fetch && git checkout main && git pull(no working-tree changes — main now matches what was onmigration)pc/xpsfrom origin:gh api -X DELETE repos/rdlu/dotfiles/git/refs/heads/pc/xpsmigrationand remotemigrationon both machines:git branch -d migration && git push origin --delete migrationREADME.mdto document the two-machine + per-host overlay model and the newjust stow/just services-enable/just update/just doctorrecipesRisk points to keep in mind
pc/xpsfirst, the source files formimeinfo.cacheand*.target.wants/*symlinks disappear when you check outmigration, andstow -Dcan't clean them up by name → dangling symlinks in~/.config. Mitigation: thefind ~/.config -xtype lcheck after unstow.*.target.wants/symlinks withoutsystemctl --user enablewould silently disable mpd.just services-enablecovers this — don't skip it. Verify withsystemctl --user is-enabled mpd.service.wpaperd/waybar/mako/swayidleget restarted as part of stow. Do Phase 2 from a TTY, not inside a niri terminal.mise installadds, doesn't remove. Runmise lson each machine before splitting and cross-check after — anything installed but not in the post-split files was forgotten OR should be actively removed.migrationin between, xps mustgit pullbefore its checkout step (the Phase 2 commands already include the fetch).~/.tmux/plugins/tpmalready exists on a machine, the (now gated) clone is a no-op. New machines get a fresh clone.Justfile improvements (folded in from review)
Per-host divergence already leaking into the justfile
stow,stow-daisy,stow-check) that disagree on package list. Collapse into a singlestow HOST=$(hostname)recipe that stows base packages thenstow hosts/<HOST>/if present.restow/unstow/adoptrecipes — first-install conflicts (real files where stow wants symlinks) have no escape hatch.Distro coverage (cleanup)
setup/fedora-base.fish. WSL is also gone — deletesetup/archlinux-wsl2.fishand thegnupg/directory (which is just the WSLwin-gpg-agent-relay.shsetup).AUR helper standardization
packagesrecipe currently runspacman -Sy paru. Keep it as a defensive no-op (already present on CachyOS); standardize every other recipe onparu -S(wasyay -S). The user keepsyayfor daily interactive use as a separate, optionalinstall-yayrecipe.Pacman + mise overlap is intentional, not a bug
(Correcting an earlier note.)
dev-setupinstallsnodejs npm python3 rustup zig erlang elixirvia pacman, AND mise'sconfig.tomlpins versions for several of the same tools. This is deliberate two-tier:/usr/bin/...for anything system-level).Both coexist without conflict. The actionable item: ensure
dev-setupends withmise installso the user-pinned versions are bootstrapped on a fresh machine instead of waiting for first interactive use.Idempotency / re-run safety
git clone .../tpm ~/.tmux/plugins/tpmfails on re-run (gate withtest -d ... || …).chsh -s /usr/bin/fishruns every time — check$SHELLfirst.read -pis a bash-ism; recipes inheritsh/the user shell unlessset shell := [\"bash\", \"-uc\"]is at the top of the justfile.packages(reflector.conf,pacman.conf[chaotic-aur]block) could be made idempotent:grep -q '\\[chaotic-aur\\]' /etc/pacman.conf || sudo tee -a ....Redundant work
stow --dotfiles -S terminalruns infish-shell,kitty-terminal, andyazi-file-manager. Harmless but noisy. Onestow:prereq, or stow at the end, would be cleaner.Architecture-specific hard-coding
rustup toolchain add stable-x86_64-unknown-linux-gnu— fine for both current machines (both x86_64) butrustup default stableis more portable.Missing day-2 recipes
update: re-stow,fisher update,ya pkg upgrade, nvimLazy sync,mise upgrade,paru -Syu. Currently no single command brings an existing machine up to date.doctor: check that fish/tmux/stow/mise are installed, that key symlinks exist, that the user shell is fish, that expected systemd user services are enabled, that mise tools resolve.services-enable: consolidatesystemctl --user enablecalls into one recipe (replaces the tracked*.target.wants/symlinks).Small ergonomic wins
[confirm]attribute on destructive recipes instead ofread -p.set shell := [\"bash\", \"-uc\"]andset dotenv-loadat the top.Mise per-host catalog (folded in)
Mise currently manages 30+ tools across cargo/pipx/ubi/native backends, with the config stowed via
terminal/dot-config/mise/config.toml— both machines install the same set today. Goal: shared base + per-host overlays.Mechanism:
conf.d/overlaymise loads
~/.config/mise/config.tomlplus everything in~/.config/mise/conf.d/*.tomland merges the[tools]tables additively. Layout:```
terminal/dot-config/mise/config.toml # shared base — cross-machine tools
hosts/xps/dot-config/mise/conf.d/xps.toml # xps-only tools
hosts/daisy/dot-config/mise/conf.d/daisy.toml # daisy-only tools
```
Stow handles the overlay the same way it would for waybar or
.desktopfiles. Each machine ends up with a merged[tools]view;mise installpulls everything new.Side benefit:
conf.d/also gives a clean place to drop temporary project tools without polluting the shared base.Catalog audit (one-time, manual — happens during Phase 1/2)
The current
[tools]table is one undifferentiated list. Splitting it requires deciding per-tool which file it belongs in. First-pass guesses (user to confirm):erlang,elixir,ruby,zig,gleam,python,pipx:llm,pipx:xxh-xxh,cargo:bottom,cargo:jaq,cargo:jnv,cargo:jj-cli,cargo:lazyjj,cargo:scooter,cargo:monolith,cargo:zellij,lazydocker,ubi:duckdb/duckdb,ubi:jesseduffield/lazydocker,pipx:epy-readerpipx:aider-chat,pipx:playwright,pipx:posting,pipx:pocket-tts,cargo:probe-rs-tools,cargo:rainfrog,cargo:gittype,cargo:ttyper,cargo:xleakWhy not deduplicate
erlang/elixir/zigbetween pacman and mise? Because the dual install is intentional (see Justfile section).Alternatives considered
MISE_PROFILE=$(hostname)— works, but needs an env var set everywhere andmise.<profile>.tomlnaming is less obvious thanconf.d/.pc/xpswould essentially be doing if mise diverged. Don't.