Skip to content

Restructure repo: move symlinked configs into a home-mirror directory (convention over configuration) #7

Description

@zimakki

Problem

All ~20 symlinked config files live in the repo root, mixed in with docs, scripts, and meta files (README.md, MIGRATION.md, BrewFile, skills, etc.). Every new tool adds another root file and a hand-maintained line in the LINKS manifest in setup_sim_links.zsh. The root gets noisier over time and there are two sources of truth for "where does this file go" (its location + its manifest entry).

Research: standard approaches

  1. Grouped config/<tool>/ dir, keep manifest — cleaner root, but the manifest still grows with every tool. Half the win.
  2. Home-mirror layout (GNU Stow convention)chosen — files live under home/ at paths mirroring their real destination (home/.config/starship.toml~/.config/starship.toml). The symlink script derives destinations from paths; no manifest for the normal case. This is the classic, widely-recommended dotfiles pattern.
  3. Adopt stow/chezmoi/dotbot — rejected. Big migration, new tooling; our custom script's per-file backup behavior is nicer than stow's, and stow's directory folding can surprise (e.g. the television/ directory link). Repo + skills already handle per-host config and installs.

Agreed approach

  • New top-level home/ directory mirroring $HOME:
    home/.zshenv
    home/.zshrc
    home/.gitconfig
    home/.gitignore_global
    home/.claude/settings.json
    home/.config/starship.toml
    home/.config/atuin/config.toml
    home/.config/atuin/themes/catppuccin-mocha-mauve.toml
    home/.config/karabiner/karabiner.json
    home/.config/television/           (directory link — see note below)
    home/.config/ghostty/config
    home/.config/bat/config
    home/.config/hunk/config.toml
    home/.warp/keybindings.yaml
    home/.warp/themes/catppuccin_mocha.yml
    home/.zsh/catppuccin_mocha-zsh-syntax-highlighting.zsh
    home/Brewfile                       (or keep at root — see Decisions)
    
  • Rewrite setup_sim_links.zsh: walk home/ (files, plus an explicit list of directory-linked paths like television), compute dest = $HOME/<relative path>, keep the existing backup-to-.bak behavior.
  • Small OVERRIDES map for the irregular cases — the escape hatch that makes pure convention workable:
    • lazygit_config.yml$(lazygit -cd)/config.yml (destination computed at runtime)
    • anything we decide to keep at repo root (see below)
  • Non-symlinked repo files (README.md, CLAUDE.md, MIGRATION.md, docs/, scripts/, hosts/, macos_defaults.sh, skills) stay where they are.

Decisions to confirm during implementation

  • BrewFile + mise_config.toml: recommend keeping at repo root with override entries, since they're the install ledger that CLAUDE.md and all three skills reference constantly; moving them churns many references for little gain.
  • Root cleanup candidates spotted while auditing: favicon.ico/favicon.png, droid_test/, raycast.rayconfig (not in LINKS), Brewfile.lock.json — decide keep/move/delete as part of this work (or via /cleanup-report).

Migration plan

  1. Branch off master.
  2. git mv each symlinked file/dir to its home/ path (preserves history).
  3. Rewrite setup_sim_links.zsh (convention walker + OVERRIDES + directory-link list). Keep the same UX: idempotent, .bak backups, SKIP on missing source.
  4. Run it. Verify every link: for f in ~/.zshrc ~/.gitconfig ...; do readlink $f; done — all should point into home/. Old links get replaced automatically since the script backs up existing dests.
  5. Open a new shell; smoke-test zsh, starship, atuin, git, lazygit, bat.
  6. Grep the repo for old paths (grep -rn "zshrc\b\|starship.toml" --include='*.md' --include='*.zsh' .) and fix references in CLAUDE.md, MIGRATION.md, README.md, docs/conventions/shell-config.md.
  7. Update skills (below), commit, PR.

Skill updates required

  • .claude/skills/install-app/SKILL.md — replace the "add file to repo root + add LINKS entry" instructions (~lines 61–64) with: "place the config at home/<its real path relative to $HOME> and re-run ./setup_sim_links.zsh; only touch OVERRIDES for dynamic destinations." Update the zsh-syntax-highlighting path example.
  • .claude/skills/uninstall-app/SKILL.md — the grep sweep (line 19) and step 2 (~lines 48–49): instead of "remove the LINKS entry", it's "delete the file from home/ (and any OVERRIDES entry), remove the dangling symlink in $HOME."
  • .claude/skills/cleanup-report/SKILL.md — dangling-symlink audit (~lines 72–74): derive expected destinations from the home/ tree instead of parsing LINKS.
  • CLAUDE.md — update the symlink-management sentence to name the new convention.

Definition of done

  • Repo root contains no tool config files; all symlinked configs live under home/.
  • setup_sim_links.zsh needs no edits when adding a normally-located config — drop the file in home/ and re-run.
  • All existing symlinks resolve to the new locations; shell + key tools verified working.
  • All three skills, CLAUDE.md, and docs reference the new structure; no stale mentions of the old root paths or LINKS array.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions