Skip to content

Chezmoi refactor - #1

Merged
ffrizzo merged 15 commits into
masterfrom
chezmoi-refactor
Aug 24, 2026
Merged

Chezmoi refactor#1
ffrizzo merged 15 commits into
masterfrom
chezmoi-refactor

Conversation

@ffrizzo

@ffrizzo ffrizzo commented Aug 24, 2026

Copy link
Copy Markdown
Owner

No description provided.

ffrizzo added 15 commits July 31, 2026 09:40
Fixes several bugs that would break a fresh install (invalid goreleaser
tap formula, renamed cask tokens, p10k sourced but never installed via
brew, stale mas entry), syncs tracked files with what's actually live
(.zshrc/.zprofile drift, dock tilesize, dock app list), fills in real
Brewfile gaps found via brew leaves/cask diffs and Spotlight usage data,
and replaces asdf/hey/httpie with mise/oha/xh. Also documents the
two-repo (dotfiles + dotfiles-confidential) install flow and adds a
sync-from-home.sh helper to pull local dotfile edits back into the repo.

See plans/dotfiles-refresh-plan.md for the full rationale.
Fixes several bugs that would break a fresh install (invalid goreleaser
tap formula, renamed cask tokens, p10k sourced but never installed via
brew, stale mas entry), syncs tracked files with what's actually live
(.zshrc/.zprofile drift, dock tilesize, dock app list), fills in real
Brewfile gaps found via brew leaves/cask diffs and Spotlight usage data,
and replaces asdf/hey/httpie with mise/oha/xh. Also documents the
two-repo (dotfiles + dotfiles-confidential) install flow and adds a
sync-from-home.sh helper to pull local dotfile edits back into the repo.

See plans/dotfiles-refresh-plan.md for the full rationale.
Replaces the hand-rolled setup.sh + install-*.sh/osx-*.sh script pile and
one-directional `cp -a ./home/ ~/` with chezmoi: dotfiles get the dot_
naming convention at repo root, and all install/setup logic moves into
ordered .chezmoiscripts/ (run_once_/run_onchange_ scripts), replacing
setup.sh, install-cli-tools.sh, install-homebrew.sh, install-zsh.sh,
install-broswer-extensions.sh, install-cursor-plugins.sh,
osx-system-defaults.sh, osx-user-defaults.sh, setup-dock.py/.sh, and
sync-from-home.sh outright (chezmoi's diff/apply/re-add natively solves
the drift problem sync-from-home.sh was working around).

Along the way:
- Dock setup now uses `brew "dockutil"` instead of an unverified curl+pkg
  install of the latest GitHub release, and drops the interactive
  confirmation prompt so it can run unattended under `chezmoi apply`.
- Fonts install via `cp -n` into ~/Library/Fonts instead of a manual
  Font Book "Install" click-through.
- Fixed macos-system-defaults running fully under `sudo` (which wrote
  user-domain `defaults write -g` calls to root's domain instead of the
  actual user's) - only the genuinely system-level calls are sudo'd now.
- Fixed `dock autohide` being written without a `-bool` type flag.
- Dropped the orphaned `.git-templates/hooks/prepare-commit-msg` (no
  `init.templatedir` ever pointed at it) and the `arkade` Brewfile entry
  (not installed, not a brew leaf - rot from before either audit).
- Brewfile installs are now hash-gated: `run_onchange_before_10-packages`
  only re-runs `brew bundle` when the Brewfile's content actually changes.
- Added ShellCheck + a macOS smoke-test GitHub Actions workflow.

dotfiles-confidential stays untouched and fully separate, per plan.
Matches convention for chezmoi run_ scripts.
- run_once_after_30-dock.sh.tmpl: dockutil is now a Homebrew formula
  (installed to /opt/homebrew/bin), which isn't on PATH within this
  script's own process since each .chezmoiscripts file runs independently
  - the packages script's `eval brew shellenv` doesn't carry over. Without
  this, dockutil silently wouldn't be found on a genuinely fresh machine
  and the run_once script would never retry. Added the same shellenv
  bootstrap used in the packages script before the dockutil check.

- run_onchange_before_10-packages.sh.tmpl: running a full `brew bundle`
  against the entire Brewfile on every CI push (dozens of formulae/casks,
  several JDKs, full browsers, CAD apps) risked exceeding GitHub-hosted
  macOS runners' disk/time budget, making the smoke test flaky for
  reasons unrelated to the change under test. Tried validating individual
  formula/cask names via `brew info` in CI first, but that produces false
  positives on legitimate third-party-tap entries (svu, goreleaser) that
  Homebrew's tap-trust model blocks from `brew info` without an explicit
  `brew trust` - confirmed by testing both directly. Settled on
  `brew bundle list`, which validates the Brewfile's syntax without
  attempting to resolve or install anything, and documented in both the
  script and README that catching renamed/removed formulas is still a
  manual `brew bundle check --verbose` step after editing Brewfile.
Caught by the GitHub Actions smoke test - compaudit failed with
"command not found" under bash. It's a zsh completion-system function
that needs `autoload -U compaudit` first, not a standalone binary, so
the script needs `#!/bin/zsh`. Was silently swallowed by the trailing
`|| true` (the script "succeeded" but never actually fixed the
completion directory permissions).
Caught by actually running the workflow: ludeeus/action-shellcheck
auto-detects shell from each script's shebang, and ShellCheck flatly
refuses zsh scripts (SC1071) - it only supports sh/bash/dash/ksh. My
local verification passed because I was manually passing --shell=bash
without realizing the CI config itself didn't. Since the one zsh script
(oh-my-zsh install) is otherwise plain POSIX-ish shell, checking it in
bash mode is fine - verified locally before this commit.
unsupported action input

ludeeus/action-shellcheck has no option to force --shell (confirmed by
the action itself rejecting the shellcheck_options input I tried:
"Unexpected input(s) 'shellcheck_options', valid inputs are
[additional_files, ignore, ignore_paths, ignore_names, severity,
check_together, scandir, disable_matcher, format, version]"). It
auto-detects shell from each file's shebang instead, and refuses zsh
scripts outright (SC1071). Since these are lint-only copies anyway (the
real .tmpl files keep their real shebangs), just replace line 1 with
`#!/bin/bash` unconditionally when generating them - simpler and more
portable than trying to sed-replace only the zsh one (my first attempt
at that broke on this machine's BSD sed and stripped every shebang).
Rancher Desktop manages this block itself (injects it on first launch
when shell integration is enabled) - tracking it here just meant it'd
get fought over between the app and chezmoi apply on every re-run.
oh-my-zsh's synchronous plugin loading was the actual source of shell
startup lag. zinit's turbo mode (wait/lucid ice) defers plugin loading
until just after the first prompt renders, typically cutting startup
from ~200ms to ~40ms.

- Every current oh-my-zsh plugin gets a 1:1 OMZP:: snippet equivalent -
  no functionality dropped, just deferred loading.
- zsh-syntax-highlighting -> zdharma-continuum/fast-syntax-highlighting:
  the original doesn't tolerate turbo-mode's async loading (autosuggestions
  can wrap ZLE before it does, silently breaking highlighting with no
  error) - this is the documented, actively-maintained fork built for
  exactly this ordering problem. Loaded before autosuggestions with
  atload"!_zsh_autosuggest_start" to force synchronous init order.
- zsh-autosuggestions and zsh-completions move from brew-installed to
  zinit-managed too, since that's what makes controlling load order
  possible in the first place - removed from Brewfile.
- No theme added - Warp's own prompt already provides the visual look,
  matching current behavior (no ZSH_THEME was set before this either).
- run_once_after_20-oh-my-zsh.sh.tmpl -> run_once_after_20-zinit.sh.tmpl,
  same run_once + directory-existence-guard pattern, just cloning zinit
  instead of oh-my-zsh.
- Added a zsh startup verification step to the smoke test: oh-my-zsh
  silently warns on an unknown plugin name, but zinit's OMZP:: snippet
  fetch hard-errors (404) on one, so this is what actually catches a bad
  plugin-name mapping in CI before it reaches a real machine.
The previous check (zsh -ic 'exit') returned before most of the ~39
zinit snippets had a chance to load - the captured log only showed the
first 4 (the trio + OMZP::aliases) before the step finished, meaning it
wasn't actually validating the other 35 plugin names. Added a real wait
and an explicit check that the last plugin in the list (OMZP::yarn)
actually loaded, so a silent early-exit doesn't look like a clean pass.
20s wasn't close to enough - the previous CI run showed the 2nd zinit
snippet hadn't even started downloading after 25s. Fetching ~39
individual files from GitHub with zero parallelism on a cold cache is
genuinely slow; this is a one-time cost on first shell start, not
representative of the actual startup-time improvement this migration
is for.
…tion

Direct curl validation of every OMZP:: plugin URL (bypassing zinit/turbo
mode entirely) found the real bug the interactive-shell approach never
reached: redis-cli isn't a real oh-my-zsh *plugin* (no .plugin.zsh file
exists) - it only ships a completion file (_redis-cli). Fixed in
dot_zshrc: moved it out of the plain snippet list into its own
as"completion" load pointing at OMZP::redis-cli/_redis-cli, same pattern
oh-my-zsh's own docs use for docker's _docker completion.

Also replaced the interactive-shell-based CI check entirely. Across two
separate runs (20s then 120s sleep), zsh -ic 'sleep N; exit' consistently
stalled right after the very first deferred plugin regardless of how
long it waited - turbo mode's queue advancement appears to depend on
genuine interactive idle-time scheduling that a -c command context
doesn't produce, so no amount of sleeping was going to fix it. Replaced
with two steps: a short (5s) check that zsh starts without hard errors,
and a direct curl check of every OMZP:: plugin URL - which is both more
reliable and actually found the real bug on the first local run.
The already-tracked Library/Preferences/dev.warp.Warp-Stable.plist
doesn't hold the meaningful stuff - Warp's actual theme, font, tab
behavior, and keybinding settings live in ~/.warp/settings.toml instead
(a plain, non-sensitive TOML file), which wasn't tracked anywhere. This
is what actually restores the look on a fresh install.
@ffrizzo
ffrizzo merged commit 1e2b676 into master Aug 24, 2026
4 checks passed
@ffrizzo
ffrizzo deleted the chezmoi-refactor branch August 24, 2026 13:06
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