Skip to content

Converge: one branch, one installer, every machine - #15

Merged
woud420 merged 36 commits into
masterfrom
converge/jm-home-box-laptop
Jul 10, 2026
Merged

Converge: one branch, one installer, every machine#15
woud420 merged 36 commits into
masterfrom
converge/jm-home-box-laptop

Conversation

@woud420

@woud420 woud420 commented Jul 9, 2026

Copy link
Copy Markdown
Owner

What this is

The full consolidation of the dotfiles work that was stranded across 6 branches, 2 machines, and 4 AI-session surfaces. One branch, one installer (install.sh), covering the MacBook and jm-home-box (Arch/Sway). Executes the plan agreed in docs/convergence/combined-plan.md with the decisions made on 2026-07-09.

Do not merge yet — explicit joint verification agreed.

Decisions encoded here (flagging for your review)

  1. One tool: install.sh. scripts/dotfiles.py + common/bin/dotfiles + machines/ removed. install.sh gained install_desktop_configs (everything under linux/arch/.config/~/.config/, copy-only). Rationale: only install.sh can bootstrap a bare machine (packages, plugins, CoC); dotfiles.py only synced files.
  2. Theme: the committed Arch overlay wins (personal-pink, #2A1E2E), macOS/debian stay Catppuccin-Mocha; color-linux-box.md archived under docs/reference/ as the container-theming example.
  3. Shell-function stubs kept (git.sh, docker.sh, k8s.sh, …) and documented as disabled-for-later-restore.
  4. charlie-lab-laptop: not merged; reviewed for leverage, nothing unique needed. Branch left intact.
  5. AI-context installs are copies (not symlinks): ~/.claude/CLAUDE.md, ~/AGENTS.md, ~/MACHINE.md. Machine-state snapshots are manual (scripts/refresh-machine-state.sh); the pacman auto-refresh hook is NOT installed by default (unattended repo writes).
  6. Local overrides are the clobber escape hatch: ~/.bashrc.local, ~/.zshrc.local, ~/.gitconfig.local (included last, so git-ai's PATH/trace2 appends survive reinstalls), and ~/.ssh/config keeps machine-local entries with shared defaults via a prepended Include.

What went in

  • Merged fix/jm-home-box (11 commits): Arch desktop configs (Sway/Waybar/GTK/kitty personal-pink), sudo-askpass, installer fixes, treesitter.
  • Merged feature/ai-context (= fix/dotfiles-cleanup minus the rescued 3dabbca commit, which is cherry-picked here): legacy duplicate dirs deleted (shell/, git/, bash/, config/, root dotfiles — its root-symlink versions were not imported), AI-context files, and the CI workflow — rewritten: it targeted main (would never run here), asserted symlinks the copy-only installer doesn't create, and container jobs would have been forced into minimal mode (new DOTFILES_FULL_INSTALL override).
  • Cherry-picks: CoC npm fallback as a shared helper (from bugfix/coc-nvim-ci-error), TS syntax plugins, git-lfs filter; your rescued 3dabbca git hooks (pre-commit secrets/conflict/size guard, pre-push repo check — installed to ~/.config/git/hooks via core.hooksPath); rofi + mako configs from feature/add-linux-box; sudo-askpass now installed to ~/.local/bin/sudo-askpass so SUDO_ASKPASS works on any checkout path.
  • Gap fixes: README-promised local-override hooks now exist; guarded ~/.local/bin/env; common/ssh/config finally installed (non-clobbering, IgnoreUnknown UseKeychain for Linux); broken Makefile legacy section removed; docs made truthful (clone URL, stub table, remote-install commands, arch README).
  • 34 findings from an adversarial multi-agent review, all fixed — highlights: first-run install aborted at vim PlugInstall under set -e (reproduced on a clean HOME, now guarded + silent! colorscheme); the CI YAML was invalid (GitHub would reject the file); the SSH Include-append was host-context-dependent (now prepended); bash prompts lacked \[ \] readline delimiters; pre-commit hook was bash-4-only (macOS ships 3.2).

Rescued before anything else

  • 3dabbca ("current state of stuff I want") pushed to origin/fix/dotfiles-cleanup — its git hooks are in this PR.
  • The home box's diverged feature/add-linux-box preserved at backup/homebox-add-linux-box.

Verified

  • make check green; installer smoke test green.
  • Fresh-HOME full install completes end-to-end (exit 0, all artifacts present) — it did not before.
  • Fresh-HOME --dry-run creates zero files/dirs — it did not before.
  • Workflow YAML validates; .gitconfig parses; bash -n/zsh -n clean across configs, hooks, scripts.
  • CI (lint + Arch/Debian/macOS install tests) runs on this PR — first real run of this workflow.

After merge (not in this PR)

  • master fast-forwards past PR [codex] Add default git commit template #14 (git commit template) — it should auto-close as merged.
  • Delete superseded branches: fix/jm-home-box, feature/ai-context, fix/dotfiles-cleanup, feature/add-linux-box, bugfix/coc-nvim-ci-error, codex/git-commit-template, feature/personal-laptop, feature/personal-laptop-combined, plus the already-merged feature/codex-cleaning (the other stale codex/* refs listed earlier live only as remote refs already contained in master).
  • Switch jm-home-box's checkout off fix/jm-home-box and re-run ./install.sh; re-install on the MBP (live ~/.zshrc/~/.gitconfig drift from git-ai gets preserved via the new .local includes).
  • brew bundle check still fails on the docker-desktop cask on the MBP — pre-existing, untouched here.

🤖 Generated with Claude Code


Round 2 adversarial review (post-open)

A second 35-agent pass with different lenses (fix regressions, live runtime execution, bash-3.2/BSD portability, security, intent fidelity, fresh eyes) confirmed 25 more findings — all fixed in the two follow-up commits. Highlights: Arch packages.list still shipped renamed/removed packages (exaeza, deltagit-delta, neofetch gone, swayfx is AUR) so a default Arch install aborted; the round-1 </dev/null PlugInstall guard made vim-only machines silently install zero plugins (now pre-seeds vim-plug + ex-mode recipe, verified 10/10 plugins land in a fresh HOME); the git hooks had SIGPIPE-under-pipefail false negatives on large files, a dash-leading-filename bypass, and blocked every Cargo.lock/poetry.lock commit (all reproduced, fixed, and re-verified with staged-file tests); repo-hook delegation (.husky) gets a jm.hooks.runRepoHooks trust switch; .zshrc aborted mid-file on an empty shell-functions dir (null-glob fix); the Sway config carried a literal @sysconfdir@ placeholder. The intent-fidelity reviewer verified all four user decisions hold on HEAD.

Round 3 adversarial review

A third 45-agent pass (round-2 fix regressions, live runtime matrix, cross-file coherence, hostile-environment adversary, completeness critic over never-reviewed files) confirmed 33 more findings, all fixed in 27c10b2. The two that mattered: vim-plug cannot run in ex mode, so the round-2 recipe still installed zero plugins on vim-only machines (nvim's shared plugged/ dir had masked it — now a pty via script(1), verified 9/9 on a vim-only PATH), and a legacy ~/.vim -> repo symlink made the installer delete the repo's own files (now materialized to real dirs first; verified repo-intact). Also: the three secondary install scripts silently disabled all git hooks via a dangling core.hooksPath; the rofi theme was never loaded; sway's screenshot key invoked a nonexistent tool; ~/.claude/CLAUDE.md is no longer clobbered when user-customized; neovim is now actually in the Linux package lists; and the jm.hooks.runRepoHooks security switch honors git boolean spellings. 7 findings refuted.

woud420 and others added 30 commits January 25, 2026 14:15
- Add install_ai_context() to symlink CLAUDE.md, AGENTS.md, MACHINE.md
- Add install_pacman_hook() with __DOTFILES_DIR__ templating
- Run refresh-machine-state.sh during install to bootstrap state file
- Symlink generated machine-state.md to ~/MACHINE-STATE.md

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Override the kitty theme background with a dark plum (#2A1E2E) that
coordinates with the Sway purple/pink accent (#9d5a7f), matching the
jm-home-box machine.toml style = "personal-pink".

Scoped to Arch only: install.sh overlays linux/arch/.config/kitty/*.conf
over the shared common/themes after copying them, guarded by DISTRO=arch.
macOS and other distros keep stock Catppuccin-Mocha (#1E1E2E).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The cross-platform askpass script (rofi on Linux, osascript on macOS)
had gone missing on this branch, breaking sudo -A. Restore it from
abfeea3 and track it so it stops disappearing. rofi inherits the system
theme.rasi, matching Sway/Waybar/Mako without any custom styling.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Install Neovim alongside the existing Vim config and alias vi/vim/vimdiff to nvim when available.

Keep installs copy-based with path-preserving backups and audit logs, and add installer/editor parity checks.

Remove the GNU which alias and replace it with a shell-aware lookup wrapper so aliases are visible.

Tests: make check; make check-editor
# Conflicts:
#	common/shell/.zshrc
#	darwin/Brewfile
Keep the GitHub HTTPS-to-SSH rewrite with the rest of the top-level Git settings after the laptop branch merge.

Checks: git diff --check -- common/git/.gitconfig; git config --file common/git/.gitconfig --get-regexp
# Conflicts:
#	common/git/.gitconfig
#	install.sh
Update the macOS Brewfile from the current no-description Homebrew bundle dump.

Add guarded git-ai PATH support for bash/zsh and suppress zsh no-EOL markers.

Skipped the local git-ai Git trace2 socket because it is machine-local daemon state, not portable dotfiles config.

Checks: make check; make check-editor; zsh -n common/shell/.zshrc; bash -n common/shell/.bashrc; git diff --check. Brew bundle check still reports docker-desktop needs install/update.
- machine-state.md: bump kernel, bash, python, node, docker, kubectl,
  terraform; drop go/rust from PATH (not installed); replace stale
  recently-installed list with full AUR explicit-package inventory
- machine.toml: expand aur[] to reflect all explicitly installed AUR
  packages (GPU drivers, nordic theme, swayfx, fonts, apps)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Installed neovim 0.12.3 (was in machine.toml but missing from system)
- Removed python38 3.8.20 (legacy, 111 MiB freed)
- machine-state.md: reflect nvim version, drop python38, bump pkg count to 896

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
712 MiB freed. Update machine-state.md to reflect removal and drop pkg
count to 892.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Default COPY_MODE=true; --symlink flag for explicit opt-in (non-negotiable
  constraint from combined plan: no symlinks)
- backup_file() now preserves directory structure under BACKUP_DIR and shows
  destination path in both real and dry-run output
- install_vim_config() expands dry-run output to list every file individually
- Add nvim install step: copies common/nvim/init.vim -> ~/.config/nvim/init.vim
  (bridges to existing vim config; identical behavior on both machines)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…#13)

* Clean up dotfiles: fix Linux theme/fonts, remove duplicates, add missing configs

- Fix Kitty theme: custom warm purple matching Sway/Waybar/Rofi/Mako palette
- Fix Kitty include path (was broken after install.sh copy)
- Replace FiraCode Nerd Font with Iosevka Nerd Font (Linux only)
- Add OS-specific theme override in install.sh (Linux=purple, macOS=Mocha)
- Remove duplicate directories: bash/, config/, git/, shell/ (all shadowed by common/)
- Remove .bak files from version control
- Add machine.md stubs for debian, fedora, alpine
- Guard unprotected source of ~/.local/bin/env in .zshrc and .bashrc
- Add install.sh deployment for .tmux.conf, .inputrc, .gdbinit
- Move sudo.sh to common/shell-functions/, track sudo-askpass.sh
- Add fedora/alpine routing in refresh-machine-state.sh
- Include accumulated config updates (vim, shell-functions, git, tmux)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Add CI workflow to test install.sh across Arch, Debian, and macOS

Runs on push/PR: spins up Arch (container), Debian (container), and
macOS (native runner) to verify install.sh deploys correctly on each.
Checks symlinks, copies, kitty theme per OS, and font config.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Use FiraCode Nerd Font on Linux (same as macOS)

FiraCode Nerd Font is the preferred font on both platforms.
Installed via ttf-firacode-nerd on Arch.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Rewrite CI with deep config validation, not just file existence checks

Adds a fast lint job (shell syntax, shellcheck, git config parse, CoC
JSON validation) that gates the platform tests.

Platform tests now validate configs actually load:
- Kitty: headless parse via kitty +runpy with load_config(), checks for
  bad lines, verifies parsed font/opacity/cursor values
- Vim: loads vimrc in ex mode (vim -e, not -es which breaks line
  continuations), runs PlugInstall --sync
- tmux: starts headless server, verifies config loads
- Git: parses .gitconfig, counts aliases
- Shell: bash -n / zsh -n syntax validation on deployed configs
- Fonts: fc-list -q to verify font actually resolves (not fc-match
  which always falls back)
- Theme: verifies correct colors deployed per OS (purple on Linux,
  Catppuccin Mocha on macOS)

Each platform uploads an evidence artifact with install log, deployed
file listing, theme contents, git aliases, and vim plugin list.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Add super+ keybindings to Linux kitty config with ctrl+shift fallbacks

Matches the deployed config on the Arch box. Super+ gives macOS-style
shortcuts on Linux (Sway passes Super to apps), ctrl+shift+ as fallback.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…figs

Brings in the jm-home-box work: scripts/dotfiles.py convergence CLI,
machines/jm-home-box profile, Sway/Waybar/GTK/kitty personal-pink Arch
desktop configs, sudo-askpass.sh, treesitter settings, and pruned arch
packages.list.

Conflict resolutions:
- install.sh: kept copy-only mode (no --symlink escape hatch), kept the
  audited backup_path_for backups, and consolidated the incoming
  copy_file() duplicate into install_file() (which removes targets
  before copying so symlinked setups convert cleanly to copies).
- Makefile: union of check/test-install/check-editor and dotfiles-*
  targets (dotfiles-* removed in the follow-up single-tool commit).
- common/nvim/init.vim: kept coc_config_home bridge from the laptop side.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
scripts/dotfiles.py and install.sh overlapped on the copy step but split
responsibilities: only install.sh could bootstrap a machine (packages,
vim plugins, CoC, fzf), while only dotfiles.py knew about the Arch
desktop files. One tool is enough:

- install.sh gains install_desktop_configs: on Arch, everything under
  linux/arch/.config/ is copied into ~/.config/ preserving relative
  paths (sway, waybar, gtk-3.0/4.0, and any future tool configs),
  with the kitty subdir still applied as theme overlays.
- Remove scripts/dotfiles.py, common/bin/dotfiles, and
  machines/jm-home-box/machine.toml (nothing consumes machine.toml
  anymore; OS/distro detection covers the real per-machine differences).
- Remove the dotfiles-* Makefile targets and rewrite the README
  convergence section around the single entry point.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Delete-wins on the legacy duplicate layout: root .gitconfig/.zshrc/
.tmux.conf/.inputrc/.gdbinit/.dircolors and the bash/, shell/, git/,
config/ directories are gone (including config/kitty.conf.bak). The
branch's repo-internal symlinks for root .gitconfig/.zshrc were NOT
imported - this repo is copy-only.

Kept from feature/ai-context:
- common/ai-context/ (AGENTS.md, CLAUDE.md, context.md) + per-OS
  machine.md, installed by a new copy-based install_ai_context step
  (the branch's symlink version contradicted copy-only installs).
  Machine-state snapshots are generated manually via
  scripts/refresh-machine-state.sh, not at install time, and the
  pacman auto-refresh hook is no longer installed by default (it
  caused unattended writes into the repo); the hook file remains
  in linux/arch/hooks/ for manual opt-in.
- path_prepend dedup helper, mise activation, and kctx in .bashrc.
- Linux kitty super+ keybindings (union with existing copy/paste maps).
- Guarded sourcing of ~/.local/bin/env in .zshrc (fixes fresh installs
  on machines without uv).
- .github/workflows/test-install.yml, rewritten for reality: triggers
  on master (was main, so CI would never have run after consolidation),
  asserts copies instead of symlinks, tests the Arch desktop configs
  and personal-pink overlay (and that it does NOT leak to debian/macos),
  and uses the new DOTFILES_FULL_INSTALL override so container jobs
  aren't forced into minimal mode.

Also fixes refresh-machine-state.sh to derive the repo path from its
own location instead of hardcoding ~/workspace/dotfiles.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
From bugfix/coc-nvim-ci-error: extract a shared compile_coc_nvim helper
(npm ci with lockfile, npm install fallback, non-fatal on failure) used
by both the vim and nvim paths, replacing two duplicated bare `npm ci`
blocks; lightweight typescript-vim + vim-jsx-typescript plugins with
polyglot's heavy TS syntax disabled; git-lfs filter in .gitconfig.

From the rescued home-box commit 3dabbca: personal global git hooks
(pre-commit blocks secrets/conflict markers/oversized files, pre-push
runs a configured repo check; both delegate to repo hooks like .husky
first), installed copy-based to ~/.config/git/hooks with core.hooksPath
set by the installed .gitconfig, plus a make install-git-hooks target.

From feature/add-linux-box: the mako notification config, rofi
theme.rasi (used by the rofi sudo-askpass prompt), and the Arch README
- picked up automatically by install_desktop_configs.

sudo askpass: the installer now copies scripts/sudo-askpass.sh to
~/.local/bin/sudo-askpass, and sudo.sh points SUDO_ASKPASS there
instead of hardcoding ~/workspace/dotfiles (which was wrong on any
machine with a different checkout path).

fix/charlie-lab-laptop reviewed for leverage: its only unique content
is work-laptop machine captures and Brewfile entries already present
or out of scope; nothing further taken.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
woud420 and others added 6 commits July 9, 2026 13:36
…eanup

- Machine-local override hooks now actually exist: ~/.bashrc.local and
  ~/.zshrc.local are sourced at the end of the shell configs (the README
  promised this but nothing implemented it), and .gitconfig gains an
  [include] of ~/.gitconfig.local that wins over shared values - the
  sanctioned home for tool-appended blocks (git-ai PATH/trace2) that
  copy-based reinstalls would otherwise clobber.
- common/ssh/config is finally installed: copied to ~/.ssh/config.dotfiles
  and Include'd from ~/.ssh/config so machine-local host entries keep
  precedence, with IgnoreUnknown UseKeychain so the macOS-only option is
  harmless on Linux.
- Makefile: the broken legacy section is gone (duplicate darwin target,
  misspelled brews rule with an Intel-only path, backup-bash calling a
  script that does not exist, no-op profile-source, misleading stow-*
  aliases, unlink of files nothing installs) and help now matches the
  targets that exist.
- README: real clone URL, master instead of main in the raw one-liner,
  shell-function table split into what works vs the disabled stubs that
  are deliberately kept for incremental restore, kubectl section trimmed
  to the k alias and kctx, accurate git-hooks and AI-context sections.
- install.sh closing tips no longer advertise sshdot / k get p, which
  do not exist.
- scripts/update_cursor_tools.py removed (cursor was dropped earlier).
- The two-agent convergence plan artifacts from jm-home-box are archived
  under docs/convergence/ (combined-plan.md and inputs) with
  docs/reference/color-linux-box.md kept as a container-theming example,
  and docs/machine-convergence-plan.md marked historical with the
  decisions that supersede it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Installer correctness:
- First-run no longer aborts: vim/nvim PlugInstall get </dev/null and a
  log_warning guard (a fresh machine hit E185 from the not-yet-installed
  colorscheme, hung at press-ENTER or died under set -e, silently
  skipping the nvim bridge, fzf, and AI-context steps); appearance.vim
  now uses silent! colorscheme.
- compile_coc_nvim's subshell is now the if-condition, so an npm failure
  reaches the intended warning instead of tripping set -e (the previous
  guard was dead code).
- --dry-run no longer creates ~/.config/{git,kitty,htop} and logs the
  real backup destination; install_vim_config dedupes its dry-run branch
  (settings.vim was missing from the log) and drops a duplicated nvim
  init.vim install; minimal mode skips plugin installation; fzf install
  no longer aborts when ~/.fzf exists or the network fails; stale
  --symlink usage comment removed.
- SSH: the Include is prepended to ~/.ssh/config instead of appended -
  an Include after a Host block only applies to that host, and
  IgnoreUnknown must parse before any UseKeychain reaches Linux openssh.

Shell configs:
- .bash_profile guards ~/.local/bin/env like the other rc files.
- bash prompts wrap color escapes in \[ \] (raw escapes corrupt readline
  line wrapping); single path_prepend definition moved before
  shell-function loading with one comprehensive call (the merge had left
  a raw duplicate block that re-prepended on every source).
- .zshrc path_prepend includes ~/.local/bin; macos-clipboard.sh gets a
  shebang (shellcheck error severity would fail CI).
- pre-commit hook: mapfile -d replaced with a bash-3.2-portable read
  loop (macOS system bash) and ======= alone no longer false-positives
  as a conflict marker.

CI workflow:
- Fixed invalid YAML in the install.sh syntax step (plain scalar with a
  colon - GitHub would have rejected the whole file).
- set -o pipefail on the three install steps (| tee masked failures),
  personal-pink assertion now enforcing, debian/macos jobs assert the
  AI-context files, lint job runs apt-get update before installing zsh.

Repo hygiene and docs:
- Untracked generated linux/arch/ai-context/machine-state.md (gitignore
  already declared it); deleted orphaned root .dircolors,
  .dircolors-catpuccin, .gnu_aliases, .profile, stale
  linux/common/current-theme.conf, cursor .gitignore entry, and the
  unused hashicorp tap.
- README: working remote-install commands, dropped nonexistent v/kns,
  package list matches the Brewfile; linux/arch/README.md now describes
  the copy-based install.sh flow, the real kitty overlay (#2A1E2E), and
  drops stale AMD GPU claims (the box runs NVIDIA);
  quick-install.sh uses copies instead of symlinks per policy.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Debian's default step shell is dash, which rejects set -o pipefail
(GitHub's explicit bash shell runs with -eo pipefail built in), and
/tmp/evidence was created by root while testuser writes the report.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The big two:
- Arch installs work again: linux/arch/packages.list still listed exa,
  delta, and neofetch (renamed/removed from the repos) and swayfx (AUR
  only), so a default ./install.sh on Arch aborted before installing
  anything. Renamed to eza/git-delta, moved swayfx to a documented AUR
  section, added ttf-firacode-nerd (the configs require it; also added
  the font cask to the Brewfile), and the pacman step now uses --needed
  with a warning guard instead of aborting the whole install.
- vim plugins actually install now: the round-1 `</dev/null` guard made
  `vim +PlugInstall` deterministically die reading input, so vim-only
  machines (every Linux box - neovim is Brewfile-only) silently got zero
  plugins. install.sh now pre-seeds vim-plug and uses the ex-mode recipe
  (vim -e -N -u vimrc --not-a-term -c 'PlugInstall --sync'), verifies
  plugged/ is non-empty, and compile_coc_nvim no longer claims success
  when it skipped a half-cloned coc.nvim. Verified: 10/10 plugins land
  in a fresh HOME (was 0/10).

Hooks (all verified by staged-file reproduction):
- Conflict-marker and generated-file checks no longer silently pass
  files larger than the pipe buffer (grep -q early-exit SIGPIPEs git
  show, which pipefail turned into "no match"); single full-input grep
  with captured output instead.
- basename -- handles dash-leading filenames (a staged "-sneaky.pem"
  bypassed the secret check); secret list extended (id_dsa/ecdsa/
  ed25519_sk, *.p8, *.jks, *.keystore, .netrc, .pgpass).
- Lockfiles (Cargo.lock, poetry.lock, yarn.lock, ...) are allowlisted -
  their generated-by headers blocked every lockfile commit in every repo.
- Repo-hook delegation (.husky etc.) gets an explicit trust switch:
  git config jm.hooks.runRepoHooks false disables running
  repo-controlled code in untrusted clones (default stays on).

Portability and configs:
- .zshrc shell-functions glob gets the (N) null-glob qualifier (zsh
  aborted mid-rc when the dir was empty, skipping kctx and .zshrc.local).
- .gnu_aliases only evals dircolors when a real binary exists (macOS
  without coreutils printed an error on every shell startup).
- Sway config had a literal @sysconfdir@ autotools placeholder, so
  /etc/sway/config.d drop-ins never loaded.
- Waybar docker/k8s modules poll every 30s (was 10s) and only when
  dockerd runs / a kube-context is set (exec-if), instead of
  unconditionally at every desktop startup.
- Shared ssh github.com block drops IdentitiesOnly so a machine missing
  the pinned key falls back to agent keys instead of bricking GitHub
  access; ForwardAgent trade-off documented in the README.
- Arch kitty overlay goes through install_file (backup + audit + dry-run
  symmetry) and manjaro is treated like arch everywhere.

Docs made truthful: shell-functions README rewritten around the 5 active
files vs 11 disabled stubs, CLAUDE.md no longer points at a
~/MACHINE-STATE.md nothing creates (and drops the machine-specific repo
path), color-linux-box.md gets the historical status header, arch README
documents the opt-in pacman hook substitution, quick-install wording
matches what it does, refresh-machine-state.sh detects alpine.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The big ones:
- vim plugins genuinely install on vim-only machines now: vim-plug
  cannot run in ex mode (E31, installs nothing - the nvim pass on this
  laptop had been masking it by sharing ~/.vim/plugged), so headless
  installs allocate a pty via script(1) (BSD and util-linux forms).
  When nvim is present the vim invocation is skipped entirely; both
  paths report installed-vs-declared plugin counts instead of a
  non-empty-dir guess, vim-plug downloads atomically (a truncated
  plug.vim could previously never heal), and compile_coc_nvim warns
  when coc.nvim was requested but never cloned. Verified: 9/9 plugins
  in a fresh vim-only HOME.
- install_file replaces symlinked ancestors that resolve into the repo:
  a legacy ~/.vim -> repo/.vim symlink previously made the installer
  DELETE the repo's own files and copy sources onto themselves - this
  is the exact migration path both real machines could hit. Verified
  against a repo copy: symlink becomes a real dir, repo untouched.
- quick-install.sh / ssh-copy-dotfiles.sh / minimal-bashrc.sh installed
  a gitconfig whose core.hooksPath pointed at a directory they never
  populated, silently disabling ALL git hooks (including repo husky
  hooks) on machines set up that way. All three now install the hooks;
  quick-install also detects SSH sessions for server configs.
- install_ai_context no longer clobbers a user-curated ~/.claude/
  CLAUDE.md (seeded only when absent), skips minimal mode along with
  the sudo-askpass helper, and covers rhel/centos.

Hooks: the jm.hooks.runRepoHooks off-switch now honors git boolean
spellings (0/no/off previously failed open on the security control);
documented in both READMEs.

Desktop: rofi theme actually loads (new config.rasi - nothing
referenced theme.rasi), sway screenshot binding invokes grim/slurp
instead of a nonexistent sshot (grim+slurp added to packages.list),
sway's literal @sysconfdir@ include fixed, spotify.sh paused/stopped
branches were command invocations not assignments (+bash shebang for
its [[ ]]), storage-workspace.sh no longer hardcodes /home/jm and
hides cleanly when the mount is absent, dead files removed
(sway/key-bindings, waybar cpu-graph.sh, docker-k8s.py - nothing
referenced them), GTK's Nordic theme noted as AUR, pacman hook runs
refresh as the owning user via runuser (root-owned repo files
otherwise), version_of passes multi-flag commands correctly.

Also: neovim added to all Linux package lists (README promised
Neovim-first; only the Brewfile delivered it), ui-features.vim is
actually sourced (installed but dead), .bashrc.server gets the
.bashrc.local hook, nvim dry-run preview matches the real steps,
install.sh header tells the truth, README file table covers vim/nvim/
askpass, minimal-mode behavior documented, combined-plan.md gets its
historical banner.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@woud420
woud420 merged commit afc41d4 into master Jul 10, 2026
8 checks passed
@woud420
woud420 deleted the converge/jm-home-box-laptop branch July 10, 2026 11:31
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