Stow & Dotfiles Patterns

GNU Stow and dotfiles management patterns I’ve actually used. Every entry has a date and context.

2026-04-02: Stow Selective Deployment (37 of 44 Packages)

Problem: Not all stow packages apply to every machine — some are machine-specific (GPU config, hardware-specific settings). Blindly stowing all 44 packages causes conflicts.

Context: P16g deployment. dots-quantum has 44 packages, some Razer-specific. Private packages (gpg, secrets, hosts) are not in git and must be rsync’d first.

The Fix:

# Remove default shell configs that conflict with stow
rm -f ~/.bashrc ~/.bash_profile ~/.zshrc
# Stow Tier 1 (essential — shell, desktop, editor, tools)
cd ~/atelier/_projects/personal/dots-quantum
stow -t ~ \
    zsh bash shell git \
    hyprland waybar wofi mako \
    kitty oh-my-posh \
    bin share \
    btop fastfetch fzf fd ripgrep \
    claude
# Stow Tier 2 (applications)
stow -t ~ \
    tmux vim lazygit \
    vscodium zathura thunar \
    libvirt ghostty \
    gpg aider opencode
# Private packages — rsync from existing machine first (not in git)
rsync -avz razer:~/dots-quantum/gpg/ ~/dots-quantum/gpg/
rsync -avz razer:~/dots-quantum/secrets/ ~/dots-quantum/secrets/
stow -t ~ gpg secrets

Rule: Not all stow packages are git-tracked. Private packages (gpg, hosts, secrets) must be rsync’d from an existing machine before stowing. Stow in tiers: essentials first (shell, desktop), applications second. Remove default dotfiles (~/.bashrc, ~/.zshrc) before stowing — stow can’t overwrite real files with symlinks.

Worklog: WRKLOG-2026-04-02


Problem: NVIDIA environment variables differ between machines (RTX 4090 on Razer vs RTX 5090 on P16g). A single stowed config breaks one machine.

Context: P16g and Razer both run Hyprland but need different GPU configurations for env-gpu.conf.

The Fix:

# Directory structure in dots-quantum
# hyprland/.config/hypr/hosts/razer/env-gpu.conf   (RTX 4090 settings)
# hyprland/.config/hypr/hosts/p16g/env-gpu.conf     (RTX 5090 settings)
# Per-host symlink (not managed by stow — gitignored)
ln -sf hosts/p16g/env-gpu.conf ~/.config/hypr/env-gpu.conf
# Verify
ls -la ~/.config/hypr/env-gpu.conf

Rule: Per-host config files go in hosts/{hostname}/ within the stow package. Create a gitignored symlink on each machine pointing to the host-specific file. Stow doesn’t manage this symlink — it’s a manual, machine-specific step.

Worklog: WRKLOG-2026-04-02


2026-04-02: NVIM_APPNAME for Multiple Neovim Configs

Problem: Need both domus-nvim and instrumentum-nvim configurations on the same machine without conflicts. Default Neovim only supports one config at ~/.config/nvim/.

Context: P16g deployment, multiple Neovim configs for different purposes (personal editing vs infrastructure tooling).

The Fix:

# Clone config repo
git clone git@github.com:EvanusModestus/domus-nvim.git ~/atelier/_projects/personal/domus-nvim
# Symlink to match NVIM_APPNAME (NOT to ~/.config/nvim)
ln -sf ~/atelier/_projects/personal/domus-nvim ~/.config/nvim-domus
# dots-quantum .zshrc exports globally:
#   export NVIM_APPNAME="nvim-domus"
# So `nvim` always uses ~/.config/nvim-domus/

# Per-invocation aliases for other configs:
alias dvim='NVIM_APPNAME=nvim-domus nvim'
alias ivim='NVIM_APPNAME=nvim-instrumentum nvim'
# Verify
echo "NVIM_APPNAME: $NVIM_APPNAME"
ls -la ~/.config/nvim-domus

Rule: NVIM_APPNAME selects the config directory under ~/.config/. Symlink your repo to ~/.config/{appname}. Data directory follows: ~/.local/share/{appname}/. Do NOT symlink to ~/.config/nvim if NVIM_APPNAME is set — Neovim won’t look there.

Worklog: WRKLOG-2026-04-02


2026-04-02: SSH Config Decrypt + Stow Sequence

Problem: SSH config is age-encrypted in dots-quantum. Must decrypt before stowing, otherwise stow creates a symlink to the encrypted .age file.

Context: P16g deployment, age keys available after Phase 7 rsync. SSH config contains sensitive internal hostnames and IPs.

The Fix:

# Decrypt SSH config (age keys must be available from rsync)
cd ~/atelier/_projects/personal/dots-quantum
age -d -i ~/.age/identities/personal.key ssh/.ssh/config.age >| ssh/.ssh/config
# Stow SSH package (creates symlink to plaintext config)
stow -t ~ ssh
# Verify config is symlinked
ls -la ~/.ssh/config

Rule: Decrypt before stow, not after. The stow target must be the plaintext file. The >| operator forces overwrite without prompting (useful when re-decrypting). The plaintext ssh/.ssh/config is gitignored — only the .age file is tracked.

Worklog: WRKLOG-2026-04-02


2026-04-02: Git SSH over Port 443 (VLAN Port Restriction)

Problem: git clone via SSH fails — port 22 is blocked on the iPSK VLAN (DOMUS-IoT). GitHub supports SSH over port 443 via ssh.github.com.

Context: P16g deployment, on iPSK VLAN before EAP-TLS migration. Need to clone repos before SSH config is stowed.

The Fix:

# Test GitHub — port 443, explicit user=git, bypass local SSH config
ssh -F /dev/null -i ~/.ssh/id_ed25519_github -T -p 443 -l git ssh.github.com
# Clone using SSH over port 443 (ssh:// URL format required for non-standard ports)
GIT_SSH_COMMAND="ssh -F /dev/null -i ~/.ssh/id_ed25519_github -p 443 -l git" \
    git clone ssh://ssh.github.com:443/EvanusModestus/dots-quantum.git \
    ~/atelier/_projects/personal/dots-quantum

Rule: When port 22 is blocked, use ssh.github.com on port 443. The ssh:// URL format with :443 is required (the git@github.com:user/repo.git syntax doesn’t support port specification). -F /dev/null bypasses SSH config. -l git is mandatory — GitHub rejects your local username.

Worklog: WRKLOG-2026-04-02