Files
dotfiles/.config/dot/.claude/tasks/0006-setup-dispatcher-and-folders-core.md
alexion 1fd8e7e773 dotcli: add dot setup folders (XDG short-name migration)
Adds a dot setup subcommand family (idempotent, re-runnable machine-setup
tasks) with a folders task that brings the 8 standard XDG user
directories under a fixed short-name convention (Desktop -> .desktop,
Documents -> doc, Downloads -> dwn, Music -> mus, Pictures -> pic,
Videos -> vid, Templates/Public -> .ignoreme), hardcoded rather than read
from ~/.config/user-dirs.dirs -- that file is a separate, manually
tracked dotfile whose values can drift or go stale, and the migration
must not depend on it being correct. The nested Pictures/Screenshots
folder is renamed to pic/screenshots in the same pass.

Content left behind in a legacy full-named folder by a fresh XDG-defaults
install -- empty or not -- is merged into its short-named replacement.
A same-named collision between a legacy folder and its target is never
overwritten: it is skipped, reported, and the legacy folder is left in
place rather than deleted while something in it could not be merged.
--dry-run previews what would move/skip without touching the filesystem.
xdg-user-dirs-update runs once afterward to notify running apps/portals.
2026-07-06 16:31:35 -04:00

5.0 KiB

spec
spec
dot-setup-folders

What to build

A new dot setup subcommand family, following the project's existing nested-subcommand dispatch convention. Bare dot setup (no arguments) runs every machine-setup task unconditionally; dot setup <task> runs just that one task. The only task that exists yet is folders.

dot setup folders brings the 8 standard XDG user directories under the project's short-name convention (Desktop→.desktop, Documents→doc, Downloads→dwn, Music→mus, Pictures→pic, Videos→vid, Templates and Public both →.ignoreme). The desired short names live in a tracked user-dirs.dirs file (a plain dotfile, not generated from a table each run). A separate small hardcoded table maps each of the 8 standard XDG categories to its legacy full-named folder, used only to locate content an XDG-defaults install would have left behind, and merge it into the already-tracked short-named target.

This slice covers the core happy path: a legacy folder found empty (strictly: no entries at all, including dotfiles/metadata) is merged into its short-named target silently, with no confirmation needed. As part of the same Pictures→pic pass, a nested Screenshots folder is renamed to lowercase screenshots, landing at pic/screenshots. After all folder moves complete, run xdg-user-dirs-update (no arguments) once to notify running apps/portals. ~/wrk gets no XDG variable of its own and is out of scope for any mapping; the existing ad hoc ~/Projects folder is left alone.

Non-empty legacy folders and filename collisions are out of scope for this slice (covered by later tasks) — for now it's acceptable for a non-empty legacy folder to be handled in whatever minimal way unblocks the empty-folder path (e.g. left untouched with a message), since the confirmation gate and collision safety are built out next.

Wire the new command into the project's standard subcommand checklist: a _dot_setup_usage help function reachable via dot setup help (and dot setup folders help for the nested task), the completions/help-glob duplication point, and a README command-table row.

Acceptance criteria

  • dot setup folders on a fresh scratch $HOME (all 8 legacy folders present and empty) renames them to their short-name targets per the mapping table, including Pictures/Screenshots→pic/screenshots, and leaves the tracked user-dirs.dirs short names in place
  • The fake xdg-user-dirs-update (PATH-prepended, logging its invocation per the project's existing fake-sudo/fake-pacman testing pattern) is invoked exactly once after a successful migration
  • Bare dot setup on a fresh scratch $HOME runs the folders task as part of running everything
  • dot setup folders help and dot setup help print usage and make no filesystem changes
  • Re-running dot setup folders after a clean migration is a no-op (idempotent)
  • ~/.github/README.md has a command-table row for dot setup (and its folders task) with paths relative to $HOME
  • ~/.config/dot/tests/dot.fish covers the above cases and fishtape ~/.config/dot/tests/dot.fish passes

Implementation Notes

  • The desired short names for dot setup folders are read directly from the tracked ~/.config/user-dirs.dirs (parsed via grep/string match, not sourced as shell), per the parent spec's decision that this file is the single source of truth. This machine's real user-dirs.dirs was deliberately left untouched/untracked and no live migration was run against this machine's actual home directory — the user chose "code + tests only" scope for this task (a real rename of ~/Desktop, ~/Documents, etc. is a separate, explicit action to take later), so only the scratch-$HOME fishtape fixtures exercise the short-name user-dirs.dirs content. Tracking the real file and running the real migration remains open.
  • During /review-uncommitted, the spec-fidelity pass caught a real bug: the nested Pictures/Screenshots→pic/screenshots move ran unconditionally, before checking whether Pictures held other, unrelated content — so a Pictures folder with both Screenshots/ and some other file got partially mutated (Screenshots pulled out) while still being reported as "left in place." Fixed by gating the Screenshots move on the rest of the folder being empty too; added a regression test for this case ("Screenshots is not peeled off... when Pictures still has other content").
  • Completions (~/.config/fish/completions/dot.fish) got a dot setup block mirroring dot kde's per-subcommand completion entries, even though the task's required "completions/help-glob duplication point" is already satisfied automatically by the existing generic directory glob (no changes were needed there for dot setup/dot help to discover the new nested command). The added completions are a small polish addition beyond the strict letter of the acceptance criteria, consistent with the existing kde subcommand's treatment.