Convert machine setup to declarative mise bootstrap - #21
Open
ericboehs wants to merge 5 commits into
Open
Conversation
Port bootstrap.sh and defaults.sh to mise's declarative bootstrap: packages, repos, dotfiles, macOS defaults and hooks in mise.toml, with the four genuinely imperative steps left as `bootstrap:*` tasks. Verified against this machine with `mise bootstrap -n`: all 37 macOS defaults keys from defaults.sh are covered (the two that aren't expressible — the -currentHost tap behavior and the $HOME-relative screenshot location — moved to hooks), and 23 of 25 dotfile entries already report `applied`. Two fixes fall out of the port: - ~/.tmux is declared as one directory link, matching what this machine actually has, so .tmux.conf's bindings for agenda.sh, btop.sh, goto-window.sh, move-window.sh and session-jump.sh resolve on a fresh install; bootstrap.sh linked only four of the nine helpers. - The dead ~/.ssh/config entry is dropped — the repo has no .ssh/, so bootstrap.sh would either prompt over a real config or leave a broken symlink. mise.toml is un-ignored here because the global gitignore excludes per-project mise configs; this repo's copy is the setup itself. bootstrap.sh and defaults.sh stay until this is proven on a fresh machine.
mise.toml now covers everything both scripts did, so delete them and point the README and CI at `mise bootstrap`. CI drives the real documented path — install mise from mise.run, then `mise bootstrap --force-dotfiles --skip tools,task` — and asserts convergence with `mise bootstrap dotfiles status --missing` instead of hand-listing every expected symlink. [tools] and the bootstrap task are skipped for runtime (bootstrap:nvim compiles every treesitter parser); bootstrap:linux-shims still runs on its own since it creates the fd/bat shims the tool check asserts on. Submodules are no longer checked out by actions/checkout so the pre-dotfiles hook is exercised instead. Also harden the workflow while it's open: default-deny permissions with per-job grants, actions/checkout pinned to a SHA and bumped to v7.0.1, and persist-credentials disabled. zizmor reports no findings. shellcheck now covers .tmux/*.sh, which is what's left of the repo's shell scripts; .claude/scripts/statusline.sh has pre-existing warnings and is left for its own change. Drop the iTerm2 Catppuccin import task and the iTerm2 pointer in .tmux.conf — Ghostty is the terminal now.
code-editor opened iTerm, and claude-man/monitor_tmux_pane passed -sender com.googlecode.iterm2 to terminal-notifier so click-through focused an app that is no longer installed.
.gitmodules declared .vim/pack/minpac/opt/minpac but .vim/ has no gitlink in the index (and no longer exists in the repo), so the entry was inert config. The four .vim* .gitignore lines guarded paths that are likewise gone.
Homebrew runs on Linux, so the brew: prefix only filters in one direction — the Ubuntu CI job installed the entire macOS list alongside the apt one and then died building terminal-notifier from source, which needs xcodebuild. Every package entry now carries an explicit os filter. The filter needs mise 2026.8.4, so declare min_version; without it an older mise reports only 'invalid type: map, expected a string'.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Replaces the imperative
bootstrap.sh(329 lines) anddefaults.sh(79 lines)with a declarative
mise.toml. Setup is nowmise bootstrap— convergent,dry-runnable, and diffable.
What moved where
brew install/apt-get installloops[bootstrap.packages](brew:,brew-cask:,apt:— the prefix is the platform filter)ln -sloop over a hardcoded file list[dotfiles], 25 entriesgit cloneof gcd[bootstrap.repos]defaults write× 37[bootstrap.macos.*]curated + raw[bootstrap.macos.defaults.<domain>]brew-cask:font-inconsolata-nerd-font[tasks.bootstrap]+ threebootstrap:*subtasksBugs this surfaced and fixes
.tmux.confbinds 9 helper scripts butbootstrap.shsymlinked only 4 —dead bindings on a fresh install. The TOML links
~/.tmuxas a wholedirectory, which is what the live machine actually has.
bootstrap.shlinked.ssh/config, but the repo has no.ssh/— it wouldprompt over a real
~/.ssh/configor leave a broken symlink. Dropped.~/.config/lsd/colors.yamlwas a broken symlink to a file nothing creates.The new config repairs it.
Ordering notes
TPM is a task, not a
[bootstrap.repos]entry: repos run at step 7 anddotfiles at step 8, so cloning into
~/.tmux/plugins/would materialize areal
~/.tmuxand block the whole-directory symlink. Submodules init from apre-dotfileshook for the same reason.Two
defaultskeys live in hooks rather than[bootstrap.macos.defaults]because template expressions do not render in defaults values (verified
against a junk domain):
com.apple.screencapture locationneeds$HOME, andNSGlobalDomain com.apple.mouse.tapBehaviorneeds-currentHost.Parity verification
domain keypairs fromdefaults.shand frommise bootstrap macos defaults status, diffed withcomm. 37 keys covered;the only two in the old script but not the TOML are the two moved to hooks.
Nothing extra.
mise bootstrap dotfiles status→ 25 entries, 23applied,2
differs(one real file byte-identical to the repo copy, one brokensymlink) — both resolved by
--force-dotfiles.mise bootstrap -nprints the bootstrap task withoutexecuting it.
CI
.github/workflows/bootstrap.ymldrives the real thing on Ubuntu instead ofasserting symlinks by hand:
mise bootstrap -y --force-dotfiles --skip tools,task, thenmise bootstrap dotfiles status --missing(exit 1 ondrift), a CLI-tool presence check, and a re-run no-op check. Hardened per the
gh-actions-security checklist — SHA-pinned checkout,
permissions: {}default-deny,
persist-credentials: false.Also
iTerm2 references swapped to Ghostty (
bin/code-editor, twoterminal-notifier -senderbundle IDs, a.tmux.confcomment), and the deadminpac submodule plus four stale
.vim*ignore rules removed.Not done here
mise bootstraphas not been run for real on the live machine yet — only-nand the per-step status commands. The old scripts are already deleted, sothis branch is the only path once merged.