Skip to content

Reshape dotfiles: layout cleanup, XDG, security tooling#1

Merged
davidham merged 17 commits into
mainfrom
feature/reshape
May 20, 2026
Merged

Reshape dotfiles: layout cleanup, XDG, security tooling#1
davidham merged 17 commits into
mainfrom
feature/reshape

Conversation

@davidham

Copy link
Copy Markdown
Owner

Summary

  • Branch hygiene: master fast-forwarded to dotbot, renamed to main, default branch switched on GitHub. Old branches deleted. Upstream mathiasbynens remote removed.
  • Drop upstream cruft: bash files (.bash_profile/.bashrc/.bash_prompt), bootstrap.sh, brew.sh, .macos, .vim/, .vimrc, bin/subl, init/ (Sublime + iTerm2 + Terminal.app), upstream README/LICENSE.
  • New layout: home/ for files symlinked into $HOME, xdg/ for files under ~/.config/, shell/ for zsh modules sourced by zshrc. Directory name = symlink target.
  • shell/env.zsh: merges .exports + .path. Fixes GOPATH (was $HOME/go/bin, now $HOME/go). Fixes PATH bugs. Drops dead entries (Intel-era python, ansible, libxml/libxslt, easyrsa, NVM, ANSIBLE_PYTHON_INTERPRETER, HISTCONTROL, PKG_CONFIG_PATH).
  • Aliases pruned: drops broken (urlencode), dead (lwp-request loop, chrome, jsc), dangerous (update with sudo), and one-off macOS commands. Keeps navigation, ls/grep colors, docker/k8s/terraform/AWS/gcom/bazel.
  • Functions pruned: drops gitio (URL service shut down), server/json (Python 2), phpserver, etc. Replaces initConfigVar (which ran kubectl synchronously at every shell start) with a side-effect-free load_kubeconfigs. Keeps clean_branches per user preference.
  • fzf integration: new shell/fzf.zsh. Ctrl-R history, Ctrl-T file picker. Degrades cleanly when fzf is absent.
  • XDG adoption:
    • Histories: zsh/less/psql/python/node REPL all under $XDG_STATE_HOME.
    • zcompdump moves to $XDG_CACHE_HOME/zsh/zcompdump.
    • gitconfig/ignore/attributes move to ~/.config/git/ (native git XDG support, drops explicit excludesfile/attributesfile).
    • npmrc moves to ~/.config/npm/npmrc via NPM_CONFIG_USERCONFIG.
  • $HOME imports: nvim (LazyVim, full dir), ghostty, zellij, direnv, yarnrc.yml -- all now symlinked back from the repo.
  • Security + linting:
    • .pre-commit-config.yaml orchestrates gitleaks (secret scanning), shellcheck (lint), shfmt (format), and standard hygiene hooks.
    • .gitleaks.toml allowlists *.example and *.tmpl template files.
    • .shellcheckrc disables zsh-only false-positives and dotfile-common noise.
    • scripts/lint wraps pre-commit run --all-files.
    • GitHub Action mirrors the local pre-commit run plus a deeper full-history gitleaks scan.
  • README: replaced with a focused doc covering layout, bootstrap, required + optional tools, per-machine overrides, lint, and secrets convention.

Test plan

  • Phase 0 gitleaks audit on full history -- 711 commits scanned, no leaks.
  • master -> dotbot FF, renamed to main, default branch updated on GitHub, master and dotbot remotes deleted.
  • Each commit on the branch leaves the shell startable (`env -i HOME=$HOME zsh -i -c true` exits cleanly).
  • PATH, HISTFILE, GOPATH, ASDF_DIR resolve correctly in a clean-env shell.
  • `./install` runs without errors; symlinks land at expected paths.
  • `./scripts/lint` passes (pre-commit run --all-files).
  • CI passes on this PR (will know after push).
  • Post-merge: rerun `./install` to clean any residual orphaned symlinks in $HOME.

Notes

  • The two .gitleaks audits ran clean.
  • nvim is symlinked as a directory; lazy-lock.json updates will appear in `git status` whenever lazy.nvim updates plugins, and should be committed as needed.
  • Three fixup commits in the history address review feedback inline rather than amending atomic commits (per CLAUDE.md preference).

🤖 Generated with Claude Code

davidham added 17 commits May 19, 2026 17:18
Drops bash-era files (.bash_profile/.bashrc/.bash_prompt), the upstream
bootstrap.sh and brew.sh, run-once macOS defaults (.macos, .osx), Sublime
and Terminal.app artifacts (bin/subl, init/, .vim/, .vimrc), various
unmaintained dotfiles (.curlrc, .wgetrc, .inputrc, .screenrc, .gvimrc,
.gdbinit, .hgignore, .hushlogin), and the upstream README/LICENSE. None
were linked by Dotbot or used by the user.
home/ holds files symlinked directly into $HOME. xdg/ holds files
symlinked under $XDG_CONFIG_HOME (~/.config). shell/ holds zsh modules
sourced by home/zshrc.zsh; they are not symlinked individually.

This commit only moves files; content changes happen in later commits.
.exports and .path remain at repo root transitionally and are sourced
from zshrc.zsh until Task 7 merges them into shell/env.zsh.

install.conf.yaml is rewritten to match the new layout. Existing
$HOME symlinks (~/.aliases, ~/.path, etc.) become orphans that
Dotbot's clean action will remove on next install.

home/zshrc.zsh updates the original .zshrc with: (1) module loader for
shell/*.zsh files, (2) conditional guards for apollo-cli/direnv/docker
completions/gcloud SDK so the shell works on machines without them,
(3) replaces hardcoded /Users/davidham/ with $HOME for portability,
(4) removes duplicate compinit call.
- Docker completions were silently broken in the previous commit: the
  Docker fpath augmentation happened AFTER compinit, so the new completion
  files were never picked up. Move it next to the asdf fpath augmentation,
  before compinit. The original .zshrc worked around this with a second
  compinit; this fix is cleaner.
- Remove the dead DIRENV_LOG_FORMAT first assignment (it was immediately
  overwritten by the line below). Update the comment to explain that the
  intent is to silence direnv output.
- Combine .exports and .path into shell/env.zsh sourced first by zshrc.
- Use zsh path= array form for clarity.
- Fix GOPATH bug: was $HOME/go/bin (the bin dir), now $HOME/go (the
  parent). Paired with old PATH entry ~/go/bin/bin which was also wrong;
  net result was working by accident.
- Drop HISTCONTROL (bash-only), LESS_TERMCAP_md (broken $yellow ref),
  PKG_CONFIG_PATH=/usr/local/ (wrong on Apple Silicon), NVM (moved to
  asdf), commented JAVA_HOME, ANSIBLE_PYTHON_INTERPRETER.
- Drop dead PATH entries (Intel-era python, ansible, libxml/libxslt,
  easyrsa, pinned Python 3.9 user bin, redundant /opt/homebrew/bin).
- Keep /opt/homebrew/opt/grep/libexec/gnubin (verified gnu-grep installed).
- Add XDG_*_HOME exports and XDG-relocated history vars (HISTFILE,
  LESSHISTFILE, PSQL_HISTORY, PYTHON_HISTORY, NODE_REPL_HISTORY) plus
  NPM_CONFIG_USERCONFIG. Histories now live under ~/.local/state/.
- Remove transitional .exports/.path source block from zshrc.
- Remove stale inline HISTFILE= assignment from zshrc that overwrote
  the XDG-relocated path set in env.zsh.
zshrc.zsh: change shell-dir resolution from ${0:A:h} to ${(%):-%N}.
Inside .zshrc, $0 is "zsh" (the shell name), not the rc file path, so
${0:A:h} expanded to the cwd or wherever, not the dotfiles dir. ${(%):-%N}
is the zsh prompt expansion that gives the currently-sourcing file path.

env.zsh:
- Fix misleading comment about /opt/homebrew/bin ordering (zprofile is
  sourced AFTER env.zsh, so brew shellenv's bins appear later, not
  earlier).
- Add shellcheck disable=SC2206 for the zsh-array $path expansions.
- Remove redundant export PATH in the middle of the file; keep one at
  the end with a comment about zsh's path/PATH tie.
- Make AWS_PROFILE override-friendly with ${AWS_PROFILE:-govcloud-dev}.
- Export ASDF_DIR alongside ASDF_DATA_DIR; without it, the fpath
  augmentation in zshrc.zsh tried to read /completions (junk path).
Drops aliases that were broken (urlencode -- Python 2 syntax), dead
upstream (lwp-request HTTP-method loop, jsc, chrome), dangerous (update
-- mixed sudo across brew/npm/gem), or one-off macOS commands easily
re-Googled when needed (show/hide/lscleanup/emptytrash/airport/etc).

Kept: navigation, ls/grep color setup, clipboard helper, path printer,
map (xargs -n1), reload, docker/k8s/terraform/AWS/gcom/bazel aliases.

Also switches the shebang from #!/usr/bin/env bash (legacy from when
this file was .aliases) to #!/usr/bin/env zsh to match the extension,
and adds # shellcheck shell=bash directive so the linter knows what
dialect to use.
…ranches

- Drop gitio (git.io shut down), server/json (broken on Python 3),
  phpserver, getcertnames, escape/unidecode/codepoint, dataurl, gz,
  targz, digga.
- Replace initConfigVar (which ran kubectl config get-contexts at every
  shell startup and auto-mkdir'd ~/.kube/configs) with load_kubeconfigs,
  which only sets KUBECONFIG from existing kubeconfig files. No print,
  no side effects, faster shell startup.
- Keep mkd, cdf, fs, v, o, tre, profile, download_secret, upload_secret,
  clean_branches. clean_branches is rewritten with array-safe quoting
  to satisfy shellcheck.
- Switch shebang from #!/usr/bin/env bash to #!/usr/bin/env zsh to match
  the extension; add # shellcheck shell=bash directive.
Sources key-bindings and completion from $(brew --prefix)/opt/fzf.
Adds Ctrl-R for fuzzy history search, Ctrl-T for fuzzy file search,
**<TAB> for fuzzy completion. Uses fd or rg as the file source if
installed. Degrades cleanly when fzf is absent.
compinit's dump file moves from ~/.zcompdump to
${XDG_CACHE_HOME:-$HOME/.cache}/zsh/zcompdump.

The zsh/less/psql/python/node REPL histories are already relocated via
HISTFILE/LESSHISTFILE/PSQL_HISTORY/PYTHON_HISTORY/NODE_REPL_HISTORY
exports in shell/env.zsh (Task 7). \$HOME shrinks by six dotfiles.
Drops excludesfile and attributesfile from xdg/git/config -- git natively
finds ~/.config/git/{ignore,attributes} now.

Imports the global ignore from ~/.gitignore as xdg/git/ignore, merging
in the pattern that was at ~/.config/git/ignore (.claude/settings.local.json).
Dotbot symlinks it into ~/.config/git/ignore.
…ocal.md

The .claude/ directory holds Claude Code project state and the user's
per-project CLAUDE.local.md briefing -- not appropriate for the dotfiles
repo. Add .claude/ to .gitignore and remove the file that slipped into
the previous commit via 'git add -A'.
NPM_CONFIG_USERCONFIG is exported in shell/env.zsh (Task 7); the npmrc
moves from $HOME to $XDG_CONFIG_HOME/npm/npmrc. Same content
(ignore-scripts=true).
Brings the user's LazyVim setup, Ghostty terminal config, Zellij
multiplexer config, direnv config + hooks, and global yarnrc.yml into
the repo. Each is symlinked back to its conventional location by
Dotbot.

nvim is symlinked as a directory because lazy.nvim writes lazy-lock.json
in place; that file is a deliberate versioned artifact and should flow
back to git.
- .pre-commit-config.yaml orchestrates: gitleaks (secret scanning),
  shellcheck (shell lint), shfmt (shell format), and standard hygiene
  hooks (trailing-whitespace, end-of-file-fixer, check-yaml,
  mixed-line-ending).
- .gitleaks.toml extends the default ruleset; allowlists *.example and
  *.tmpl template files.
- .shellcheckrc sets bash dialect with disables for zsh-only idioms
  (SC2128/SC2168/SC2206/SC2296/SC2298/SC2139) and dotfile-common noise
  (SC1090/SC1091).
- scripts/lint wraps 'pre-commit run --all-files' for ad-hoc use.
- shell/prompt.zsh marked 'shellcheck disable=all' (zsh-heavy: TRAPUSR1,
  ZLE, porcelain v2 parsing -- shellcheck cannot usefully lint it).
- shell/fzf.zsh: drop 'local' outside function (real bug; replaced with
  bare assignment + unset at end).
- shfmt auto-formatted xdg/nvim/lazyvim.json, xdg/nvim/stylua.toml,
  xdg/zellij/config.kdl (trailing whitespace / final newline).

After cloning, run 'pre-commit install' to enable the git hook.

Also gitignores .nvimlog (transient nvim server log).
Two jobs on PR and push to main:
- pre-commit: runs the same .pre-commit-config.yaml as local hooks
  (gitleaks, shellcheck, shfmt, hygiene hooks).
- gitleaks-history: full-history scan with fetch-depth: 0; deeper than
  pre-commit's per-commit scan.

Pinned versions match .pre-commit-config.yaml so local and CI agree.
Documents the new layout (home/ xdg/ shell/), bootstrap commands for a
fresh machine, required vs optional tools, how to add modules, the
per-machine override pattern, lint command, and secrets convention.
@davidham davidham merged commit f14cd3d into main May 20, 2026
2 checks passed
@davidham davidham deleted the feature/reshape branch May 20, 2026 03:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant