Integrate with the devbox VM flow (de-brew Linux + mise) and lint the whole repo - #1
Merged
Merged
Conversation
.zshrc activates mise and the headless devbox flow runs `mise install`, but the repo shipped no mise config, so mise managed nothing. This adds mise/.config/mise/config.toml (stowed to ~/.config/mise/config.toml, which is exactly one of the paths devbox's guest_personalize role stats before running `mise install`). On the Debian VMs mise is the primary tool manager — there is no Homebrew — so the config pins the Node/Go runtimes plus the modern CLIs the shell config references (bat, eza, fd, ripgrep, delta, yq, zoxide, atuin, go-task). fzf and direnv are deliberately excluded: their oh-my-zsh plugins load before `mise activate`, so they come from apt on Linux / brew on macOS instead. Wires the package into the usual places: STOW_PACKAGES, the Brewfile snapshot (mise is a real brew formula here), the README/CLAUDE.md tables, and the mdBook (src/SUMMARY.md + src/mise.md). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The devbox Ansible flow clones this repo to ~/.dotfiles and runs this
script over SSH with no TTY as a passwordless-sudo user. Two things
blocked that, and both are fixed here.
De-brew Linux. Homebrew on an ephemeral VM is a heavy, slow step and we
now want mise to own language runtimes + modern CLIs there. Remove the
Linuxbrew install, the /home/linuxbrew shellenv, and `brew bundle`.
Instead:
* apt installs the base system and the CLIs Debian packages well,
plus fzf and direnv — those two must precede `mise activate` because
their oh-my-zsh plugins load at shell-init time.
* mise is installed from its own apt repo (same deb822 pattern as the
devbox role; skipped when devbox already installed it), and a new
step 7 runs `mise install` to materialize ~/.config/mise/config.toml.
The Brewfile stays the macOS source of truth.
Run headless. Derive DOTFILES_DIR from the script's own path so it works
from ~/.dotfiles, not just ~/dotfiles. Replace the bare `chsh` (which
prompts via PAM and hangs with no TTY) with `sudo chsh -s <zsh> <user>`,
a no-op when zsh is already the login shell. apt already runs with -y and
there are no other prompts.
Passes shellcheck (the repo's enable=all config) and shfmt -i 2 -ci.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
On the Debian VMs, mise is the only source of zoxide, atuin, eza, go-task, etc. But `mise activate` sat at the very bottom of .zshrc, after the `command -v zoxide`/`atuin`/`eza`/`task` checks that wire those tools up — so on Linux they were never on PATH when their checks ran, and the integrations silently no-op'd. Move `mise activate` up, right after the PATH setup, so its shims are present before those blocks. macOS is unaffected: Homebrew already puts the tools on PATH regardless of mise's position. Also switch the macOS GNU-tools block from a hardcoded /opt/homebrew to $(brew --prefix) (Intel-Mac safe) and gate it on `command -v brew`, per the repo convention. The block is already macOS-only, so Linux skips it. Verified: zsh -n passes and a fresh interactive shell loads cleanly on macOS (the pre-existing gitstatus notice is unrelated — it also appears on the prior .zshrc when sourced without a TTY). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Until now CI only built the mdBook. Add .github/workflows/ci.yml that
lints on push/PR the same way the lefthook template and stowed rc files
do locally:
* shellcheck + shfmt (pinned via mise's aqua backend — 0.11.0 / 3.13.1,
the versions these scripts were verified against) over the tracked
shell scripts, using shellcheck/.shellcheckrc (enable=all) and
shfmt -i 2 -ci.
* yamllint (pinned 1.38.0) over the tracked YAML, using the repo's
yamllint config.
Scoping is done with `git ls-files` so the gitignored vim persistent-undo
files that merely end in .sh/.yaml are never linted. gh's generated
config.yml (its own 4-space format, not ours) is the single YAML
exclusion. permissions are read-only; no untrusted event input reaches a
run step.
Verified locally: every tracked file passes these exact commands, so the
first run is green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Only the Debian bootstrap existed. Add bootstrap-macos.sh so a fresh Mac has a single idempotent entry point too: ensure Homebrew, `brew bundle` from the Brewfile, install OMZ + p10k + the custom plugins, and stow the packages. Homebrew stays the macOS source of truth. The mise package is deliberately left out of the macOS stow set — there the tools come from Homebrew, so the global mise tool-list is a Linux-only concern; per-project mise.toml pinning in individual repos is unaffected. Passes shellcheck (enable=all) and shfmt -i 2 -ci. README documents both bootstrap scripts and drops the stale "Linuxbrew" mention. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Format every authored Markdown file with mdformat (gfm + tables plugins,
wrap=keep, consecutive list numbering) and lint with markdownlint. This
aligns all the README tables (satisfying markdownlint's new MD060 rule)
and normalizes fenced-code / list / heading syntax without reflowing
prose.
Fix the substantive markdownlint findings by hand: add languages to bare
code fences (MD040), convert kitty's bold pseudo-headings to real ###
headings (MD036); markdownlint --fix handled the blanks-around-fences and
space-in-code nits.
Config:
* .markdownlint-cli2.jsonc — default rules, MD013 (line-length) off to
match .editorconfig; src/ (mdBook include-wrappers) and vim/.vim/
excluded.
* .mdformat.toml — wrap=keep + consecutive numbering.
mdformat --check and markdownlint are both clean and mutually idempotent.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reformat mise/.config/mise/config.toml with taplo (the TOML formatter now run in CI): single-space inline comments, aligned entries. No semantic change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a repo-root .editorconfig capturing the conventions actually used here (2-space default; tabs for Go/Make; Markdown exempt from trailing-whitespace and indent-width, since mdformat indents ordered-list continuations by 3). It mirrors the global editorconfig this repo ships. .editorconfig-checker.json excludes the files we don't hand-edit: the vendored vim colorschemes under vim/.vim/ and the p10k.zsh written by `p10k configure`. Normalize the two files that violated the config: git/.gitconfig had two stray tab-indented lines among 83 space-indented ones, and a tmux.conf if-shell continuation used a 3-space indent. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Expand the lint workflow to cover the whole tree using the repo's own configs: shellcheck + shfmt (shell), yamllint (yaml), actionlint (workflows), taplo (toml), markdownlint + mdformat (markdown), and editorconfig-checker. Binary linters come pinned from mise (aqua backend); yamllint and mdformat (+gfm/tables plugins) from pipx; markdownlint-cli2 from npm. Scope is `git ls-files` so gitignored vim persistent-undo files are skipped; gh's generated config.yml plus the vendored/generated files are excluded to match the local configs. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a repo-root lefthook.yml running the same nine linters as .github/workflows/ci.yml against staged files, so a pre-commit catches what CI would. Distinct from lefthook/lefthook.yml, which stays a stowable Go-project template. Enable with `lefthook install`. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Open a grouped weekly PR when the workflow actions (actions/checkout, jdx/mise-action, the mdBook and Pages actions, …) release new versions. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The Linuxbrew removal left two stale claims: that `bootstrap-debian.sh` runs `brew bundle`, and that `$(brew --prefix)` resolves Linuxbrew. Update both — the Brewfile is now the macOS path (bootstrap-macos.sh), and Linux uses apt + mise. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Ran bootstrap-debian.sh end-to-end in a fresh Debian 13 (trixie)
container as a passwordless-sudo user with no TTY, which surfaced two real
bugs:
* Fresh install aborted at `stow zsh`. The oh-my-zsh installer always
writes its template ~/.zshrc when a box has none (KEEP_ZSHRC=yes only
preserves an *existing* one), colliding with our stow target. Fix:
stow BEFORE installing OMZ, so ~/.zshrc is our symlink first and
KEEP_ZSHRC keeps it.
* Re-runs falsely refused ("Refusing to stow atuin:
~/.config/atuin/config.toml exists as a regular file"). stow folds a
single-package subtree into one dir symlink (~/.config/atuin -> repo),
so files under it look like plain files though they're already ours.
Fix: an `-ef` (same-inode) check tells an already-stowed file apart
from a genuine foreign one, keeping re-runs idempotent.
Also add gnupg to the apt set so mise verifies tool signatures instead of
warning. Same reorder + collision fix applied to bootstrap-macos.sh.
Verified in-container: fresh run exits 0 (no Homebrew; go/node + the CLIs
installed; ~/.zshrc and ~/.config/mise stowed; default shell zsh; .zshrc
sources cleanly; no gpg warning), and a re-run is a clean idempotent
no-op.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.
Summary
Two connected efforts:
sound-barrier/devboxAnsible flow,which clones the repo to
~/.dotfiles, runs./bootstrap-debian.shover SSHwith no TTY as a passwordless-sudo user, then runs
mise install. macOSkeeps Homebrew.
.editorconfig, and Dependabot.Linux / devbox
mise/stow package →~/.config/mise/config.toml(the exact path devboxstats before running
mise install). Pins Node/Go + the modern CLIs;fzf/direnvstay on apt/brew because their oh-my-zsh plugins load beforemise activate.bootstrap-debian.sh: drop Linuxbrew +brew bundle; install via apt + mise(mise from its own apt repo). Location-independent (works from
~/.dotfiles),fully non-interactive (
sudo chsh, no prompts). Stows before installingOMZ so its template
~/.zshrccan't collide, and an-ef(same-inode)collision check keeps re-runs idempotent.
.zshrc: activate mise before the zoxide/atuin/eza/task blocks (on Linuxthose tools exist only via mise);
$(brew --prefix)on macOS.bootstrap-macos.shcounterpart (Homebrew stays the macOS source of truth).Linting / tooling
.github/workflows/ci.yml: shellcheck, shfmt, yamllint, actionlint, taplo,markdownlint, mdformat, editorconfig-checker — all pinned, scoped via
git ls-files.lefthook.yml(repo root) with 1:1 parity to CI..editorconfig; Dependabot keeps the workflow Actions current.Verification
bootstrap-debian.shend-to-end in a fresh Debian 13 (trixie) containeras a passwordless-sudo user with no TTY: exits 0, installs no Homebrew, leaves
go/node + the CLIs on
PATH, stows~/.zshrcand~/.config/mise, sets thelogin shell to zsh, and
~/.zshrcsources cleanly — and a re-run is a cleanidempotent no-op.
Notes
misepackage is intentionally not stowed on macOS (Homebrew providesthe tools there); per-project
mise.tomlpinning is unaffected.rewrite it wholesale.
🤖 Generated with Claude Code