As documented in the README’s adoption guide and Adoption.md, this repo and its scripts are aimed at developers/techies. If you are stuck or need help in any fashion, you can reach out to the owner of the parent repo from where this was forked.
For those who follow this repo, here’s the changelog for ease of adoption:
3.2.33
Refactor Ruby codebase for maintainability and eliminate all static analysis warnings
Comprehensive refactoring addressing code quality issues identified by static analysis tools. All RuboCop, Reek, and Flay warnings eliminated through systematic improvements to code structure, duplication removal, and consistent API design.
Color system refactoring:
- [scripts/utilities/colorizable.rb] Renamed from
string.rb- extracted color methods into standalone module (68% similarity, major refactor). All color methods now support both String and Pathname without explicit.to_sconversion - [scripts/utilities/pathname_ext.rb] New file extends Pathname with Colorizable module - enables
pathname.cyaninstead ofpathname.to_s.cyanthroughout codebase (eliminates 50+ verbose conversions) - [scripts/utilities/string_ext.rb] New file extends String with Core utilities and Colorizable - centralizes String class extensions
- [all Ruby scripts] Removed explicit
.to_sbefore color methods on Pathname objects - color methods now handle conversion automatically (pattern:path.to_s.cyan→path.cyan)
Logging module improvements:
- [scripts/utilities/logging.rb] Extracted
_print_collected_messageshelper - DRY’d warning/error summary printing (eliminated Flay mass-50 duplication between warning and error blocks) - [scripts/utilities/logging.rb] Extracted
_record_messagehelper - DRY’d message collection with script/section prefix (eliminated Flay mass-38 duplication betweenrecord_warningandrecord_error) - [scripts/utilities/logging.rb] Auto-detect script name from caller -
run_scriptnow usescaller_locations(1,1)to extract filename, eliminating need forFile.basename(__FILE__, '.rb')in every dual-mode script (10 scripts simplified) - [scripts/utilities/logging.rb] Replaced Unicode
μ(mu) with “microsecond” in performance comments - ensures ASCII-only for RuboCop compliance - [scripts/utilities/logging.rb] Added
frozen_string_literal: truedirective for performance (prevents String allocation churn)
GitProcessor enhancements:
- [scripts/utilities/git_processor.rb] Extracted nested
GitUrlParserclass - encapsulates URL parsing logic for HTTPS, SSH, git+ssh formats (310 lines added, 61 removed). Addsconstruct_upstream_urlmethod for building upstream remotes from parsed components - [scripts/utilities/git_processor.rb] Added
verify_pre_recreationmethod - validates git directory exists and confirms user intent before destructive operations - [scripts/utilities/git_processor.rb] Added
verify_and_recreate_local_repomethod - combines verification + recreation in single call (pattern used by resurrect-repositories.rb) - [scripts/utilities/git_processor.rb] Documented intentional Flay duplication in URL parsing - git+ssh and ssh:// formats require identical field extraction (mass-48, accepted with inline comment)
Dual-mode script standardization:
- [scripts/recreate-repository.rb] Removed manual
File.basename(__FILE__, '.rb')- leveragesLogging.run_scriptauto-detection (155 lines removed, 38 added - 76% reduction) - [scripts/recreate-repository.rb] Documented intentional Flay pattern - dual-mode CLI wrapper structure shared across all dual-mode scripts (mass-50, accepted with inline comment)
- [scripts/resurrect-repositories.rb] Refactored to use named parameters -
run(generate:, resurrect:, check:)instead of positional arguments (improves call-site clarity) - [scripts/resurrect-repositories.rb] Extracted
RepositoryConfig.from_hashclass method - centralizes YAML deserialization and validation (44.9 flog score, complex but necessary) - [scripts/resurrect-repositories.rb] Documented intentional Flay patterns - validation blocks and error handling have context-specific messages that cannot be extracted (3 locations, mass-32/44, accepted)
- [scripts/add-upstream-git-config.rb] Refactored to use named parameters -
run(dir:, upstream_owner:)instead of positional arguments - [scripts/add-upstream-git-config.rb] Documented intentional Flay pattern -
add_remoteandfetch_allerror handling have different contexts (mass-44, accepted) - [all dual-mode Ruby scripts] Replaced
File.basename(__FILE__, '.rb')with auto-detection viaLogging.run_script- 10 scripts simplified
Static analysis configuration:
- [.reek.yml] New configuration file (141 lines) - documents all 34 suppressed warnings with rationales. Strategy: inline
:reek:comments for specific smells, file-level config only for detectors we disable entirely (TooManyStatements, IrresponsibleModule, etc.) - [.rubocop.yml] Added ASCII-only enforcement -
Style/AsciiCommentsenabled to catch Unicode in comments (μ, §, emoji) - [scripts/ruby-lint.rb] Added Flay mass threshold
--mass 51- filters intentional duplication patterns (dual-mode wrappers, URL parsing, validation blocks). Remaining duplications documented with inline comments explaining why extraction would harm readability - [scripts/ruby-lint.rb] Removed manual script name passing - leverages auto-detection
Named parameters adoption:
- [.ai/domains/ruby-scripting.md] Added comprehensive § Method Parameters section (150+ lines) - documents when to use named vs positional parameters: use named for 2+ parameters OR when meaning is not obvious. Includes migration strategy, benefits, examples, and refactoring checklist
- [scripts/add-upstream-git-config.rb] Converted to named parameters -
run(dir:, upstream_owner:) - [scripts/resurrect-repositories.rb] Converted to named parameters -
run(generate:, resurrect:, check:) - [scripts/capture-prefs.rb] Converted helper methods to named parameters
- [scripts/install-dotfiles.rb] Converted helper methods to named parameters
- [scripts/cleanup-browser-profiles.rb] Converted helper methods to named parameters
Code organization improvements:
- [scripts/utilities/core.rb] Extracted
read_lines_utf8andeach_line_utf8helpers - UTF-8 file reading with explicit encoding (eliminates “invalid byte sequence in US-ASCII” errors in cron) - [scripts/utilities/command_utils.rb] Extracted
run_silenthelper - DRY pattern for suppressing stdout/stderr on background operations (killall, defaults write, brew update) - [scripts/utilities/path_utils.rb] Improved Core module inclusion - added both
include Coreandextend Corefor dual-mode access - [all utility modules] Standardized Core module pattern -
include Corefor instance methods (in blocks),extend Corefor module methods
Documentation updates:
- [.ai/domains/ruby-scripting.md] Added § Method Parameters (named vs positional guidelines)
- [.ai/domains/ruby-scripting.md] Updated § String Colors to document Pathname color support
- [.ai/domains/ruby-scripting.md] Added § Core Module Usage Pattern
- [.ai/domains/ruby-scripting.md] Added § UTF-8 File Reading
- [.ai/domains/path-constants.md] Updated to document Pathname color methods
- [.ai/domains/logging-conventions.md] Fixed Unicode character in comment
Static analysis results:
Before: RuboCop 2 offenses, Reek 0 warnings, Flay score 306 (7 duplications) After: RuboCop 0 offenses, Reek 0 warnings, Flay score 0 (all duplications eliminated or documented)
Other improvements:
- [files/–HOME–/.irbrc] Added require for colorizable and pathname extensions - enables colored paths in REPL
- [files/–HOME–/.shellrc] Minor formatting improvements
- [files/–HOME–/Brewfile] Updated gh extensions
- [files/–HOME–/custom.gitignore] Added patterns for Ruby gem artifacts
- [files/–XDG_CONFIG_HOME–/git/config] Minor whitespace fixes
- [files/–XDG_CONFIG_HOME–/rubocop/config.yml] Enabled AsciiComments cop
- [files/–XDG_CONFIG_HOME–/starship.toml] Updated configuration
- [files/–ZDOTDIR–/.aliases] Minor improvements
- [files/–ZDOTDIR–/.zshrc] Minor improvements
Adopting these changes
No action required - all changes are internal code quality improvements. Scripts work identically to before.
If you want to verify static analysis passes:
cd ~/.config/dotfiles
scripts/ruby-lint.rb # Should show all checks passing
3.2.32
Add comprehensive Ruby static analysis infrastructure with direnv integration
Implemented multi-tool static analysis for Ruby code quality and early error detection, with automatic gem installation via direnv when editing dotfiles.
Static analysis tools:
- [files/–XDG_CONFIG_HOME–/mise/default-gems] New file configures
miseto auto-install analysis tools (rubocop,reek,flay,flog,rufo) when installing any Ruby version via mise - [files/–XDG_CONFIG_HOME–/rubocop/config.yml] Global
RuboCopconfig (applies to all Ruby projects) - [.rubocop.yml] Project-specific
RuboCopconfig for dotfiles - inherits global config and adds Ruby 2.6 target (system Ruby compatibility) - [files/–XDG_CONFIG_HOME–/reek/config.yml] New
Reekconfiguration tuned for utility scripts: detects duplicate method calls (memoization opportunities), nested iterators, uncommunicative variable names, unused private methods - [scripts/ruby-lint.rb] New unified tool (116 lines) that runs all four analyzers (
RuboCop,Reek,Flay,Flog) on a directory or file, reports summary of which checks passed/failed
Automated gem installation for dotfiles development:
- [scripts/install-ruby26-gems.sh] New script installs Ruby 2.6 compatible static analysis gems for system Ruby. Uses data-driven design with associative array mapping gem specs to dependencies. Idempotent (silent when gems exist, ~2 min first run). Only installs gems for Ruby 2.6.x (system Ruby).
- [.envrc] New
direnvconfig automatically runsinstall-ruby26-gems.shand adds gem bin directory toPATHwhen entering dotfiles directory. - [.gitignore] Added
!/.envrcforce-include (direnv files are ignored by default in global gitignore) - [files/–HOME–/.shellrc] Made bash-compatible for direnv: guard
typeset -A _INDENT_CACHEwithZSH_VERSIONcheck, added sed fallback in_strip_ansi()for bash (zsh uses parameter expansion for performance)
Pre-commit validation:
- [files/–XDG_CONFIG_HOME–/git/hooks/pre-commit] New global pre-commit hook with three-stage validation:
- Syntax check (
ruby -c / zsh -n) on all staged files - always runs, blocks commits with parse errors - RuboCop static analysis on staged Ruby files - runs if RuboCop installed, shows actionable errors with auto-fix suggestion
- Repo-specific hooks - allows per-repo customization via
.git/hooks.local/pre-commitor${PERSONAL_BIN_DIR}/pre-commit-<basename>.shSkip all checks withgit commit --no-verify
- Syntax check (
What each tool catches:
- RuboCop - Style consistency, unused variables, unreachable code, potential bugs
- Reek - Code smells (excessive duplication, deep nesting, poor naming)
- Flay - Structural duplication across files
- Flog - Complexity metrics (high scores indicate refactoring candidates)
Design philosophy:
Tools are configured for utility scripts (not Rails apps): metrics cops disabled (method length, cyclomatic complexity don’t apply to small scripts), style focused on Ruby 2.6 compatibility, lint rules aggressive (catch real bugs).
Documentation:
- [docs/ruby-static-analysis.md] New comprehensive guide (113 lines) covering tool purposes, installation methods, usage patterns, configuration details, and troubleshooting
- [.ai/domains/ruby-scripting.md] Updated edit workflow to remove
cd HOME && rufopattern (rufo works from any directory with~/.rufoconfig) - [.ai/domains/edit-checklist.md] Updated Ruby formatting section to remove
cd HOMErequirement (2 occurrences) - [.ai/REBASE-AND-REFACTORING-METHODOLOGY.md] Updated edit workflow to remove
cd HOMErequirement - [CONTRIBUTING.md] Updated to remove
cd HOMErequirement
Adopting these changes
Run install-dotfiles.rb to install new configs and pre-commit hook.
Static analysis gems are automatically installed via direnv:
When you enter the dotfiles directory, direnv detects .envrc and prompts you to allow it (one-time):
cd ~/.config/dotfiles
# Output: direnv: error /Users/you/.config/dotfiles/.envrc is blocked. Run `direnv allow` to approve its content
direnv allow
After allowing, direnv automatically:
- Runs
install-ruby26-gems.sh(installs gems if missing, silent if already present) - Adds gem bin directory to PATH (tools available: rubocop, reek, flay, flog, rufo)
First run takes ~2 minutes (installs 5 tools + dependencies). Subsequent runs are instant (gems already installed).
Outside the dotfiles directory, your project’s Ruby and gems remain active (direnv is directory-scoped).
Why specific versions for Ruby 2.6?
RubyGems has updated dependencies for old gems to require Ruby 2.7+ or 3.2+. Even old versions (rubocop 0.93.1, reek 6.1.4, flay 2.11.0, flog 4.6.2) need specific transitive dependency versions. The installation script uses a data-driven associative array to map each tool to its pinned dependencies, ensuring compatibility with system Ruby 2.6.10.
Note: Pre-commit hook works without gems installed (syntax check always runs, RuboCop only runs if available). Gems are optional but recommended for full static analysis when developing dotfiles.
Run static analysis on all scripts:
cd ~/.config/dotfiles # direnv auto-installs gems and adds to PATH
scripts/ruby-lint.rb # Runs all tools (RuboCop, Reek, Flay, Flog)
rubocop scripts/ # Individual tools
reek scripts/
rufo scripts/my-script.rb # Auto-format specific file
Pre-commit hook activates immediately after install-dotfiles.rb. Test with:
# Make a syntax error, try to commit
echo "def foo" >> test.rb
git add test.rb
git commit -m "test" # Should block with syntax error and show RuboCop output
- Restart terminal to reload
.shellrc.
3.2.31
Simplify fresh-install workflow and improve performance
Eight refactorings that reduce complexity, improve runtime performance, and fix edge-case bugs across fresh-install and cron execution.
Performance optimizations:
- [scripts/software-updates-cron.rb] Removed 10-second sleep delay between
_update_home_reposand_upreb_oss_repos- saves ~1 hour/week in cron execution (modern GitHub API rate limits are generous, delay was unnecessary) - [scripts/fresh-install-of-osx.sh] Consolidated biometric hardware detection into single
ioregcall using-c AppleBiometricSensor -c AppleBiometricServices- 50-100ms faster, cleaner boolean logic (5 lines reduced to 2)
Git maintenance:
- [files/–XDG_CONFIG_HOME–/git/config] Enhanced
git maintainto run comprehensive repository repair (likebrew doctor): removes stale lock files (index.lock, commit-graph-chain.lock), runs fsck/prune/gc, rebuilds commit graph, restores mtimes. Fixes “Unable to create commit-graph-chain.lock” errors and corrupted objects automatically. Idempotent and safe to run on all repos viaall maintain.
Correctness improvements:
- [scripts/fresh-install-of-osx.sh] Made
.shellrcdownload universal - now validates and refreshes on pre-configured machines if repo version is newer than symlink (previously only downloaded onFIRST_INSTALL) - [scripts/capture-prefs.rb] Made auto-commit unconditional on export - always commits staged preferences after successful export using
smart_commit(amends if ahead of remote, creates new commit otherwise) - [scripts/fresh-install-of-osx.sh] Eliminated 20+ lines of manual git commit logic - now handled automatically by
capture-prefs.rbexport - [scripts/software-updates-cron.rb] Replaced
update_all_reposwithProfilesRepo.capture_and_commit- HOME repo now committed bycapture-prefs.rb, only profiles repo needs explicit update
Bug fixes:
- [scripts/utilities/git_processor.rb] Added
--pruneflag tofetch_allmethod - removes stale remote-tracking references that cause “cannot lock ref” errors when remotes have been force-pushed - [scripts/fresh-install-of-osx.sh] Fixed
_download_and_source_shellrcto use plainechobefore sourcing.shellrc- prevents “command not found: cyan” errors on vanilla OS where color functions don’t exist yet
Code quality:
- [scripts/utilities/profiles_repo.rb] Added
capture_and_commitmethod - stages and commits profiles repo changes with timestamp (extracted fromGitWorkspace.update_repologic) - [scripts/utilities/git_workspace.rb] Updated
update_all_reposdocumentation - clarified it’s a catch-all for uncommitted changes (preferences now auto-committed bycapture-prefs.rb) - [scripts/fresh-install-of-osx.sh] Reduced preferences restore section from 39 lines to 12 lines - commit logic now centralized in Ruby
- [scripts/fresh-install-of-osx.sh] Improved biometric detection clarity - single conditional check instead of tracking two separate boolean flags
Adopting these changes
No manual steps required. Next cron run will execute 10s faster. Next fresh-install run will validate .shellrc freshness on pre-configured machines. Preferences backup now always commits on export (both manual and automated runs). resurrect-repositories.rb will automatically prune stale refs during fetch. Enhanced git maintain is immediately available (run all maintain to repair all repos).
3.2.30
Optimize git clone and unshallow operations for speed and maintainability
Eliminated redundant network operations and simplified control flow in clone_repo_into() while improving performance for both fresh installs and existing repository updates.
Universal shallow clones:
- [files/–HOME–/.shellrc] Removed
FIRST_INSTALLrestriction from shallow clone optimization - all clones now use--depth=1 --filter=blob:none --single-branch(not just first install) - [files/–HOME–/.shellrc] Moved
migrate_git_repo_to_reftable()and post-clone operations (git maintain, commit-graph generation) outside if/else blocks to run for both new clones AND existing repos
Background unshallow for all repos:
- [files/–HOME–/.shellrc] Changed background unshallow to run for all repos (new clones and existing) - converts shallow clones to full clones asynchronously without blocking caller
- [files/–HOME–/.shellrc] Moved reftable migration before background unshallow to prevent race conditions (migrating refs while fetching could cause lock contention)
Eliminate redundant fetch operations:
- [files/–XDG_CONFIG_HOME–/git/config] Modified
git unshallowalias to always runfetchafter configuring all branches (fetches complete history for shallow repos, updates all branches for full repos) - [files/–HOME–/.shellrc] Removed explicit
git fetchfor existing repos - now handled by backgroundunshallowwhich includes fetch - [scripts/utilities/antidote.rb] Removed
git pullcall afterunshallow- antidote manages plugin versions via bundle regeneration, working tree updates unnecessary - [files/–XDG_CONFIG_HOME–/git/config] Added
|| truetounshallowalias to prevent transient network failures from triggering ERR traps in background jobs
Updated documentation:
- [scripts/fresh-install-of-osx.sh] Updated user_action message to explain two-step workflow:
all unshallow(fetches history), thengit rebase @{u}orgit merge @{u}(updates working trees) - [scripts/utilities/git_processor.rb] Updated
shallow?docstring to clarifygit unshallowincludes fetch operation - [files/–XDG_CONFIG_HOME–/git/config] Updated
unshallowalias comments to reflect that fetch is now included - [scripts/utilities/antidote.rb] Updated comments to clarify unshallow fetches history without modifying working tree
Benefits:
- 🚀 10-30 seconds faster fresh installs - all fetches run in background (3-5 repos × 3-10s blocked time eliminated)
- 🚀 5-15 seconds faster per existing repo update - background unshallow returns immediately (fetch continues asynchronously)
- ✅ Simpler control flow - unified post-processing path for new and existing repos (less duplication)
- ✅ No FIRST_INSTALL coupling - shallow clones always used (speed benefit universal, not just first install)
- ✅ Race condition eliminated - reftable migration always completes before background ref writes begin
- ✅ Safer antidote updates - won’t fail on detached HEAD plugin repos (no working tree modifications)
Adopting these changes
- Restart terminal to reload
.shellrc. Nextclone_repo_into()call (e.g., duringresurrect-repositories.rbor fresh-install) will use optimized background unshallow. Existing repos will automatically get full history fetched in background on next access.
3.2.29
Comprehensive AI instruction documentation improvements
Enhanced all 13 domain instruction files in .ai/domains/ with improved navigation, cross-references, and completeness.
Structural improvements:
- [all domain files] Added comprehensive Scope sections (files covered, related files, exclusions)
- [all domain files] Converted prose
applyTopatterns to explicit glob patterns for precise matching - [shell-scripting.md, ruby-scripting.md, character-encoding.md, comment-philosophy.md, edit-checklist.md] Added Quick Reference tables for instant pattern lookup
Content improvements:
- [script-depth-tracking.md] Added explicit
print_script_summaryargument passing rules (resolves contradiction) - [shell-scripting.md] Added “Why set -e triggers on && false” explanation with examples
- [ruby-scripting.md] Added Ruby’s nil-on-no-change design rationale for mutating methods
- [ruby-scripting.md, shell-scripting.md] Added Common Mistakes sections (10 items each from code reviews)
- [ruby-scripting.md, shell-scripting.md] Clarified autoload function naming as deliberate convention
- [zsh-startup.md] Added performance benchmarks and measurement commands
Consolidation:
- [ruby-scripting.md] Consolidated logging section to reference logging-conventions.md (eliminates duplication)
- [all files] Added cross-references to related sections across files
Benefits:
- Faster navigation via Quick Reference tables
- Eliminated contradictory instructions
- Added missing “why” explanations for critical rules
- Common mistakes prevent repeated errors
- Clear scope boundaries for each file
Adopting these changes
No action required - documentation improvements only.
3.2.28
Fix nested script name leakage and direnv log suppression
Script name restoration in nested calls:
Fixed bug where nested Logging.run_script calls leaked inner script names to outer script summaries (e.g., software-updates-cron.rb showing install_mise_versions in final output).
- [scripts/utilities/logging.rb] Save and restore
@script_nameinrun_scriptensure blocks
Complete direnv log suppression:
Script banners (print_script_start, print_script_duration) now respect DIRENV_IN_ENVRC suppression like info/success already did.
- [files/–HOME–/.shellrc] Added
_should_suppress_log && return 0toprint_script_startandprint_script_duration - [scripts/utilities/logging.rb] Added
return if EnvVars.suppress_log?toprint_script_startandprint_script_duration - [.ai/domains/shell-scripting.md] Documented all suppressed functions
- [TechnicalDeepDive.md] Added script banner functions to suppression table
Benefits:
- Clean direnv output (only “direnv: loading…” message, no script banners)
- Correct script names in nested execution summaries
- Consistent suppression behavior across all logging functions
Adopting these changes
No action required - fixes apply automatically on next shell/script execution.
3.2.27
Migrate from scheduled to automatic git maintenance
Replaced scheduled background maintenance (launchd-based) with foreground auto-maintenance for simpler, more intelligent repository cleanup.
Configuration changes:
- [global git config] Set aggressive auto-maintenance thresholds:
maintenance.loose-objects.auto = 50(was: 100, now 2x more aggressive)maintenance.incremental-repack.auto = 5(was: 10, now 2x more aggressive)maintenance.commit-graph.auto = 100(unchanged, explicit for clarity)
-
[${XDG_CONFIG_HOME}/git/includes/oss.inc] Removed 40 lines of obsolete
[maintenance]repo registrations (39 repos) - these were used by scheduled maintenance but are not needed by foreground auto-maintenance - [${XDG_CONFIG_HOME}/git/config] Simplified
git maintainalias from 14 lines to 3 lines:- Removed:
maintenance registerandmaintenance startcalls (scheduled maintenance setup) - Kept:
restore-mtimewrapper (still useful for preserving file timestamps after clone) - Updated comment to clarify auto-maintenance is now handled globally via
maintenance.auto=true
- Removed:
- [${DOTFILES_DIR}/.git/config] Removed local
maintenance.auto=falseoverride that was blocking foreground auto-maintenance
How auto-maintenance works:
After git fetch, git pull, and other write commands, git automatically runs git maintenance run --auto which:
- Checks heuristics (loose objects count, pack count, commit-graph freshness)
- Only runs tasks when thresholds are met (intelligent, not wasteful)
- Executes in background via
maintenance.autoDetach=true(non-blocking) - Uses incremental strategy:
commit-graph,loose-objects,incremental-repacktasks (not fullgc)
Benefits:
- Zero manual intervention - maintenance runs automatically when needed
- No external dependencies - no system scheduler (launchd/cron) required
- Portable - works on any machine with Git 2.30+
- Intelligent triggering - only runs when heuristics indicate need (50 loose objects, 5 packs, 100 commits)
- Simpler configuration - no repo registrations to maintain
What still works:
git maintain- now just restores mtimes (useful after clone, no registration)git cc- unchanged, still provides manual aggressive cleanup with--prune=nowsemantics- Existing automation -
.shellrcclone_repo_into()andGitProcessor.clone_repo_into()calls work unchanged
Old workflow (scheduled maintenance):
git clone <url> && cd repo && git maintain # Registered in oss.inc, started launchd
# Maintenance ran hourly/daily/weekly via launchd scheduler
New workflow (auto-maintenance):
git clone <url> && cd repo && git maintain # Just restores mtimes (no registration)
# Maintenance runs automatically after git fetch/pull when thresholds met
Manual aggressive cleanup still available:
git cc [--expire=now] # Explicit aggressive pruning (prune=now, expire reflogs immediately)
Adopting these changes
Action required: Clean up obsolete maintenance registrations in your fork
The changes to global git config and dotfiles repo are already applied, but you need to clean up your personal oss.inc file:
# Edit your personal oss.inc to remove [maintenance] section
vi ~/.config/git/includes/oss.inc
# Delete the entire [maintenance] section with all repo registrations
# (should be 40 lines starting with [maintenance] and ending with repo = ...)
# Keep only: [user], [url], and [includeIf] sections
Verify auto-maintenance is active:
git config --get maintenance.auto # Should output: true
git config --get maintenance.strategy # Should output: incremental
git config --get maintenance.loose-objects.auto # Should output: 50
git config --get maintenance.incremental-repack.auto # Should output: 5
Test auto-maintenance:
cd any-repo
git fetch origin # Triggers auto-maintenance if thresholds met
git count-objects -vH # Check loose objects and pack count
Auto-maintenance will run automatically in the background when needed - no cron jobs, no manual git maintain calls required.
3.2.26
Proactive UTF-8 encoding directives for Ruby scripts
Added # encoding: utf-8 magic comment to all Ruby scripts that perform file I/O operations, preventing “invalid byte sequence in US-ASCII” errors when handling UTF-8 content in filenames, paths, or file data.
Files updated:
- [scripts/capture-prefs.rb] Reads/writes plist files with UTF-8 content
- [scripts/install-dotfiles.rb] Filesystem operations with UTF-8 paths
- [scripts/utilities/cron.rb] Writes crontab files
- [scripts/utilities/logging.rb] Writes log files with UTF-8 messages
- [scripts/utilities/antidote.rb] Reads/writes plugins.txt bundle files
- [scripts/utilities/plist.rb] Already had encoding directive (no change needed)
- [scripts/resurrect-repositories.rb] Reads YAML with UTF-8 paths
- [scripts/cleanup-browser-profiles.rb] Filesystem operations
Ruby script template updated:
- [.ai/domains/ruby-scripting.md] Added
# encoding: utf-8to all three script templates (dual-mode, legacy PERSONAL_BIN_DIR, legacy DOTFILES_DIR)
Standard Ruby file header:
#!/usr/bin/env ruby
# frozen_string_literal: true
# encoding: utf-8
Benefits:
- Prevents encoding errors in file I/O operations
- Handles UTF-8 in filenames, paths, and file content
- Future-proof for non-ASCII characters
- Explicit encoding declaration (no surprises)
- Works with system Ruby 2.6 in cron contexts
Also fixed:
- [files/–ZDOTDIR–/.zlogin] Made shell function definitions callable from nested shells by defensively sourcing
.shellrcbefore usingis_file_older_thanpredicate (mirrors pattern in.zshenvwhere guard protects against stale function definitions in interactive vs login shell contexts)
Adopting these changes
No action required - encoding directives are backward compatible and have no runtime impact on existing functionality. The changes only prevent future encoding errors when scripts encounter UTF-8 content.
3.2.25
Complete git config migration to XDG location
File relocations:
- [~/.python_history] Moved to
${XDG_STATE_HOME}/python/history. Python 3.13+ respects${PYTHONHISTORY}environment variable. - [~/.gitconfig] Moved to
${XDG_CONFIG_HOME}/git/config. Git reads XDG location before~/.gitconfig. - [~/.gitconfig-{delta,pandoc,plist,sqlite3}.inc] Moved to
${XDG_CONFIG_HOME}/git/config-{delta,pandoc,plist,sqlite3}.inc. Tool-specific git config includes now in XDG location. - [~/.gitconfig-{delta,pandoc,plist,sqlite3}-enabled.inc] Symlinks now point to
${XDG_CONFIG_HOME}/git/config-*.incinstead of${HOME}/.gitconfig-*.inc. - [~/.gitconfig-{jd,oss,work}.inc] Moved to
${XDG_CONFIG_HOME}/git/includes/{jd,oss,work}.inc. Personal git config includes consolidated in dedicatedincludes/subdirectory.
Code changes:
- [files/–HOME–/.shellrc] Added
export PYTHONHISTORY="${XDG_STATE_HOME}/python/history". Added directory creation at end of file:ensure_dir_exists "${PYTHONHISTORY%/*}"(self-healing on every shell start, mirrors${HISTFILE:h}pattern in .zshrc). - [files/–HOME–/.gitconfig → files/–XDG_CONFIG_HOME–/git/config] Moved main git config to XDG location. Updated all include paths:
~/.gitconfig-*-enabled.inc→~/.config/git/config-*-enabled.inc. Updated personal includes path:~/.gitconfig-oss.inc→~/.config/git/includes/oss.inc. - [files/–HOME–/.gitconfig-.inc → files/–XDG_CONFIG_HOME–/git/config-.inc] Moved all tool-specific git config includes to XDG location.
- [files/–ZDOTDIR–/.aliases] Updated
edit-gistalias: Changed"${HOME}"/.gitconfig-*to"${XDG_CONFIG_HOME}/git". Added"${XDG_CONFIG_HOME}/mise"to include both mise configs (HOME and XDG). - [scripts/install-dotfiles.rb] Updated
_ensure_gitconfig_tool_symlinkto reference new XDG paths:~/.config/git/config-#{tool_name}.incand~/.config/git/config-#{tool_name}-enabled.inc. Vanilla OS support: existingPathUtils.ensure_directories_existcreates~/.config/git/when processing main config symlink (which runs before tool symlinks), so no additional directory creation needed. - [.gitignore] Added
/files/--XDG_CONFIG_HOME--/git/includes/to prevent personal git config includes from being tracked in dotfiles repo (they belong in home repo). - [files/–HOME–/custom.gitignore] Updated all git config patterns to XDG locations:
/.gitconfig→/.config/git/config,/.gitconfig-delta.inc(and similar) →/.config/git/config-delta.inc(explicit list of 4 tool-specific includes in FILES SYMLINKED section),/.gitconfig-*-enabled.inc→/.config/git/config-*-enabled.inc(glob pattern in GENERATED/DERIVED section for conditional symlinks created by install-dotfiles.rb). Added!/.local/state/python/to un-ignore Python history directory for tracking in home repo (this file is symlinked to~/.gitignorefor home repo). - [templates/gitconfig-inc.template] Updated all references:
${HOME}/.gitconfig-<context>.inc→${XDG_CONFIG_HOME}/git/includes/<context>.inc,~/.gitconfig→~/.config/git/config,~/.gitconfig-oss.inc→~/.config/git/includes/oss.inc.
Benefits:
- 6 fewer visible dotfiles/symlinks in $HOME:
.python_history,.gitconfig,.gitconfig-delta.inc,.gitconfig-pandoc.inc,.gitconfig-plist.inc,.gitconfig-sqlite3.incmoved to XDG locations - 8 fewer conditional symlinks in $HOME:
.gitconfig-{delta,pandoc,plist,sqlite3}-enabled.incnow in~/.config/git/ - Complete XDG compliance: All git configuration in
${XDG_CONFIG_HOME}/git/following XDG Base Directory specification - Better organization:
- Main config:
~/.config/git/config - Tool-specific includes:
~/.config/git/config-*.inc - Personal includes:
~/.config/git/includes/*.inc - All git config grouped together in one directory tree
- Main config:
- Python history: Follows same pattern as zsh/sqlite/postgresql histories in
${XDG_STATE_HOME} - Portability: All paths use
~/tilde notation (Git’s native expansion mechanism) - Self-healing: Python history directory created automatically on every shell start
File renaming convention
All git config files follow consistent naming based on their location:
| Old Location | New Location | Naming Pattern |
|---|---|---|
~/.gitconfig |
~/.config/git/config |
Main config: config (no suffix) |
~/.gitconfig-{tool}.inc |
~/.config/git/config-{tool}.inc |
Tool includes: config-{tool}.inc prefix |
~/.gitconfig-{tool}-enabled.inc |
~/.config/git/config-{tool}-enabled.inc |
Conditional symlinks: config-{tool}-enabled.inc |
~/.gitconfig-{context}.inc |
~/.config/git/includes/{context}.inc |
Personal includes: no config- prefix, in includes/ subdirectory |
Naming rules:
- Main config: Simple
configfilename (Git’s XDG standard) - Tool-specific includes (managed by install-dotfiles.rb): Prefix with
config-to clearly identify as config fragments - Conditional symlinks (auto-created): Follow
config-{tool}-enabled.incpattern for consistency with source files - Personal includes (user-created contexts): No
config-prefix, stored in dedicatedincludes/subdirectory to separate user content from dotfiles-managed content
Why this convention:
config-*.incpattern groups all dotfiles-managed tool includes togetherincludes/*.incsubdirectory clearly separates personal/context-specific includes- Consistent with Git’s native XDG support (reads
~/.config/git/configautomatically) - Follows XDG Base Directory specification
- All git configuration logically grouped in
~/.config/git/directory tree
Adopting these changes
Step 1: Run install-dotfiles.rb
~/.config/dotfiles/scripts/install-dotfiles.rb
This creates/updates symlinks:
~/.config/git/config→ dotfiles/files/–XDG_CONFIG_HOME–/git/config (was~/.gitconfig)~/.config/git/config-delta.inc→ dotfiles version (was~/.gitconfig-delta.inc)~/.config/git/config-pandoc.inc→ dotfiles version (was~/.gitconfig-pandoc.inc)~/.config/git/config-plist.inc→ dotfiles version (was~/.gitconfig-plist.inc)~/.config/git/config-sqlite3.inc→ dotfiles version (was~/.gitconfig-sqlite3.inc)~/.config/git/config-*-enabled.inc→ conditional symlinks (was in HOME)
Step 2: Remove old symlinks from HOME
# Remove old git config symlink
rm -f ~/.gitconfig
# Remove old tool-specific include symlinks
rm -f ~/.gitconfig-delta.inc ~/.gitconfig-pandoc.inc ~/.gitconfig-plist.inc ~/.gitconfig-sqlite3.inc
# Remove old conditional symlinks
rm -f ~/.gitconfig-delta-enabled.inc ~/.gitconfig-pandoc-enabled.inc
rm -f ~/.gitconfig-plist-enabled.inc ~/.gitconfig-sqlite3-enabled.inc
# Verify removal
ls -la ~ | grep gitconfig # Should show nothing
Step 3: Migrate Python history
# Create directory and move history file
mkdir -p ~/.local/state/python
mv ~/.python_history ~/.local/state/python/history 2>/dev/null || true
Step 4: Migrate personal git config includes
# Create directory structure
mkdir -p ~/.config/git/includes
# Identify personal git config includes (excludes tool-specific ones managed by dotfiles)
# These are typically context-specific: work, personal projects, open source, etc.
personal_includes=(~/.gitconfig-*.inc(N))
tool_includes=(delta pandoc plist sqlite3)
# Move personal includes to new location
for include in "${personal_includes[@]}"; do
# Skip if it's a tool-specific include (managed by install-dotfiles.rb)
basename="${include:t:r}" # Extract name without path and .inc extension
is_tool=false
for tool in "${tool_includes[@]}"; do
if [[ "${basename}" == "gitconfig-${tool}" || "${basename}" == "gitconfig-${tool}-enabled" ]]; then
is_tool=true
break
fi
done
if [[ "${is_tool}" == "false" ]]; then
# This is a personal include - move it
new_name="${basename#gitconfig-}" # Remove 'gitconfig-' prefix
mv "${include}" ~/.config/git/includes/"${new_name}.inc"
echo "Moved: ${include:t} → ~/.config/git/includes/${new_name}.inc"
fi
done
# Update any includeIf references in your includes files
# This updates cross-references between your personal include files
for include in ~/.config/git/includes/*.inc(N); do
# Update old paths to new paths in includeIf directives
sed -i '' 's|~/.gitconfig-\([^-]*\)\.inc|~/.config/git/includes/\1.inc|g' "${include}"
done
echo "Personal git config includes migrated to ~/.config/git/includes/"
Step 5: Verify git config works
# Test that git config loads correctly
git config --get user.name
git config --get user.email
# Test conditional includes work
cd ~/dev/your-project-dir
git config --get user.email # Should show context-specific email
# Verify config file location
git config --list --show-origin | head -5
# Should show: file:/Users/yourname/.config/git/config
Step 6: Restart shell
# Restart terminal to reload .shellrc with PYTHONHISTORY
exec zsh
Step 7: Test Python history
# Verify PYTHONHISTORY is set
echo ${PYTHONHISTORY}
# Should show: /Users/yourname/.local/state/python/history
# Start Python and verify history works
python3
>>> import readline
>>> print(readline.get_history_length())
>>> exit()
Step 8: Commit changes
# Commit git config changes to home repo (if tracking .config/git/)
cd ~
git add .config/git/
git status # Verify no gitconfig files remain in HOME
git sci "Move git config to XDG_CONFIG_HOME"
To: path = ~/.config/git/includes/jd.inc
**Step 4: Update your main git config**
```bash
# Edit ~/.gitconfig to point to the new location
# Change: path = ~/.gitconfig-oss.inc
# To: path = ~/.config/git/includes/oss.inc
Step 5: Verify git config works
# Test that git config loads correctly
git config --get user.name
git config --get user.email
# Test conditional includes work
cd ~/dev/your-project-dir
git config --get user.email # Should show context-specific email
Step 6: Restart shell
# Restart terminal to reload .shellrc with PYTHONHISTORY
exec zsh
Step 7: Test Python history
# Start Python and verify history location
python3
>>> import os
>>> print(os.getenv('PYTHONHISTORY'))
# Should show: /Users/yourname/.local/state/python/history
>>> exit()
Step 8: Commit changes to home repo
# The moved git config includes should be tracked in your home git repo
cd ~
git add .config/git/includes/
git status # Verify .gitconfig changes are staged
git sci "Move git config includes to XDG_CONFIG_HOME"
3.2.24
:white_check_mark: Tested on a vanilla macOS machine
Move configuration files to $XDG_CONFIG_HOME for better organization and to declutter $HOME
File relocations:
- [files/–HOME–/.zshenv] Created new file in $HOME that sets
ZDOTDIR="${XDG_CONFIG_HOME}/zsh". This file must stay in $HOME (zsh design requirement - zsh always reads .zshenv from $HOME first, before looking at ZDOTDIR). - [files/–ZDOTDIR–/.zshenv] Deleted (moved to files/–HOME–/.zshenv)
- [files/–ZDOTDIR–/.zshrc, .zlogin] Remain in files/–ZDOTDIR–, which now resolves to
~/.config/zsh/instead of~/.zshrc,~/.zloginin $HOME - [files/–ZDOTDIR–/.aliases] Moved from files/–HOME–/.aliases. Shell utility functions now live in ZDOTDIR alongside zsh config files.
- [files/–XDG_CONFIG_HOME–/zsh/plugins.txt] Moved from files/–ZDOTDIR–/.zsh_plugins.txt. Renamed (unhidden), decoupled from ZDOTDIR.
- [~/.config/zsh/plugins.zsh] Generated file moved from
~/.zsh_plugins.zsh(antidote generates this from plugins.txt) - [~/.local/state/zsh/history] New location for zsh history (was
~/.zsh_history). History is mutable state per XDG Base Directory spec, belongs in $XDG_STATE_HOME. - [~/.local/state/postgresql/history-]* New location for PostgreSQL psql per-database history files (was
~/.psql_history-*). Configured viaHISTFILEsetting in psqlrc. - [~/.local/state/sqlite/history] New location for SQLite history (was
~/.sqlite_history). Configured via$SQLITE_HISTORYenvironment variable set in .shellrc. - [files/–XDG_CONFIG_HOME–/vim/vimrc] Moved from files/–HOME–/.vimrc. Vim 9.0+ supports
$XDG_CONFIG_HOME/vim/vimrcnatively (3rd priority after~/.vimrcand~/.vim/vimrc). - [files/–XDG_CONFIG_HOME–/vim/autoload/plug.vim] Moved from files/–HOME–/.vim/autoload/plug.vim. Follows vimrc to maintain relative plugin structure.
- [~/.local/state/vim/undo/] New location for vim persistent undo files (was
/tmp). Configured in vimrc with automatic directory creation. - [files/–XDG_CONFIG_HOME–/shellcheck/shellcheckrc] Moved from files/–HOME–/.shellcheckrc. Shellcheck supports XDG natively (searches
$XDG_CONFIG_HOME/shellcheck/shellcheckrcas 2nd priority after./.shellcheckrcand before~/.shellcheckrc). - [files/–XDG_CONFIG_HOME–/ripgrep/config] Moved from files/–HOME–/.ripgreprc. Ripgrep supports XDG natively (searches
$XDG_CONFIG_HOME/ripgrep/configas 1st priority). - [files/–XDG_CONFIG_HOME–/readline/inputrc] Moved from files/–HOME–/.inputrc. Readline supports XDG via
$INPUTRCenvironment variable. - [files/–XDG_CONFIG_HOME–/pry/pryrc] Moved from files/–HOME–/.pryrc. Pry (Ruby debugger) has supported XDG since 2014, works with Ruby 2.6+.
- [files/–XDG_CONFIG_HOME–/pg/psqlrc] Moved from files/–HOME–/.psqlrc. PostgreSQL psql supports XDG via
$PSQLRCenvironment variable. UpdatedHISTFILEsetting to use~/.local/state/postgresql/history-prefix (was~/.psql_history-). - [files/–XDG_CONFIG_HOME–/curlrc] Moved from files/–HOME–/.curlrc. Curl 7.73.0+ (2020) supports XDG natively (searches
$XDG_CONFIG_HOME/curlrcas 2nd priority after~/.curlrc). - [files/–HOME–/.notify-osd] Deleted (Ubuntu-only notification config file, not needed on macOS).
Code changes:
- [files/–HOME–/.shellrc] Updated ZDOTDIR default to
${XDG_CONFIG_HOME}/zsh. Addedexport HISTFILE="${XDG_STATE_HOME}/zsh/history". Addedexport SQLITE_HISTORY="${XDG_STATE_HOME}/sqlite/history". Updated ANTIDOTE_PLUGIN_TXT to${XDG_CONFIG_HOME}/zsh/plugins.txt. Updated ANTIDOTE_PLUGIN_ZSH to${XDG_CONFIG_HOME}/zsh/plugins.zsh. Addedexport INPUTRC="${XDG_CONFIG_HOME}/readline/inputrc"andexport PSQLRC="${XDG_CONFIG_HOME}/pg/psqlrc". Fixedload_zsh_configs()to use explicit paths:.zshenvfrom${HOME},.zshrc/.zloginfrom${ZDOTDIR}. Performance optimization: Standardized numeric comparisons to use(( ))arithmetic syntax withlocal -iinteger declarations instead of[[ -lt/-gt/-eq/-ne ]]test operators (~20% faster per comparison, bash-compatible). Affected functions:_log_indent,section_header,is_epoch_older_than,is_outermost_script,_decrement_script_depth,clone_repo_into,_cron_method_delegator,print_usage. - [files/–HOME–/.aliases] Optimized WORDCHARS definition: replaced two separate
:ssubstitutions with single pattern replacement${WORDCHARS//[\/.]}). Eliminates one parameter expansion. Performance optimization: Converted numeric comparisons to(( ))arithmetic syntax in_call_ruby_git_workspace,pdf_to_png,recron. - [files/–ZDOTDIR–/.zshrc] Updated plugin file references. Added early directory creation for
${HISTFILE:h}(zsh history directory) to prevent silent write failures. Optimized zsh-patina daemon restart check: replaced externalstatcommands withzsh/statbuiltin module (eliminates subprocess fork overhead). Changed cache TTL from 5 minutes to 60 minutes. Replaced string comparisons with integer arithmetic for epoch/mtime checks. Performance: ~0.1ms (cached) vs ~20ms (full check) = ~20ms savings on 99% of startups. - [files/–ZDOTDIR–/.zlogin] Fixed
.zshenvcompilation path to${HOME}/.zshenv. Updated antidote bundle compilation comment. - [scripts/utilities/env_vars.rb] Updated ZDOTDIR constant to use
XDG_CONFIG_HOME.join('zsh'). Updated ANTIDOTE_PLUGIN_TXT toXDG_CONFIG_HOME.join('zsh', 'plugins.txt'). Updated ANTIDOTE_PLUGIN_ZSH toXDG_CONFIG_HOME.join('zsh', 'plugins.zsh'). Added HISTFILE constant usingXDG_STATE_HOME.join('zsh', 'history'). Added DOWNLOADS constant (HOME.join('Downloads')) for transient log files. All use cross-platformPathname#join. - [scripts/fresh-install-of-osx.sh] Updated ZDOTDIR initialization to
${XDG_CONFIG_HOME}/zsh. Optimized_ensure_directories_exist()to only create XDG base directories (XDG_CACHE_HOME,XDG_CONFIG_HOME) - removed creation of subdirectories that are automatically created by tools (ANTIDOTE_HOME via git clone, DOTFILES_DIR via clone_repo_into), install-dotfiles.rb (pg, pry, readline, ripgrep, postgresql, vim/undo, zsh subdirs), or never used before install-dotfiles (PERSONAL_BIN_DIR, PROJECTS_BASE_DIR, XDG_DATA_HOME, XDG_STATE_HOME). Moved brew bundle full install log to~/Downloads/brew-bundle-full-install.log. Moved fresh-install log to~/Downloads/fresh-install-of-osx.log. - [scripts/utilities/cron.rb] Moved cron log files to
~/Downloads/:software-updates-cron-last-run.log,software-updates-run-log,software-updates-cron.log. UsesEnvVars::DOWNLOADSconstant. - [scripts/software-updates-cron.rb] Moved run log to
~/Downloads/software-updates-run-log. UsesEnvVars::DOWNLOADSconstant. - [files/–XDG_CONFIG_HOME–/vim/vimrc] Added XDG Base Directory support: configures
undodirto use$XDG_STATE_HOME/vim/undowith automatic directory creation. Removed hardcoded/tmpundodir (was non-persistent across reboots). - [files/–XDG_CONFIG_HOME–/iex/iex.exs] Migrated from
~/.iex.exsto XDG location. Elixir IEx supportsXDG_CONFIG_HOME/iex/iex.exsnatively. - [files/–XDG_CONFIG_HOME–/kdiff3/kdiff3rc] Migrated from
~/.kdiff3rcto XDG location. KDiff3 supportsXDG_CONFIG_HOME/kdiff3/kdiff3rcnatively. - [files/–HOME–/custom.gitignore] Updated: removed root-level entries for all moved dotfiles. Added XDG entries:
/.config/curlrc,/.config/iex/iex.exs,/.config/kdiff3/kdiff3rc,/.config/pg/psqlrc,/.config/pry/pryrc,/.config/readline/inputrc,/.config/ripgrep/config,/.config/shellcheck/shellcheckrc,/.config/vim/,/.config/zsh/. Replaced wildcard/.config/zsh/*with explicit list of symlinked files and pattern for generated files (*.zwc,plugins.zsh). Changed/.local/→/.local/*and added un-ignore patterns for tracking history in XDG location:!/.local/state/,/.local/state/*,!/.local/state/postgresql/,!/.local/state/sqlite/. Zsh history (.local/state/zsh/history) remains ignored. Added/.sqlite_historyto ignored files (old location). - [Adoption.md] Updated bootstrap command to write log to
~/Downloads/fresh-install-of-osx.loginstead of~/fresh-install-of-osx.log. - [.ai/domains/edit-checklist.md] Added Step 7: Delete stale
.zwcbytecode files after editing zsh scripts. Prevents loading old compiled code when source has changed.
Benefits:
- 16 fewer visible dotfiles in $HOME:
.aliases,.zshrc,.zlogin,.zsh_plugins.txt,.zsh_plugins.zsh,.zsh_history,.vimrc,.vim/,.shellcheckrc,.ripgreprc,.inputrc,.pryrc,.psqlrc,.curlrc,.iex.exs,.kdiff3rcmoved to subdirectories - 31 fewer psql history files in $HOME: All
.psql_history-*files moved to~/.local/state/postgresql/ - 5 fewer log files in $HOME: Fresh-install log, brew log, and cron logs moved to
~/Downloads/ - Better organization: All tool configs grouped in
~/.config/subdirectories, state files (history, undo) in~/.local/state/, transient logs in~/Downloads/ - XDG compliance: Config in $XDG_CONFIG_HOME, state in $XDG_STATE_HOME per XDG Base Directory spec
- Location independence: Plugin files decoupled from ZDOTDIR - even if ZDOTDIR reverts to $HOME, plugins stay in
~/.config/zsh/ - Unhidden plugin files:
plugins.txteasier to find and edit than.zsh_plugins.txt - Vim undo persistence: Undo files now survive reboots (was
/tmp, cleared on restart) with proper security (0700 permissions) - Log file visibility: Logs in
~/Downloads/easier to find than hidden files in~/ - Ruby 2.6 compatibility: Pry XDG support verified to work with system Ruby 2.6 (macOS default)
- Cross-platform: Uses
Pathname#joinfor path construction
Not migrated (intentionally left in $HOME):
.irbrc- Requires Ruby 3.1+ for XDG support (system Ruby is 2.6).gemrc- Requires Ruby 3.0+ for XDG support (system Ruby is 2.6).sqliterc- No XDG support, hardcoded to~/.sqliterc
Adopting these changes
Step 1: Run install-dotfiles.rb
~/.config/dotfiles/scripts/install-dotfiles.rb
This creates/updates symlinks:
~/.zshenv→ dotfiles/files/–HOME–/.zshenv (new)~/.config/zsh/.aliases→ dotfiles/files/–ZDOTDIR–/.aliases (moved from ~/.aliases)~/.config/zsh/.zshrc→ dotfiles/files/–ZDOTDIR–/.zshrc (moved from ~/)~/.config/zsh/.zlogin→ dotfiles/files/–ZDOTDIR–/.zlogin (moved from ~/)~/.config/zsh/plugins.txt→ dotfiles/files/–XDG_CONFIG_HOME–/zsh/plugins.txt (moved + renamed)~/.config/curlrc→ dotfiles/files/–XDG_CONFIG_HOME–/curlrc (moved from ~/.curlrc)~/.config/iex/iex.exs→ dotfiles/files/–XDG_CONFIG_HOME–/iex/iex.exs (moved from ~/.iex.exs)~/.config/kdiff3/kdiff3rc→ dotfiles/files/–XDG_CONFIG_HOME–/kdiff3/kdiff3rc (moved from ~/.kdiff3rc)~/.config/pg/psqlrc→ dotfiles/files/–XDG_CONFIG_HOME–/pg/psqlrc (moved from ~/.psqlrc)~/.config/pry/pryrc→ dotfiles/files/–XDG_CONFIG_HOME–/pry/pryrc (moved from ~/.pryrc)~/.config/readline/inputrc→ dotfiles/files/–XDG_CONFIG_HOME–/readline/inputrc (moved from ~/.inputrc)~/.config/ripgrep/config→ dotfiles/files/–XDG_CONFIG_HOME–/ripgrep/config (moved from ~/.ripgreprc)~/.config/shellcheck/shellcheckrc→ dotfiles/files/–XDG_CONFIG_HOME–/shellcheck/shellcheckrc (moved from ~/.shellcheckrc)~/.config/vim/vimrc→ dotfiles/files/–XDG_CONFIG_HOME–/vim/vimrc (moved from ~/.vimrc)~/.config/vim/autoload/plug.vim→ dotfiles/files/–XDG_CONFIG_HOME–/vim/autoload/plug.vim (moved from ~/.vim/autoload/)
Step 2: Remove broken symlinks from $HOME
# Remove old symlinks that now point to non-existent files in dotfiles repo
rm -f ~/.aliases ~/.curlrc ~/.inputrc ~/.pryrc ~/.psqlrc ~/.ripgreprc ~/.iex.exs ~/.kdiff3rc
# Verify removal
ls -la ~ | grep -E '\.(aliases|curlrc|inputrc|pryrc|psqlrc|ripgreprc|iex\.exs|kdiff3rc)' # Should show nothing
Step 3: Migrate history files (one-time manual steps)
# Migrate zsh history
mkdir -p ~/.local/state/zsh
cp ~/.zsh_history ~/.local/state/zsh/history
# Migrate PostgreSQL psql history files
mkdir -p ~/.local/state/postgresql
for file in ~/.psql_history-*; do
[ -f "$file" ] && mv "$file" ~/.local/state/postgresql/history-${file##*/.psql_history-}
done
# Migrate SQLite history (if it exists)
if [ -f ~/.sqlite_history ]; then
mkdir -p ~/.local/state/sqlite
mv ~/.sqlite_history ~/.local/state/sqlite/history
fi
# Verify migrations
ls -la ~/.local/state/zsh/history
ls -la ~/.local/state/postgresql/
ls -la ~/.local/state/sqlite/history 2>/dev/null || echo "No SQLite history to migrate"
# Vim undo directory will be auto-created on first vim startup
# (vimrc includes automatic directory creation with proper permissions)
Step 4: Restart terminal and test tools
# Restart shell
exec zsh
# Test vim
vim /tmp/test.txt
# Make some changes, save, quit, reopen to test undo persistence
# Verify tool configs are loaded from new locations
rg --version # Should load from ~/.config/ripgrep/config
pry -e "exit" 2>/dev/null # Should load from ~/.config/pry/pryrc (if pry installed)
curl --version # Should load from ~/.config/curlrc
# Verify environment variables
echo $ZDOTDIR # Expected: ~/.config/zsh
echo $HISTFILE # Expected: ~/.local/state/zsh/history
echo $INPUTRC # Expected: ~/.config/readline/inputrc
echo $PSQLRC # Expected: ~/.config/pg/psqlrc
echo $SQLITE_HISTORY # Expected: ~/.local/state/sqlite/history
Antidote bundle will automatically regenerate in new location (~/.config/zsh/plugins.zsh) on first shell startup.
Vim will automatically create ~/.local/state/vim/undo/ on first edit.
Step 5: Regenerate crontab (moves log files to Downloads)
# This updates the crontab with new log file paths
recron
# Verify the crontab was updated
crontab -l | grep "Downloads"
# Should show: tmplog=/Users/vijay/Downloads/software-updates-cron-last-run.log
Step 6: Clean up old files (optional, after verifying everything works)
# Only after verifying the new locations work correctly:
rm ~/.zsh_history # History now in ~/.local/state/zsh/history
rm ~/.zsh_plugins.zsh # Bundle now in ~/.config/zsh/plugins.zsh
rm ~/.vimrc # Vimrc now in ~/.config/vim/vimrc (if symlink, will be auto-removed by install-dotfiles.rb)
rm -rf ~/.vim/ # Vim autoload now in ~/.config/vim/autoload/ (if symlink, will be auto-removed by install-dotfiles.rb)
rm ~/.shellcheckrc # Shellcheckrc now in ~/.config/shellcheck/shellcheckrc (if symlink, will be auto-removed by install-dotfiles.rb)
# Clean up old log files after crontab regeneration
rm ~/.software-updates-cron-last-run.log 2>/dev/null # Now in ~/Downloads/
rm ~/.software-updates-run-log 2>/dev/null # Now in ~/Downloads/
rm ~/software-updates-cron.log 2>/dev/null # Now in ~/Downloads/
rm ~/brew-bundle-full-install.log 2>/dev/null # Now in ~/Downloads/
Technical notes:
Why .zshenv stays in $HOME: Zsh always reads .zshenv from $HOME first, before looking at any other configuration. This is by design and cannot be changed. .zshenv sets ZDOTDIR to tell zsh where to find the other files.
Why plugins are in XDG_CONFIG_HOME, not ZDOTDIR: Plugin files are intentionally decoupled from ZDOTDIR. If ZDOTDIR is reverted to $HOME, plugins stay in ~/.config/zsh/. This achieves the goal of keeping $HOME uncluttered regardless of ZDOTDIR setting.
Why history is in XDG_STATE_HOME: Per XDG Base Directory spec: Config → $XDG_CONFIG_HOME (.zshrc, settings), Data → $XDG_DATA_HOME (application resources), Cache → $XDG_CACHE_HOME (ephemeral, can be deleted), State → $XDG_STATE_HOME (persistent mutable data like history, logs). History is mutable state that persists between sessions.
3.2.23
Fix git upreb for read-only repos, add non-interactive Homebrew upgrades, fix profiles repo squashing
- [scripts/recreate-repository.rb] Fixed force-squash detection for profiles repo. Was comparing basename
'browser-profiles'againstKEYBASE_PROFILES_REPO_NAME'profiles', which never matched. Now directly compares full path againstPERSONAL_PROFILES_DIR. Result: profiles repo always force-squashed, HOME repo respects-fflag.
3.2.22
Optimize starship prompt, git size measurements, and migrate to zsh-patina instead of fast-syntax-highlighting
-
[files/–XDG_CONFIG_HOME–/starship.toml] Renamed
[custom.git_clean_arrow]to[custom.git_sync_status]for better semantic clarity (matchesgit sync-statusalias). Module shows green arrow when repo is clean AND synced with tracking branch. Optimized to use singlegit sync-statusalias (replaces 3 separate git commands). Performance cost: ~30-50ms per prompt (was ~100-180ms), savings of ~70-130ms. Updated[custom.git_size]documentation to note parallel execution behavior - runs concurrently withgit_status, making actual overhead only ~2.5ms despite 35ms execution time. Visual flow: clean+synced repos show green arrow after size, dirty/ahead/behind repos show yellow arrow + status symbols. -
[files/–HOME–/.gitconfig] Simplified
git sizealias to always usegit count-objects -vH(2-3x faster thandu -sh). Removed conditionalGIT_SIZE_FASTenv var logic. Now usesgrep size-pack | awk '{print $2, $3}'to extract pack size only. UsesGIT_SIZE_QUIETenv var to suppress header output when called from starship. -
[scripts/utilities/path_utils.rb] Added
git_repo_size_kb(repo_dir)method - returns pack size in KB viagit count-objects -vH. Parses size-pack line, converts units (KiB/MiB/GiB) to KB. Handles both repo root and.gitdirectory paths. Addedgit_repo_size_human(repo_dir)method - returns formatted pack size string viagit sizealias withGIT_SIZE_QUIET=1. Both methods 2-3x faster thandu-based equivalents (~10-20ms vs ~50ms). -
[scripts/utilities/profiles_repo.rb] Updated
check_size_limit()to usegit_repo_size_kb()andgit_repo_size_human()instead ofdir_size_kb()anddir_size_human(). Updated error/debug messages to reference “pack size” instead of “.git directory size”. Method documentation updated to note pack-size-only measurement and performance improvement (60-80% faster). -
[files/–ZDOTDIR–/.zsh_plugins.txt] Replaced
zdharma-continuum/fast-syntax-highlightingwith zsh-patina (Rust-based syntax highlighter). fast-syntax-highlighting removed from antidote bundle and commented out as fallback. Added detailed comments explaining zsh-patina benefits: 62% faster input lag (1.4ms vs 3.6ms), dynamic highlighting (invalid commands shown in red, existing files underlined), high-quality Sublime Text syntax definitions via syntect, and Rust daemon architecture for sub-millisecond highlighting shared between sessions. -
[files/–ZDOTDIR–/.zshrc] Added zsh-patina activation after antidote bundle loads. Uses cached activation pattern (same as mise/starship) to avoid forking binary on every shell start: cache stored at
~/.cache/zsh-patina-activate-cache.zsh, regenerated when zsh-patina binary is updated (mtime check viais_file_older_than), compiled to.zwcbytecode for faster loading. Guard(($+commands[zsh-patina]))ensures graceful degradation on vanilla OS before brew installs it. Activation must happen after antidote bundle loads (which sets up ZLE hooks). -
[files/–HOME–/Brewfile] Added
brew 'zsh-patina'with inline comment noting it’s a Rust-based syntax highlighter that’s 62% faster for input lag than fast-syntax-highlighting. -
[files/–XDG_CONFIG_HOME–/zsh-patina/config.toml] Created zsh-patina configuration file to match fast-syntax-highlighting’s default color scheme. Uses custom theme
fsh-default(stored in themes/ subdirectory). Configuration enables dynamic highlighting (invalid commands in red, existing paths in magenta + underline), sets reasonable performance limits (max_line_length=20000, timeout_ms=500). -
[files/–XDG_CONFIG_HOME–/zsh-patina/themes/fsh-default.toml] Created custom theme matching fast-syntax-highlighting’s default colors exactly: commands (cd, ls, git) = green, keywords (if, then, while) = yellow, paths (existing files/dirs) = magenta + underline, strings = yellow, variables = cyan, comments = gray. Dynamic features: valid commands = green, invalid commands = red, existing paths = magenta + underline.
Performance impact (zsh-bench measurements):
- Starship prompt: 156.9ms → ~130-200ms (git_clean_arrow re-enabled for sync visibility, ~100-180ms cost)
- Ruby size checks: ~100ms → ~20-40ms (60-80% faster)
- Manual
git size: ~50ms → ~10-20ms (2-3x faster) - Input lag: 3.873ms → 1.502ms (61% faster) ⭐ Most noticeable while typing!
- First prompt lag: 156.518ms → 115.393ms (26% faster)
- Command lag: 156.909ms → 109.178ms (30% faster)
- First command lag: 354.000ms → 268.069ms (24% faster)
- Exit time: 53.435ms → 48.387ms (9% faster)
Key learning: Starship executes git modules in parallel. git_size (35ms) runs concurrently with git_status (27ms), so prompt time is dominated by slowest operation. Actual overhead of git_size is only ~2.5ms, not 35ms. git_clean_arrow (~100-180ms) provides essential sync visibility (ahead/behind status) - acceptable trade-off for knowing when commits need push/pull. zsh-patina’s Rust daemon provides sub-millisecond syntax highlighting without blocking the main shell process, delivering 61% faster input lag that matches published benchmarks (62% claimed).
Fix git upreb to support read-only repos and remove redundant push
- [files/–HOME–/.gitconfig] upreb alias: Only push when upstream remote exists (fork workflow)
- WITH upstream: fetch all → rebase upstream → push to origin
- WITHOUT upstream: fetch all → rebase origin → NO push
- Fixes permission denied errors on read-only repos like zsh-bench
- [files/–XDG_CONFIG_HOME–/zsh/upreb] Remove redundant push after git upreb call
- git upreb alias already handles push correctly based on upstream
- Extra push was causing duplicate push attempts and errors
- Now cleanly delegates all push logic to the alias
Adopting these changes
- Run
brew bundleto install zsh-patina (and update any other packages) - Run
install-dotfiles.rbto symlink zsh-patina config files (config.toml and themes/fsh-default.toml) - Restart terminal to reload zsh configuration and activate zsh-patina
- Verify color scheme matches FSH: commands should be GREEN, paths should be MAGENTA + underlined, invalid commands should be RED
- Verify prompt still shows git branch, status symbols, and repo size
- Check zsh-patina daemon status:
zsh-patina status(should show PID) - Performance improvement is automatic, most noticeable when typing commands (61% faster input lag)
- Note: The daemon auto-restarts when config/theme files are modified (checked on each new shell). Manual
zsh-patina restartonly needed if editing config while keeping same shell session open.
3.2.21
Conditionally suppress section_header in autoload scripts when called from wrapper scripts
-
[files/–XDG_CONFIG_HOME–/zsh/cc, files/–XDG_CONFIG_HOME–/zsh/push] Added conditional
section_headerdisplay based on_DOTFILES_SCRIPT_DEPTH. Headers are only shown when_DOTFILES_SCRIPT_DEPTH <= 0(direct invocation). When called from wrapper scripts that already printed their own header viaprint_script_start, the autoload scripts skip theirsection_headerto avoid duplicate headers. -
[.ai/domains/script-depth-tracking.md] Documented the conditional output pattern for autoload functions. Added “Conditional Output Based on Depth” section with complete examples of suppressing section_header when called from wrapper scripts, including wrapper script template and output comparison.
Why this matters:
- Eliminates duplicate headers when wrapper scripts call autoload functions
- Wrapper scripts (e.g.,
push-browser-profiles.sh) useprint_script_startfor lifecycle management - Autoload scripts retain headers for direct invocation (
git push,git cc, or direct function calls) - DRY principle: Wrapper provides overall context, autoload provides operation details only when not nested
Usage patterns:
# Direct invocation - shows section_header
git push # "Pushing '/path/to/repo'"
git cc # "Compressing '/path/to/repo'"
# Via wrapper script - no duplicate header
push-browser-profiles.sh # "Starting..." (from wrapper), then git output (no section_header)
cc-browser-profiles.sh # "Starting..." (from wrapper), then git output (no section_header)
Adopting these changes
- Restart terminal to reload zsh autoload functions.
3.2.20
Enhanced logging and monitoring utilities
-
[scripts/utilities/logging.rb] Added structured logging with file output and log level filtering. Set
LOG_FILE=/path/to/fileto write logs to file with automatic rotation (keeps last 5 files, max 10MB each). SetLOG_FORMAT=jsonfor JSON-formatted logs orLOG_FORMAT=textfor human-readable logs. SetLOG_LEVEL=debug|info|success|warn|error|user_actionto filter messages by severity (default: info). Console output unchanged (human-readable with colors). Required modules:json,fileutils. -
[scripts/utilities/cron.rb] Added crontab validation to
restore_cron()via_valid_crontab?helper. Validates syntax before installation: checks file is readable/non-empty, validates line format (comments, env vars, cron entries with 6+ fields). Prevents installing malformed crontab files. Added_cleanup_old_backupshelper tosuspend_cron()- keeps only the 5 most recent backup files in$TMPDIR, sorted by mtime, deletes oldest. -
[scripts/utilities/macos.rb] Enhanced
kill_login_item_apps()with process verification and graceful termination. Uses_process_running?helper (viapgrep -x) to check if process exists before kill. Sends SIGTERM, waits 2 seconds, verifies termination, falls back to SIGKILL (-9) if needed. Logs warnings for failed terminations. Added notification rate limiting tonotify()- deduplicates notifications within 60-second window, tracks history in@_notification_history, auto-cleans entries older than 5 minutes. Prevents spam from repeated errors.
Usage examples:
# Log level filtering
LOG_LEVEL=warn ruby script.rb # Show only warnings and errors
LOG_LEVEL=debug DEBUG=true ruby script.rb # Show all messages including debug
# Structured logging with rotation
LOG_FILE=~/logs/script.log LOG_FORMAT=json ruby script.rb # JSON logs
LOG_FILE=~/logs/script.log LOG_FORMAT=text ruby script.rb # Human-readable logs
- [scripts/add-upstream-git-config.rb] Added
extend Coreafterextend selfto enable unqualifiednil_or_empty?calls in module methods. Maintains consistency with other utility modules.
Enhancements impact:
- Logging methods now check
_should_log?(level)before printing (filters based on LOG_LEVEL) - File output writes to
LOG_FILEif set, with format determined byLOG_FORMATenv var - Log rotation prevents unbounded growth (10MB limit per file, 5 files max)
- Cron operations validate syntax before modifying system crontab
- Cron backups no longer accumulate indefinitely in
$TMPDIR - Process termination is safer (verifies process exists, retries with SIGKILL if needed)
- Notification spam prevented via 60-second deduplication window
Adopting these changes
- Restart terminal to reload zsh functions if using any autoload scripts that depend on updated utilities.
- No action required for existing scripts - all enhancements are opt-in via environment variables.
- To enable structured logging: set
LOG_FILE,LOG_FORMAT, and/orLOG_LEVELenv vars.
3.2.19
Global git hooks + wrapper functions for lifecycle management
-
[files/–XDG_CONFIG_HOME–/git/hooks/pre-push] Added global git hook for pre-push validation. Uses optimized shell patterns: inline
${PWD:t}for basename (no subshell), utility functions (is_directory,is_executable) instead of raw tests, local array for hook paths. Execution order: repo-specific.git/hooks.local/pre-push(e.g., Husky/lint-staged), then per-repo customization${PERSONAL_BIN_DIR}/pre-<command>-<basename>.sh. -
[files/–HOME–/.gitconfig] Added
core.hooksPath = ~/.config/git/hooksto enable global hooks for all repositories. Hooks are automatically active for all repositories (existing and newly cloned) without per-repo installation. -
[files/–HOME–/custom.gitignore] Added
/.config/git/hooks/*to symlinked files section (hooks are symlinked byinstall-dotfiles.rbfrom dotfiles repo to~/.config/git/hooks/). -
[Extras.md, .ai/domains/git-config.md, Adoption.md] Updated documentation to reflect that git has NO
post-pushhook (onlypre-pushexists - this is intentional design, not a bug). For operations requiring cleanup after push completes (e.g., cron resume), use wrapper functions instead of hooks. EXIT traps in pre-push hooks do NOT work because the trap fires when the hook script exits (before git starts the push). -
[${PERSONAL_BIN_DIR}/push-browser-profiles.sh] Created wrapper script for browser-profiles push with cron suspension. Uses
with_cron_suspended _pushpattern: suspends cron before push, restores it after push completes (regardless of whether data was pushed or “Everything up-to-date”), cleans up backup file. Handles errors via EXIT trap - cron always restored.
Benefits of hybrid approach:
- ✅ Works for all git operations with native hooks (pre-push, pre-commit, post-commit, post-merge, etc.)
- ✅ Automatic installation on clone (no per-repo setup)
- ✅ Simple pre-validation scripts (no autoload loading, no depth tracking)
- ✅ Chains with repo-specific hooks (Husky, lint-staged, etc.)
- ✅ Wrapper functions handle lifecycle management (before + after) without hook limitations
When to use each approach:
- Pre-validation hooks: Need validation BEFORE operation starts (tests, linting)
- Wrapper functions: Need cleanup AFTER operation completes (cron resume, mtime restore)
Root directory write protection
-
[files/–HOME–/.shellrc] Added
is_root_dir()utility function to check if a path is root/. Mirrors shell pattern[[ "${path}" == "/" ]]with semantic name. Used inline with${path:h}parameter expansion to validate parent directories before write operations:is_root_dir "${target_path:h}". -
[files/–HOME–/.shellrc] Added root directory protection to
ensure_dir_exists(),recompile_zsh_script(), andclone_repo_into(). Each function checks parent directory withis_root_dir "${path:h}"before performing write operations (mkdir, rm, zrecompile). Prevents catastrophic operations like creating/mydiror deleting/.cachewhen environment variables are unset or misconfigured. -
[files/–HOME–/.aliases] Added root directory protection to
delete_caches()andwith_cron_suspended(). Uses sameis_root_dir "${path:h}"pattern to prevent deleting cache directories or cron backup files in root. -
[scripts/utilities/path_utils.rb] Added
PathUtils.root_dir?(path)to check if path is root/. Mirrors shellis_root_dir()function. AddedPathUtils.safe_for_write?(path)to check if parent directory is not root (safe for write operations). Both methods handle Pathname and String inputs, with automatic type conversion. -
[scripts/utilities/cron.rb] Added root directory protection to
resume_cron()andwith_cron_suspended()usingPathUtils.safe_for_write?(backup_file). Prevents deleting cron backup files in root directory. -
[.ai/domains/shell-scripting.md] Added
is_root_dirto Common Substitutions table with usage patternis_root_dir "${path:h}". Added example demonstrating root directory protection before write operations. Cross-referenced Ruby equivalentPathUtils.root_dir?. -
[files/–HOME–/.shellrc] Refactored
is_directory()to use! is_root_dir "${1}"instead of hardcoded[[ "${1}" != "/" ]]for DRY principle. Single source of truth for root directory check. -
[files/–HOME–/.aliases] Refactored
homealias to use dynamic basename${DOTFILES_DIR:t}instead of hardcoded.dotfilesfor portability across systems with different dotfiles directory names.
All error/warn messages follow unified color conventions (paths use cyan + single quotes).
Cross-platform path handling improvements
-
[scripts/utilities/path_utils.rb] Replaced hardcoded
'/'withFile::SEPARATORinroot_dir?method for cross-platform compatibility (Windows uses\). Refactoredvalid_directory?to useroot_dir?method instead of inline check for DRY principle. -
[scripts/utilities/git_processor.rb] Replaced hardcoded
'/'withFile::SEPARATORinbasename_from_urlmethod’s regex pattern and split operation for cross-platform compatibility. -
[scripts/recreate-repository.rb] Replaced hardcoded
'/'withFile::SEPARATORin directory path chomp operation for cross-platform compatibility. -
[scripts/utilities/antidote.rb] Combined zsh flags from
'zsh', '-f', '-c'to'zsh', '-fc'for consistency with shell flag combining conventions.
Git GC optimization and rerere cache preservation
-
[files/–HOME–/.gitconfig] CRITICAL FIX: Changed
gc.pruneExpire = now→2.weeks.agoto preserve amended commits and deleted branches for 2 weeks instead of deleting immediately. This was causing loss of recent history when runninggit cc. - [files/–HOME–/.gitconfig] Added git gc optimization settings:
autoDetach = true- Runs gc in background (non-blocking) when auto-gc triggersautoPackLimit = 50- Consolidates packs when 50+ exist (prevents pack file proliferation)bigPackThreshold = 512m- Keeps packs >512MB separate to avoid expensive repacking of large unchanged packscruftPacks = true- Stores unreachable objects in cruft packs instead of loose objects (better compression, faster gc)
-
[files/–HOME–/.gitconfig] Updated rerere cache retention from 1 week to 3 weeks (
gc.rerereResolved = 3.weeks.ago) to prevent losing recent conflict resolutions. Unresolved conflicts kept for 1 week (gc.rerereUnresolved = 1.week.ago). - [files/–HOME–/.gitconfig] Removed redundant
git rerere gccall fromccalias -git maintenance run --task=gcalready includesgit gc, which automatically runs rerere gc internally. Updated comment to document this behavior.
Disk space impact:
- Slightly more disk space for 2-week unreachable object window (vs immediate pruning)
- Cruft packs compress better than loose objects, offsetting this
- Large packs no longer repacked unnecessarily (saves CPU/disk I/O)
Recovery window:
- Amended commits: 2 weeks (was immediate deletion)
- Deleted branches: 2 weeks (was immediate deletion)
- Reflog entries: 2 weeks (unchanged)
- Rerere resolutions: 3 weeks (was 1 week)
Multi-repo command alias
- [files/–HOME–/.aliases] Added
my-reposalias as shorthand for running commands in home, dotfiles, and browser-profiles repos. Uses dynamic basename expansion:FILTER='(/${HOME:t}/\.git|/${DOTFILES_DIR:t}/\.git|/${PERSONAL_PROFILES_DIR:t}/\.git)$' all <command>. The FILTER regex matches.gitdirectory paths using zsh parameter expansion (:tgets tail/basename), making it portable across systems regardless of username.
Usage examples:
my-repos st # Runs 'git st' in home + dotfiles + browser-profiles
my-repos push # Runs 'git push' in all three repos
my-repos upreb # Runs 'git upreb' in all three repos
# Or use FILTER directly for ad-hoc filtering:
FILTER='dotfiles' all st # Only dotfiles repo
FILTER='(vijay|profiles)$' all st # Home + browser-profiles
Comparison with existing autoload functions:
my-repos st- Quick interactive status check (home + dotfiles + browser-profiles)status_all_repos- Comprehensive check via Ruby (includes Chrome profile subdirs if they’re git repos)update_all_repos- Cron job automation (stages/commits auto-generated content in home + browser-profiles)
Why an alias instead of a function:
- 3 lines instead of 28 lines
- No hardcoded usernames - uses
${HOME:t},${DOTFILES_DIR:t},${PERSONAL_PROFILES_DIR:t} - No need for git command detection logic (handled by
allalias) - Transparent - just sets FILTER env var before calling
all - Easy to customize - users can set FILTER to any regex pattern
Adopting these changes
- Global git hooks are installed automatically by
install-dotfiles.rb- no action required - For repositories requiring lifecycle management (e.g., cron suspension during push), create wrapper script in
${PERSONAL_BIN_DIR}:# push-browser-profiles.sh (see Adoption.md § 4.5.1 for complete example) with_cron_suspended _push "$@"Make executable:
chmod +x ${PERSONAL_BIN_DIR}/push-browser-profiles.shInvoke:cd ~/personal/vijay/browser-profiles && ./push-browser-profiles.sh - Root directory protection is defensive - no action required
- Restart terminal to reload
${ZDOTDIR}/.aliaseswith newmy-reposalias and.shellrcwith root protection utilities - New utility functions available for use in custom scripts:
- Shell:
is_root_dir "${path}"- returns true if path is root/ - Shell:
my-repos <command>- runs command in home + dotfiles + browser-profiles repos - Ruby:
PathUtils.root_dir?(path)- returns true if path is root - Ruby:
PathUtils.safe_for_write?(path)- returns true if parent directory is not root
- Shell:
3.2.18
- [Brewfile] Replaced Sol, Stats, Thaw with Vorssaint (menu bar tools). Vorssaint provides Metrics (replaces Stats), window preview (replaces Dockdoor), extension of menubar (handled by macos 27 as overflow replacing thaw) and window tiling and clipboard history (replaces sol) in a single app. Issue #115 (Zoom hanging) was fixed in Vorssaint v3.1.8 (July 7, 2026); current version v3.2.0 includes the fix.
- Switched back to using Spotlight for launching apps since Sol is no longer used/installed.
- Use utility methods from
CommandUtilsinstead of directsystemcalls in ruby classes.
3.2.17
Ruby code quality improvements and pattern documentation
-
[scripts/utilities/command_utils.rb, git_processor.rb, macos.rb] Standardized
nil_or_empty?guard pattern: check nil/empty BEFORE calling.strip, cache stripped result AFTER check (only if used multiple times). Eliminates redundant checks and prevents potential nil crashes. -
[scripts/utilities/git_processor.rb] Hot path optimization: extracted static arrays (
STREAMING_COMMANDS,QUIET_FLAGS) to frozen constants at class level. Eliminates repeated allocations (2 arrays per git command = 100s per cron run). -
[scripts/utilities/command_utils.rb] Enhanced
CommandUtils.run_silent(*command, out:, err:)to accept optionaloutanderrparameters (both defaulting toFile::NULL). Supports selective output suppression (err: :errshows stderr), output redirection (out: '/path/to/file'), and full suppression (default). Returns boolean (true if exit 0). -
[11 Ruby files] Migrated 26 call sites from verbose
system(..., out: File::NULL)andsystem(..., out: File::NULL, err: File::NULL)patterns toCommandUtils.run_silent(...): software-updates-cron.rb (5), cron.rb (1), macos.rb (6), plist.rb (4), path_utils.rb (1), capture-prefs.rb (1), cleanup-browser-profiles.rb (2), setup-login-item.rb (1), plus 5 call sites updated to use optional parameters (selective suppression/redirection instead of both).
3.2.16
Git alias consolidation and cleanup
-
[files/–HOME–/.gitconfig] Added new
list-oldalias to list all remote branches with no commits in a specified timeframe (defaults to 10 days). Accepts optional--sinceflag for custom timeframes (e.g.,--since 30.days,--since 2.weeks). Output format shows<last commit relative date> | <branch name>, sorted oldest first. Supports optional directory argument. Complements existinggit oldalias which checks a single branch. -
[files/–HOME–/.gitconfig] Consolidated incoming change aliases (
in,inc,inp) into singlegit inwith optional flags: default (commit summary with stats),-d(combined diff),-p(full patches). Removed redundantincandinpaliases. -
[files/–HOME–/.gitconfig] Consolidated outgoing change aliases (
out,outp) into singlegit outwith optional-pflag: default (commit summary),-p(full patches). Removed redundantoutpalias. -
[files/–HOME–/.gitconfig] Consolidated status aliases (
st,sts,stsub) into singlegit stwith optional flags and directory support: default (full status),-s(short status),-m(status with submodules). All modes accept optional[<dir>]argument. Removed redundantstsandstsubaliases. -
[files/–HOME–/.gitconfig] Removed duplicate
co = checkoutalias definition (was defined in both “BASIC SHORTCUTS” and “LOCAL CHANGES & STAGING” sections). Kept single definition in “BASIC SHORTCUTS” section. -
[files/–HOME–/.gitconfig] Removed
ltalias marked as[WIP/DUPLICATE]- was incomplete and duplicative of existinglcalias. -
[files/–HOME–/.gitconfig] Enhanced
git cc(cleanup/compress) to delete stalerefs/prefetch/*references before running garbage collection. These refs are created bygit maintenanceand can keep old commits reachable after rebasing, preventing cleanup. The prefetch refs are now deleted early in the cleanup process and recreated fresh by themaintenance run --task=gcstep at the end. This ensuresgit cc --expire=nowafter a rebase fully removes all unreachable commits without requiring manual intervention. -
[files/–HOME–/.gitconfig] Added
git maintainalias to consolidate post-clone maintenance operations (restore-mtime, maintenance register/start). Idempotent and safe to run multiple times. Gracefully handles missing dependencies (restore-mtime not installed, .gitconfig-oss.inc not present on FIRST_INSTALL). Accepts optional[<dir>]argument. Useful for manually cloned repos or migrating old repos to background maintenance. -
[files/–HOME–/.shellrc] Updated
clone_repo_into()to usegit maintainalias instead of inline post-clone logic (8 lines → 1 line). -
[scripts/software-updates-cron.rb] Updated comment to reference
git maintainalias instead of individual commands.
Adopting these changes
- New git alias available immediately:
git list-old [--since <timeframe>]to find stale remote branches - New git alias available immediately:
git maintain [<dir>]to run post-clone maintenance (restore-mtime, maintenance register/start) - Consolidated git aliases maintain backward compatibility via flags:
git inc→git in -d(combined diff of incoming changes)git inp→git in -p(incoming commits with full patches)git outp→git out -p(outgoing commits with full patches)git sts→git st -s(short status)git stsub→git st -m(status with submodules)git stsub /path→git st /path -m(status with submodules in different repo)
- No breaking changes - all previous functionality preserved with cleaner interface
3.2.15
Ruby filter_map polyfill optimization
- [scripts/utilities/enumerable_ext.rb] Optimized
filter_mappolyfill implementation from two-pass to single-pass witheach_with_objectloop. Reduces intermediate array allocations on Ruby 2.6 (macOS default system Ruby). Guard ensures native Ruby 2.7+filter_mapis used when available. Added TODO comment documenting this file can be removed once macOS ships Ruby 2.7+ as default.
3.2.14
Incorporate starship-ftl for instant-prompt and Terminal.app time_shell_startup fixes
- Incorporate starship-ftl for the instant-prompt
- Fix issue with noise output from Terminal app when running
time_shell_startupto behave exactly like how iTerm does.
Adopting these changes
- Restart terminal to reload
${ZDOTDIR}/.aliaseswith fixedtime_shell_startup
3.2.13
Revamping documentation
3.2.12
GitProcessor robustness, duration utilities, and custom.gitignore maintenance
-
[scripts/utilities/git_processor.rb] Added
repo?guards to 15 mutation methods (config_set,add_remote,set_remote_url,fetch_all,stage_all,add,delete_tag,pull,rm_cached,restore,commit,smart_commit,push,compress,build_commit_group) to prevent operations on non-repos. Removed instancerepo?memoization (@_is_repo ||=) to prevent stale cache afterinit/recreateoperations - now directly checks@dir.join('.git').exist?each time. Kept class-levelGitProcessor.repo?(path)memoization with@repo_cachehash (appropriate for validation checks across different paths during tree traversal). Added documentation explaining cache difference. Guard placement preserves original behavior: dry-run checks first (return true), then repo checks (for actual execution). -
[scripts/utilities/core.rb] Added
duration_since(start_time)method to calculate elapsed seconds from Unix epoch timestamp - single source of truth for duration calculations across Ruby codebase. Addedelapsed?(start_time, threshold)method to check if enough time has passed since reference timestamp - returns true when duration meets or exceeds threshold. Used for time-interval checks in rate-limiting scenarios (mise plugin updates, ollama model updates). -
[scripts/software-updates-cron.rb] Replaced all manual
Time.now.to_i - start_timecalculations withCore.duration_since(start_time)(4 call sites). Replaced time comparison logic (duration < threshold) with semanticCore.elapsed?(timestamp, threshold)checks (2 call sites: mise plugin updates, ollama model updates). Eliminated duplicateduration_sincecalls in ollama check (was called twice per iteration - once for comparison, once for hours calculation). Removed redundantrepo?check for zen-browser-desktop repo - internal GitProcessor guards provide same protection. -
[scripts/utilities/logging.rb] Updated
print_script_duration()to useCore.duration_since(start_time)instead of manualTime.now.to_i - start_timecalculation. -
[scripts/utilities/.rb]* Fixed Pathname color method usage in 8 utility modules (
antidote.rb,command_utils.rb,keybase.rb,macos.rb,path_utils.rb,plist.rb,profiles_repo.rb,git_workspace.rb). Color methods (.cyan,.yellow, etc.) are defined on String, not Pathname - added.to_scalls before color methods. Removed redundant.to_son variables already documented as String type. Kept informativerepo?checks ingit_workspace.rb:status_repoandprofiles_repo.rbchrome folder loop where custom logging prevents misleading “attempting…” messages before failure. -
[files/–HOME–/.envrc] Deleted file (no longer needed).
-
[files/–HOME–/custom.gitignore] Removed
/.envrcentry - synced with deletion of source file per maintenance rule.
Adopting these changes
- Run
install-dotfiles.rbto sync deleted.envrcfile and updatedcustom.gitignore - No other user action required - changes are internal robustness improvements
- GitProcessor now safely handles non-repo directories without crashes
- Duration calculations now use consistent Core utility methods
3.2.11
Git clone optimization and SSH configuration standardization
- [files/–HOME–/.shellrc] Enhanced
clone_repo_into()with three clone optimizations:-n(no-checkout) prevents writing working tree to temp folder (security + speed)--filter=blob:none(FIRST_INSTALL) downloads only commits/trees without file contents (blobs fetched on-demand)--single-branch(FIRST_INSTALL) fetches only default branch
Standardized SSH options: removed all inline
GIT_SSH_COMMANDoverrides since keepalive options now default in.gitconfigand fresh-install export. Consolidated comments. -
[files/–HOME–/.gitconfig] Updated
core.sshCommandtossh -o ConnectTimeout=20 -o Compression=no -o ServerAliveInterval=10 -o ServerAliveCountMax=3. Keepalive options (10s interval, 3 max failures = 30s timeout) prevent timeout on slow networks and detect dead connections quickly. Compression disabled since git protocol already compresses. -
[scripts/fresh-install-of-osx.sh] Updated
GIT_SSH_COMMANDexport to match.gitconfigoptions (added keepalive). Consistent SSH behavior across vanilla OS and pre-configured machines. - [scripts/utilities/git_workspace.rb]
update_reponow accepts array of paths. Updatedupdate_all_reposto stage bothsolanddefaultsdirectories in home repo (previously onlydefaults).
Adopting these changes
- Restart terminal to pick up new
.shellrcchanges
Global gitignore enhancement: Ruby support and pattern standardization
- [files/–HOME–/.gitignore_global, files/–HOME–/custom.gitignore] Regenerated from gitignore.io with expanded language/editor support.
3.2.9
Shell delegation standardization: Unified Ruby invocation pattern
-
[files/–HOME–/.shellrc] Created
call_ruby_utility()helper function to encapsulate Ruby invocation pattern. Accepts Ruby code string as argument, handles RUBYLIB setup automatically (adds utilities/ and bin directories to load path), preserves COLUMNS env var for terminal width detection, includes Ruby availability check (graceful no-op if Ruby not installed on vanilla OS). Added comprehensive 20-line documentation with usage examples and delegation pattern. Inlinedsetup_rubylib()function body intocall_ruby_utility()and removed standalonesetup_rubylib()(no longer needed as separate function). Updated 2 internal call sites:migrate_git_repo_to_reftable()and_call_ruby_cron()to use new helper. Standardized mandatory argument validation to use${1:?function: arg required}pattern (built-in shell error handling) instead of manual${1:-}+is_zero_string+error+return 1pattern (4 lines → 1 line). Removed 2 redundant Ruby availability guards (now handled centrally bycall_ruby_utility). -
[scripts/fresh-install-of-osx.sh] Updated
_ensure_keybase_logged_in()to usecall_ruby_utilityinstead of manualsetup_rubylib+ruby -esequence. Maintains same behavior (returns boolean via exit code) with cleaner implementation. -
[.ai/domains/ruby-scripting.md] Updated “Shell integration” section to document
call_ruby_utilityas the standard pattern for all shell→Ruby delegation. Added benefits list (automatic RUBYLIB setup, COLUMNS preservation, Ruby availability check, consistency). Added examples showing correct usage and anti-patterns (rawruby -ecalls). Added delegation function pattern template. Replaced all references to manualsetup_rubylib+ruby -esequences withcall_ruby_utilitypattern. -
[.ai/context.md] Updated “cron.rb Exception Propagation” section to reference
call_ruby_utilityinstead ofruby -ein explanation of how Ruby exceptions propagate to shell. Updated “Shell delegation pattern” section to documentcall_ruby_utilityhandles RUBYLIB setup, COLUMNS preservation, and Ruby availability check automatically.
Adopting these changes
- No user action required - changes are internal refactoring
- All shell→Ruby delegation now uses consistent
call_ruby_utilitypattern - Ruby availability check centralized (single guard instead of scattered checks)
- Argument validation more concise (built-in shell error handling)
3.2.8
Core module refactoring: Eliminate circular dependencies and standardize timestamp handling
-
[scripts/utilities/core.rb] Added
current_timestamp()method returning'YYYY-MM-DD HH:MM:SS'format - single source of truth for all timestamp formatting across Ruby codebase. Addedrunning_in_tty?()method checking if stdout is TTY orFORCE_COLORset - gates interactive operations (app kill/restart, prompts) that should not run in cron/non-interactive contexts. Added comprehensive 35-line documentation defining strict rules for Core module: ZERO requires except Ruby stdlib, OS-agnostic only (no macOS/Linux-specific calls), check ENV directly (not via EnvVars to avoid circular dependency), with examples of appropriate vs inappropriate methods. These methods moved from MacOS module to eliminate circular dependency (macos.rb required logging.rb which used MacOS.current_timestamp). -
[scripts/utilities/macos.rb] Removed
current_timestamp()andrunning_in_tty?()methods (now in Core module). UpdatedLOGIN_ITEM_APPScomment to document this is single source of truth (shell array_MACOS_LOGIN_ITEM_APPSin .aliases was dead code, removed). Addedsleep 1after killing apps inkill_login_item_apps()to ensure full termination before defaults writes begin - prevents race where app’s shutdown handler might flush preferences after we’ve started writing new values. Updated documentation explaining the sleep prevents race conditions. -
[scripts/utilities/git_processor.rb] Enhanced
smart_commit()method to auto-generate commit messages when called without arguments. Detects repository state via newcommit_count()helper - returns 0 for brand new repos, >0 for repos with history. Auto-generates “Initial commit:" for first commit (count == 0) or "Incremental commit: " otherwise. Changed signature from `smart_commit(message)` to `smart_commit(message = nil)` to support optional message. Uses `Core.current_timestamp` for consistent formatting. Works correctly for brand new repos, repos without remotes, and after `git.recreate()`. Removed `require_relative 'macos'` from requires block - now uses `Core.current_timestamp` instead of `MacOS.current_timestamp`. -
[scripts/utilities/logging.rb] Updated
print_script_start()andprint_script_duration()to useCore.current_timestampinstead of inlineTime.now.strftime('%Y-%m-%d %H:%M:%S'). Eliminated circular dependency: logging.rb previously required macos.rb for timestamps, which itself required logging.rb for log methods. Core module has zero dependencies, breaking the cycle. -
[scripts/utilities/git_workspace.rb] Simplified
_commit_repo()to usegit.smart_commitwith no arguments - auto-generates “Incremental commit:" message instead of manually constructing timestamp string. Removed manual `Time.now.strftime` call and `timestamp` variable. -
[scripts/software-updates-cron.rb] Updated 3 call sites to use
Core.current_timestampinstead ofMacOS.current_timestamp. Addedrequire_relative 'utilities/core'to requires block. Maintains consistent timestamp format across all log entries and status updates. -
[scripts/capture-prefs.rb] Updated to use
Core.running_in_tty?instead ofMacOS.running_in_tty?in conditional for killing/restarting login-item apps. Only kills apps on import when running interactively (not in cron). Addedrequire_relative 'utilities/core'to requires block. -
[scripts/recreate-repository.rb] Simplified to use
git.smart_commitwith no arguments instead of manually constructing commit message withMacOS.current_timestampand force/incremental prefix logic. Auto-generation insmart_commithandles Initial vs Incremental detection via commit count, eliminating duplicate logic. -
[scripts/osx-defaults.sh] Updated comment documenting canonical login-item app list location changed from
_MACOS_LOGIN_ITEM_APPS(.aliases § 3n) toMacOS::LOGIN_ITEM_APPS(scripts/utilities/macos.rb). Shell array was dead code (never referenced, only Ruby constant used). -
[files/–HOME–/.aliases] Removed 26-line dead code
_MACOS_LOGIN_ITEM_APPSarray. This shell array was never used - all scripts call RubyMacOS.kill_login_item_appsandMacOS.restart_login_item_appswhich read fromMacOS::LOGIN_ITEM_APPSconstant. Comment claimed array was duplicated in both .aliases and macos.rb, but shell version was never referenced. Ruby constant is single source of truth.
Adopting these changes
- No user action required - changes are internal refactoring
- Timestamp format unchanged: all timestamps still display as
YYYY-MM-DD HH:MM:SS - Git commit messages auto-generated by
smart_commituse same format as before - Login-item apps behavior unchanged (still killed/restarted during defaults writes)
3.2.7
Antidote 2.1.1 compatibility: .zwc compilation enabled, pattern fixes, and performance improvements
-
[files/–ZDOTDIR–/.zlogin] Removed antidote.zsh exclusion from .zwc compilation (lines 79-86). Antidote 2.1.1 fixed the bytecode crash (issue #270) by changing source-detection pattern from
*:file:*to*:file(|code):*to match both regular sourcing and .zwc bytecode contexts. Thefindcommand now compiles all .sh/.zsh files in scanned directories including antidote.zsh. Updated documentation (lines 116-123) to note issue is fixed and reference GitHub issue #270. -
[files/–XDG_CONFIG_HOME–/zsh/]* Fixed ZSH_EVAL_CONTEXT self-invocation guards in 8 autoload functions (cc, count, pull, push, st, status_all_repos, update_all_repos, upreb). Changed from lowercase
zsh_eval_context(array) to uppercaseZSH_EVAL_CONTEXT(scalar string) for correct string pattern matching. Updated pattern from*file*to:${ZSH_EVAL_CONTEXT}: == *:file(|code):*to match both regular sourcing (:file:) and .zwc bytecode loading (:filecode:). Added colon wrappers to ensure exact token matching. Pattern now mirrors antidote 2.1.1’s fix. Without this fix, autoload functions compiled to .zwc would execute when sourced (wrong behavior) instead of only when run directly. -
[scripts/install-dotfiles.rb] Performance optimization: replaced regex pattern
/\.zwc/with string suffix checkend_with?('.zwc')for ignored files (lines 42-43, 67). Changed constant name fromIGNORED_FILE_PATTERNStoIGNORED_SUFFIXESto reflect simpler implementation. Benchmark: 2.6x faster (56ms → 22ms per 100k iterations). Saves ~3.4ms per install-dotfiles run (typical 60-100 files). -
[scripts/utilities/git_processor.rb] Added
build_commit_graphmethod (lines 391-404) to optimize git operations after repository recreation or cloning. Executesgit commit-graph write --reachable --changed-pathsto pre-generate commit graph data structure. Speeds up git log, status, and merge-base by 10-50x. Includes dry-run support and debug logging. Returns boolean success/failure. -
[scripts/recreate-repository.rb] Integrated commit graph building into both force and non-force workflow paths (lines 112-113, 121-122). Runs after push in both modes to leave repository in optimally configured state. Refactored to extract common
git.pushcall outside if/else blocks (line 117), usingforcevariable as parameter for DRY principle. Onlygit.build_commit_graphand the push call are now common final steps; stage/commit/compress operations remain in separate blocks due to different workflow timing (force mode runs these after recreation, non-force before push). -
[files/–ZDOTDIR–/.zshrc] Removed redundant
ensure_dir_exists "${XDG_CACHE_HOME}"call from brew shellenv cache regeneration block (line 115). Directory creation already handled once at line 94 before all cache operations (brew, git, mise, starship). Comment at lines 91-93 documents that early call prevents silent cache-write failures whendelete_cachesremoves ~/.cache. -
[files/–HOME–/.aliases] Updated
delete_cachescomment (lines 498-502) to remove antidote-specific mention. Changed from “antidote.zsh.zwc in particular must be purged so that antidote’s ZSH_EVAL_CONTEXT source-detection check works correctly” to simply “Without -L, stale .zwc files in those paths are silently skipped.” General .zwc cleanup behavior remains unchanged, but special antidote workaround note removed since issue is fixed in antidote 2.1.1. -
[scripts/setup-login-item.rb] Added documentation comment (lines 191-198) explaining why this script uses
Logging.run_scriptwrapper instead of manualincrement_script_depth + print_script_start + print_script_summarypattern. This is a standalone utility (not called from other scripts), so simplified wrapper is appropriate. Comment notes that if later integrated into larger workflow,run_scriptautomatically suppresses banners whenscript_depth >= 1. -
[Extras.md] Updated
recreate-repository.rbdocumentation (lines 120-150) with correct filename, two-mode explanation (force vs non-force), 7-step force workflow including new commit graph building step, early remote capture rationale, usage examples, and safety features section. Force mode now documents: 1) capture remote, 2) recreate local, 3) commit files, 4) verify match, 5) delete remote (if match), 6) push, 7) build commit graph. -
[.ai/domains/shell-scripting.md] Updated Autoload Script Structure section (lines 1463-1495) with correct
ZSH_EVAL_CONTEXTpattern. Changed example from lowercasezsh_eval_contextwith*file*pattern to uppercaseZSH_EVAL_CONTEXTwith*:file(|code):*pattern. Added detailed explanation of pattern components: uppercase for scalar string version, colon wrappers for exact token matching,(|code)for optional ‘code’ suffix, and why both patterns are needed for .zwc compatibility. Documents same pattern antidote 2.1.1 uses. -
[.ai/domains/zsh-startup.md] Replaced “Do NOT compile antidote.zsh” section with “Antidote .zwc Compilation” section documenting that antidote 2.1.1+ fixed the issue. Added historical note explaining the 2.1.0 bug: source-detection pattern
*:file:*didn’t matchfilecodecontext from .zwc loading, causing CLI branch to fire and crash shells. Pattern now uses*:file(|code):*to handle both contexts. Thefind_in_folder_and_recompile "${ANTIDOTE_HOME}"call handles compilation automatically. -
[.ai/CONTEXT.md] Updated “Antidote .zwc Crash” entry (line 237) to mark as
[FIXED in 2.1.1 - July 2026]. Added details about the fix (pattern change), timeline (workaround active 3.1.19-3.1.26, fixed in 2.1.1), and current behavior (safe to compile,find_in_folder_and_recompilehandles it automatically). Preserved historical context about the original bug for future reference.
Adopting these changes
- Restart terminal to reload all zsh configuration including updated autoload functions
- Antidote.zsh will be automatically compiled to .zwc on next shell startup (via .zlogin)
- Autoload functions are now safe to compile to .zwc bytecode for faster loading
- Commit graphs will be built automatically when recreating repositories via
recreate-repository.rb - No manual intervention required - all optimizations apply automatically
3.2.6
Language build optimizations, Git performance tuning, and mise configuration improvements
-
[files/–HOME–/.shellrc] Added automatic commit graph generation in
clone_repo_into()function after successful clone or unshallow+fetch. Commit graphs accelerate git log and branch operations by 10-50x. Runs silently on success, logs debug message on failure (non-fatal). Benefits all repositories cloned via this function (resurrect-repositories.rb, fresh-install bootstrap, manual clones). -
[files/–HOME–/.gitconfig] Added Git runtime optimizations:
core.commitGraph = true(enables commit graph reading for 10-50x faster log/branch operations),core.preloadIndex = true(2-5x faster status/diff/checkout on large repos via parallel index loading),gc.writeCommitGraph = true(auto-maintains commit graphs during garbage collection). These settings apply immediately to all git operations without requiring any build-time configuration. -
[files/–HOME–/.aliases] Added Ruby and Python build optimizations via
RUBY_CONFIGURE_OPTSandPYTHON_CONFIGURE_OPTS. Created_ruby_opt()and_python_opt()helper functions with option-name-based deduplication to prevent duplicate flags when re-sourcing or when user has pre-existing values. Ruby optimizations:--with-openssl-dir(OpenSSL 3.x),--with-readline-dir(readline 8.3),--with-jemalloc(5-15% faster memory),--enable-yjit(compiles YJIT JIT). Python optimizations:--enable-optimizations(PGO+LTO, 20-40% faster). AddedRUBY_YJIT_ENABLE=1export to enable YJIT runtime globally (15-50% faster execution, ~1MB memory overhead). Updated keg-only paths cache generation to export bothRUBY_CONFIGURE_OPTSandPYTHON_CONFIGURE_OPTS. Expected Ruby improvement: 25-60% faster overall (build opts + YJIT runtime). -
[files/–XDG_CONFIG_HOME–/mise/config.toml] Changed Ruby compilation setting from
compile = falsetocompile = truewith documentation explaining Ruby always compiles via ruby-build (no pre-built binaries exist), ensuringRUBY_CONFIGURE_OPTSis used. Added header documenting tool versions belong in~/.mise.toml(personal, untracked) not in this tracked config file. Added Python setting documentation: pre-built binaries already include PGO+LTO optimizations,PYTHON_CONFIGURE_OPTSonly used as fallback. -
.mise.toml Added comment documenting Ruby must use system Ruby (2.6) in dotfiles repo for vanilla macOS compatibility - all Ruby scripts must work before mise/Homebrew Ruby is installed during fresh-install-of-osx.sh. Kept
disable_tools = ["ruby"]setting with rationale. -
[files/–HOME–/Brewfile] Added
jemallocdependency with comment “used for faster ruby”. Added inline comments tolibyamlandopenssldocumenting they’re also used for faster Ruby builds. -
[files/–XDG_CONFIG_HOME–/starship.toml] Fixed timeout warnings on shell startup: increased global
command_timeoutfrom 500ms to 1000ms to accommodate larger repos, setignore_timeout = truefor bothcustom.git_sizeandcustom.git_clean_arrowmodules to prevent warning spam when git operations exceed timeout (segments simply don’t render rather than logging warnings). -
[files/–XDG_CONFIG_HOME–/zed/settings.json] Performance tuning: increased git blame
delay_msfrom 600 to 1200, increased inlay hintsscroll_debounce_msfrom 50 to 150, changed scrollbardiagnosticsfrom “all” to “error”, changed tabsshow_diagnosticsfrom “all” to “error”. Reduces UI noise and improves editor responsiveness. -
[scripts/utilities/command_utils.rb] Added
run_interactivemethod to execute commands without suppressing stdout/stderr, allowing terminal output to flow through (for git log, etc.). Usessystem()instead ofOpen3.capture3, passes block for error handling. -
[scripts/run-all.rb] Replaced
CommandUtils.capture_outputwithCommandUtils.run_interactiveso command output is visible in terminal. Updated error recording to use$?.exitstatusinstead of captured status object. Failures still recorded as warnings viaLogging.record_warning.
Adopting these changes
- Restart terminal to pick up new
RUBY_YJIT_ENABLEand regenerated keg-only paths cache - Rebuild Ruby with optimizations:
mise uninstall --all ruby; install_mise_versions - Verify YJIT:
ruby -e 'puts "YJIT: #{RubyVM::YJIT.enabled?}"'(should show true) - Verify jemalloc:
ruby -r rbconfig -e 'puts RbConfig::CONFIG["MAINLIBS"]'(should include -ljemalloc) - Python already has optimizations if using mise pre-built binaries (Python 3.10+)
- Set your Ruby version in
~/.mise.toml:[tools]section withruby = "4.0.6"(or your preferred version)
3.2.5
Starship prompt optimization and visual refinement
-
[files/–XDG_CONFIG_HOME–/starship.toml] Replaced custom shell-based git segments with starship’s built-in Rust modules (
[git_branch]and[git_status]) - 10-100x faster with automatic caching. Root cause of 2-4s delay to first keystroke: custom segments usinggit st-nolock,git is-dirty,git rev-parse, andgit sizecaused cumulative ~500ms+ delay per prompt render. Built-in modules complete in <100ms. Reducedcommand_timeoutfrom 5000ms to 300ms. Added[custom.git_size](~50ms overhead) showing repo size (du on .git) after branch name on green background, and[custom.git_clean_arrow](~50-180ms overhead, short-circuits if dirty) to show green arrow only when repo has no uncommitted changes AND is not ahead/behind tracking branch. Fixed spacing issues: trailing space in git_size format stays on green background; git_status arrow and status symbols properly contained within yellow background to prevent black rectangles between segments; git_clean_arrow uses git_size’s trailing space (no added space). Visual flow: clean repos showmaster 1.3M(green with trailing space) → green arrow; dirty/ahead/behind repos showmaster 1.3M(green with trailing space) → green→yellow arrow →!3?1or⇣1⇡1(yellow) → yellow arrow. -
[files/–ZDOTDIR–/.zshrc] Fixed anonymous function scope bugs that destroyed
zsh-deferfunction andsetopt promptsubst: removed wrappers around antidote bundle loading (~line 210-224) and starship init (~line 271-295). Re-enabledfast-syntax-highlightingandzsh-autosuggestionsplugins after confirming they cause tiny acceptable delay (<50ms), not the 2-3s delay (which was caused by custom git segments). -
[files/–ZDOTDIR–/.zsh_plugins.txt] Removed OMZ git plugin (431 lines, only 1 alias
gcowas used). Added 7 deferred utility plugins:colored-man-pages(syntax-highlighted man pages),extract(universal archive extractor withxalias supporting 20+ formats),copypath(copy absolute paths to clipboard),copyfile(copy file contents to clipboard),copybuffer(Ctrl+O keybind to copy command line),jsontools(JSON formatting/validation utilities),macos(macOS-specific utilities includingofd,tab,showfiles,hidefiles). All new plugins usekind:deferfor zero startup impact (~1-2ms deferred load time). -
[files/–HOME–/.gitconfig] Added
co = checkoutalias to replace removed OMZ git plugin’sgcoalias. Added new “BASIC SHORTCUTS” section before “HELPER PREDICATES” section to organize simple one-line aliases separately from complex predicates.
Adopting these changes
- Quit and restart terminal (not just new tab) to reload starship config, zsh plugins, and git config
- Prompt should now appear instantly with <100ms render time (down from 500ms+)
- First keystroke should be instant (down from 2-4s delay)
- Test new plugins after 1-2 second deferral:
extract,copypath,copyfile,pp_json,ofd,man ls(colored output) - Use
git co <branch>instead ofgco <branch>(or continue using fullgit checkout)
3.2.4
Zsh startup optimization and code quality improvements
-
[files/–ZDOTDIR–/.zshrc] Minor consistency improvement in git version cache generation: Simplified single-line cache write by removing redundant
{...}block wrapper around single echo statement. Matches pattern used throughout codebase where single-line writes are inlined and multi-line writes use blocks. -
[scripts/software-updates-cron.rb] Replaced hardcoded empty
ollama_models = []array with dynamic model discovery viaCommandUtils.query('ollama', 'list'). Script now automatically detects and updates all locally installed Ollama models instead of requiring manual list maintenance. Removed commented-out hardcoded model names. Removed redundantrequire 'open3'sinceCommandUtilsalready requires it internally. Any model youollama pullmanually will now be automatically updated by the cron job.
Comprehensive code quality review
- [files/–HOME–/.aliases] Fixed
_free_wifiunsafe&&command chains - converted to explicit if statements - [scripts/resurrect-repositories.rb] Replaced Ruby stdlib
warn()withLogging.warn()for consistency; improved variable scoping in_resurrect_eachmethod by movingexisting_remotesdeclaration closer to first usage - [scripts/osx-defaults.sh] Moved
autovariable from script-level intomain()as local variable
All other issues already compliant: .shellrc logging guards use explicit if statements, arithmetic expressions have proper fallback handling. All 35 files now pass whitespace rules, syntax checks, and have correct executable permissions.
Adopting these changes
- Zsh cache change: Restart terminal to reload updated
.zshrc - Ollama updates: No action required - cron job will now automatically update all installed models on next run
3.2.3
Git Shallow Clone Workflow Simplification
- Replaced
fetch-unshallowandpull-unshallowaliases with newunshallowalias. The new alias configures all remotes to fetch all branches and converts shallow clones to full clones. After runninggit unshallow, users must rungit fetchorgit pullto retrieve complete history for all branches.
Adopting these changes
- Run
all unshallowfollowed byall fetchorall pullon any shallow-cloned repositories to retrieve complete history
3.2.2
- Turned off
ollama pullin the cron job since it was taking more than an hour in some cases. - Fixed issue when unshallowing shallow-cloned git repos.
3.2.1
CommandUtils refactoring: dead code removal and error logging improvements
-
[scripts/utilities/command_utils.rb] Added
query(*command)method for simple read-only operations - returns stdout.strip on success, ignores stderr and exit status. Use for version checks and config queries where failure is unexpected. Eliminates boilerplate for trivial commands that previously used full capture3 pattern. -
[scripts/utilities/git_processor.rb] Removed 4 unused methods (67 lines total):
log_timestamp,fix_head_file,rev_list_count,symbolic_ref- none were called by any scripts. Updated internal comments to describe behavior/format rather than implementation details. Result: 9% smaller (736 lines → 683 lines). -
[13 Ruby scripts and utility modules] Converted 15 Open3.capture3 call sites to CommandUtils methods: 9 to
query()(simple stdout reads), 2 tocapture_output()(new error handling needs), 4 tocheck_status()(pre-captured output from GitProcessor). Fixed 3 error logging sites (antidote.rb, collection_processor.rb, cron.rb) to passnilfor stdout parameter when stdout contains sensitive data, large directory lists, or success indicators rather than failure diagnostics - focuses error messages on stderr (what failed) instead of mixed output. -
[.ai/domains/logging-conventions.md] Restructured CommandUtils documentation with decision tree for choosing the right pattern: Use
query()for stdout-only reads,capture_output()for commands with error handling,check_status()for pre-captured output, raw Open3.capture3 only when both stdout and stderr are needed for processing logic (not just error logging). -
[README.md] Enhanced adoption instructions with priority markings for environment variable customization. Added
DOTFILES_BRANCHandUPSTREAM_GH_USERNAMEto required changes checklist. Clarified thatUPSTREAM_GH_USERNAMEmust NOT be changed (parent repo owner), whileGH_USERNAMEmust be changed to adopter’s username. Applies to both.shellrcandenv_vars.rbfiles.
Adopting these changes
- No action required - refactoring is internal implementation change with no user-visible behavior changes
- Net zero line count change (+120/-120 across 13 files), git_processor.rb 9% smaller
3.1.39
Logging system refactor: centralized error handling and common section header format
-
Logging improvements: All Ruby and shell scripts now use fixed-width format for section_header, and all human-readable text (not the padding character) start at a fixed position to help ease of reading all section headers in a vertical manner.
-
Vanilla OS compatibility: Removed timestamp check in
capture-prefs.rbthat was blocking imports when backup predatedosx-defaults.shchanges. Script now accepts any backup without validation errors.
Adopting these changes
- Restart terminal to reload
.shellrcwith fixedsection_headerfunction - Regenerate crontab:
crontab -r; recron; crontab -l - Scripts now provide better error messages with formatted stdout/stderr output
3.1.38
Cross-platform tool-specific git diff configuration with conditional includes
-
[files/–HOME–/.gitconfig] Moved tool-dependent diff configurations (pandoc, plist, sqlite3) to conditional include files for cross-platform compatibility. Removed inline
[diff "plist"]and[diff "sqlite3"]sections. Addedcachetextconv = trueto plist and sqlite3 configs for performance (textconv output is deterministic and safe to cache). Added four conditional includes in[include]section:~/.gitconfig-delta-enabled.inc,~/.gitconfig-pandoc-enabled.inc,~/.gitconfig-plist-enabled.inc,~/.gitconfig-sqlite3-enabled.inc. These symlinks only exist when the corresponding tool is installed, allowing git config to work on systems without these tools (Linux, Windows, fresh macOS). -
[files/–HOME–/.gitconfig-{pandoc,plist,sqlite3}.inc] Created separate config files for tool-specific diff drivers (pandoc for .docx/.odt, plutil for .plist/.defaults, sqlite3 for .db/.sqlite files). Each includes
cachetextconv = truefor performance. Plist config notes that plutil is macOS-only. SQLite3 config includesbinary = trueto prevent git text diff attempts on raw database files. Files are symlinked byinstall-dotfiles.rband conditionally enabled via-enabled.incsymlinks when tools are installed. -
[scripts/install-dotfiles.rb] Refactored tool-specific gitconfig symlink management for DRY principle and extensibility. Added
_ensure_gitconfig_tool_symlink(tool_name, command_name: nil)generic helper method that handles symlink creation/removal for any tool. Replaced four nearly-identical methods with direct calls to the generic helper, reducing ~160 lines of duplicate code to ~44 lines (73% reduction). Adding new tools now requires only a single line call, no new method definitions needed. -
[files/–HOME–/custom.gitignore] Added ignore patterns for new gitconfig conditional include files:
/.gitconfig-{pandoc,plist,sqlite3}-enabled.incsymlinks and/.gitconfig-{pandoc,plist,sqlite3}.incsource configs.
Adopting these changes
- Run install-dotfiles to create symlinks for available tools:
install-dotfiles.rb - Verify git config includes are working:
git config --list --show-origin | grep diff.pandoc(should show config loaded from~/.gitconfig-pandoc-enabled.incif pandoc is installed) - On systems without pandoc/plutil/sqlite3: The enabled symlinks won’t exist, git config will silently skip those includes, and the file types will show as binary diffs (expected behavior)
3.1.37
Skip nested git repos in run-all.rb
- [scripts/utilities/git_workspace.rb] Added nested repository filtering to
find_git_repos. Nested repos are now excluded fromrun-all.rb,oss upreb, git maintenance registration, and mtime restoration - eliminating spurious dirty-tree warnings when nested repos have uncommitted changes.
brew package cleanup improvements
- [files/–HOME–/.aliases] Added cleanup operations before first
brew bundle installinbupcfunction: Runbrew bundle cleanup -f,brew cleanup --prune=all, andbrew autoremoveto remove unused dependencies, orphaned casks, and outdated downloads before installing new packages. Prevents accumulation of stale software and avoids if the old vs new casks were conflicting with each other. Existing cleanup operations after install remain unchanged.
3.1.36
Cron job improvements: PATH expansion fix, run tracking, and warning reduction
-
[scripts/utilities/cron.rb] Fixed critical PATH expansion bug in crontab generation (lines 140-141, 151): Cron does not expand
${VAR}syntax in environment variables, causing PATH to contain literal string${HOMEBREW_PREFIX}/bininstead of/opt/homebrew/bin. This prevented git from findinggit-restore-mtime, causing 17 “not a git command” warnings per run. Changed from single-quoted template strings with variable references to double-quoted strings with Ruby interpolation, generating expanded literal paths at template generation time. Now outputsPATH=/opt/homebrew/bin:...instead ofPATH=${HOMEBREW_PREFIX}/bin:.... Also expanded paths in cron command line (line 151) for reliability. Added missing environment variables to crontab template (lines 113-118):PERSONAL_CONFIGS_DIR,PERSONAL_PROFILES_DIR,PROJECTS_BASE_DIR,HOMEBREW_BUNDLE_FILE,HOMEBREW_BUNDLE_FILE_GLOBAL- these are required by Ruby scripts invoked during cron runs. Removed redundantUSERNAMEvariable (line 126) - kept only POSIX-standardUSER(macOS/Linux).EnvVars::USERalready has fallback toUSERNAMEfor cross-platform compatibility. Changed cron schedule from daily to hourly (line 151):0 * * * *runs at top of every hour. Changed temp log from ephemeral$(mktemp)to persistent~/.software-updates-cron-last-run.logfor debugging - now captures ALL output from last run (success or failure), overwrites on each run. Main log (~/software-updates-cron.log) still only appends on errors/warnings (exit code non-zero). Updated comments (lines 143-148) to document three-file tracking system and PATH expansion issue. -
[scripts/software-updates-cron.rb] Renamed success marker file from
.software-updates-last-successto.software-updates-run-logto reflect that it now tracks both successful and failed runs. Added three status markers: STARTED (written at script start), COMPLETED (written on success), FAILED (written on error/warning). Each marker includes timestamp; COMPLETED and FAILED include duration. This allows monitoring whether cron is currently running (STARTED without completion marker), detecting hung jobs (STARTED hours ago with no completion), and tracking success/failure history over time. The file provides complete audit trail: when each run started, whether it completed successfully or failed, and how long it took. -
[scripts/utilities/macos.rb] Changed
_set_softwareupdate_schedulesudo credential warning fromLogging.warntoLogging.debug. This check fails in cron context (no interactive sudo available), which is expected and not an error. Debug level means message is logged for troubleshooting but doesn’t trigger macOS notifications. -
[scripts/utilities/git_workspace.rb] Changed
status_reponon-git-repo warning fromLogging.warntoLogging.debug. Not all chrome browser profile folders are git repositories, which is expected and not an error. Debug level prevents spurious warnings while preserving diagnostic info. -
[files/–HOME–/custom.gitignore] Replaced
.software-updates-last-successwith.software-updates-run-logand added.software-updates-cron-last-run.log. Both files are generated by cron and intentionally excluded from home repo tracking. -
[Extras.md] Updated cron documentation to explain cron’s PATH expansion limitation and the three-file tracking system. Documents STARTED/COMPLETED/FAILED markers, provides monitoring commands for checking current run status, debugging last run output, and reviewing error history. Clarifies that successful runs don’t append to main log (keeps it clean for problem diagnosis).
Adopting these changes
- Regenerate and install crontab:
recron(reads from${PERSONAL_CONFIGS_DIR}/crontab.txtif it exists, otherwise preserves current schedule) - Rename old file if it exists:
mv ~/.software-updates-last-success ~/.software-updates-run-log(first run will append new STARTED/COMPLETED/FAILED markers to existing completion timestamps) - Monitor cron runs:
tail -4 ~/.software-updates-run-logshows recent markers (STARTED/COMPLETED/FAILED with timestamps and durations) - Debug output:
cat ~/.software-updates-cron-last-run.logshows complete output from last run - Errors only:
tail ~/software-updates-cron.logshows historical errors/warnings
3.1.35
- [.zlogin, .zshrc] Performance tweaks for zsh startup.
- [starship.toml] Enabled lightweight modules
miseanddirenv. - [cron.rb] Disable all mail generation from cron jobs (rely on macOS notifications instead).
- Cron jobs do not ues chronic now. They will write to a temp file and delete if the cron was successful, else this file’s contents will be appended into the
${HOME}/software-updates-cron.logfile for human review.
3.1.34
- Removed
vorssaintsince it was causing zoom to hang when joining meetings. Went back tostats(menubar monitors),sol(clipboard, window layout) anddockdoor(window previews in dock).
3.1.33
Starship optimizations: 75-100x faster prompts + embedded git size + cron output fix + DRY helpers
-
[files/–HOME–/.gitconfig] Added 2 new helper aliases to extract repeated patterns (lines 43, 48):
st-nolockreturns porcelain status without locks (--no-optional-locks status --porcelain 2>/dev/null) for safe prompt/monitoring use,is-dirtyreturns 0 if working tree has uncommitted changes by piping st-nolock to grep. Both helpers follow<dir>argument convention. Extracted to eliminate 6 occurrences ofgit --no-optional-locks status --porcelain 2>/dev/nullin starship.toml (2 as standalone command, 4 inwhenconditions with grep pipe). Keepsstalias clean for interactive use (users benefit from normal locking/contention visibility). Converted all 19 single-line named function aliases to multi-line format for readability (helper predicates, inspection/info aliases, viewing changes/history, local changes/staging, remote operations) - improves maintainability and makes control flow immediately visible. Now 721 lines (was 649: +10 for new helper aliases, +62 for multi-line formatting). -
[files/–XDG_CONFIG_HOME–/starship.toml] Replaced all 6 occurrences of direct
--no-optional-lockscalls with new git aliases (lines 206, 214, 249, 257, 284, 293):whenconditions now usegit is-dirtyand! git is-dirtyinstead of full command pipeline, command blocks now useporcelain=$(git st-nolock)instead of inline--no-optional-locksinvocation. Reduces duplication, centralizes lock-free status logic in git config, improves maintainability (single source of truth for prompt status checks). -
[files/–XDG_CONFIG_HOME–/starship.toml] Applied 5 cumulative optimizations to all 8 custom git segments (lines 203-328): (1) Added
require_repo = trueto skip non-git directories without subprocess (~2s saved); (2) Addedshell = ["sh", "--noprofile", "--norc"]to avoid loading zsh config (~1.8-2.7s saved); (3) Removed redundantgit rev-parse --is-inside-work-treefrom 6whenconditions sincerequire_repoalready checks this (~135ms saved); (4) Moved porcelain check to start ofgit_dirtyandgit_cleancommands withwhen = "true"to eliminate duplicate git status calls while allowing starship to evaluate segments (~20-30ms saved); (5) Replacedcustom.git_statesegment (35 lines) with built-ingit_statemodule (13 lines config) which uses Starship internal caching and adds progress indicators for rebase/cherry-pick operations (~50-100ms saved during operations). Built-ingit_stateuses Rust/libgit2 internally (more correct than shell script), works with both classic .git/ and reftable backends (git 2.45+ default). Reduced from 2-3s → 35ms per prompt (50-90x faster). -
[files/–XDG_CONFIG_HOME–/starship.toml] Embedded repo size directly into
git_cleanandgit_dirtycommands (lines 237, 268) by callingGIT_SIZE_QUIET=1 git sizeinline. Eliminated 2 separategit_sizesegments and their redundantwhenconditions. Reduced from 354 → 339 lines (saved 15 lines). Git calls per prompt: 8-9 → 6-7 (eliminated 2whenconditions). Further performance gain: 35ms → ~30-32ms (10-15% faster). Cumulative improvement: 75-100x faster than v3.1.32. -
[files/–HOME–/.gitconfig] Added
GIT_SIZE_QUIETenv var support togit sizealias (lines 307-310). When set, suppresses label and outputs only size value for programmatic use (starship, scripts). Maintains optimal performance with 3 forks (git rev-parse + du + cut). Removed customstandupalias (lines 96-98) - now usinggit standupfrom git-extras which supports multi-repo search (-mflag), flexible time ranges (-dflag), branch grouping (-B), and fetch-first option (-f). Fixedscialias (line 69) to amend only when there’s exactly 1 unpushed commit (changed-gt 0to-eq 1); previously would amend with 2+ unpushed commits which could lose the earlier commit messages. Replacedgit diff --cached --quietwithgit dc --quietin 3 aliases (sci,pull-safe,upreb) to reuse thedcalias (DRY principle) - both are equivalent (--stagedis a synonym of--cached). Normalized 4 shell aliases (pull-unshallow,fetch-unshallow,new,old) from legacy!sh -c '...' -pattern to modern!f() { ... }; fpattern for consistency (17/22 → 21/22 aliases now use the named function pattern) - improves readability by eliminating nested quote complexity and making multi-line logic clearer. Removed redundant git flags made unnecessary by config settings: removed--progressfrompushinuprebandpushsub(redundant when TTY attached, wrong for cron which should suppress progress), removed--allfromfetch/pullin 4 aliases (pull-unshallow,fetch-unshallow,pull-safe,upreb) sincefetch.all=trueconfig makes it the default behavior. Reformatted 5 complex single-line aliases (pull-safe,upreb,rfc,size,cc) to multi-line format for readability - eliminates quote escaping complexity and makes control flow immediately clear. Applied DRY principle throughout aliases: updateddcto used --stagedinstead ofdiff --staged(line 165), updateddcolorto used --color-wordsinstead ofdiff --color-words(line 169), updatednewandoldaliases to usegit brinstead ofgit branch --show-currentfor consistency. Simplifiednewalias (line 329) from 8 lines to 3 lines using parameter expansion with command substitution default (b="${1:-$(git br)}") - more concise while preserving exact behavior. Added 4 new helper aliases to extract common patterns:is-clean(checks if working tree has no uncommitted changes usingd --quiet && dc --quiet, used inpull-safeandupreb),is-shallow(checks if repo is a shallow/partial clone, used inpull-unshallowandfetch-unshallow),all-refs(lists all local branches and remote-tracking branches, used inrfcandcc), andhas-upstream(checks if upstream remote exists, used inupreb) - improves readability and maintainability via DRY principle. Renamedrepoalias toorigin-nameto avoid potential clashes with external tools. Regrouped all aliases into 5 logical sections with alphabetical ordering within each section: (1) Helper Predicates (4 aliases: all-refs, has-upstream, is-clean, is-shallow), (2) Inspection & Info (23 aliases: b through track), (3) Viewing Changes & History (18 aliases: d through who), (4) Local Changes & Staging (16 aliases: amend through wipe), (5) Remote Operations (8 aliases: fetch-unshallow through upreb), (6) Submodules (2 aliases: sf, siu) - significantly improves discoverability and maintainability. -
[.ai/domains/git-config.md] Updated git alias pattern documentation (lines 81-135) to clarify that
!f() { ... }; fis the preferred pattern for all multi-step shell aliases. Documented that the legacy!sh -c '...' -pattern is valid but deprecated in favor of the clearer named function syntax. Added comprehensive comparison showing benefits (clearer structure, easier readability, simpler argument handling) and argument handling differences between the two patterns. Added § Helper Predicates for DRY Principle (lines 82-147) documenting 6 helper aliases:st-nolock(lock-free porcelain status for prompts),is-dirty(working tree dirty check using st-nolock),is-clean(no unstaged/staged changes),is-shallow(shallow clone check),all-refs(list local+remote branches),has-upstream(upstream remote exists). Documents rationale for lock-free status checks (safe for prompts, prevents creating index.lock files) and whystalias should NOT use--no-optional-locks(users benefit from seeing lock contention). -
[files/–HOME–/.editorconfig] Added
*.tomlsection withindent_size = 2for starship config consistency. -
[scripts/software-updates-cron.rb] Fixed cron job writing to mail spool despite using
chronic. Addedout: File::NULLto 5 system calls producing progress output (lines 155, 163, 165, 184, 219):brew update,mise plugins update,mise upgrade --bump,tldr --update,bat cache --build. Addedout: File::NULL, err: File::NULLtoollama pull(line 219) to suppress ANSI escape sequences and progress bars. Preserved output forbrew bundle check -v(line 160) since it shows useful diagnostic info about missing packages. UsesFile::NULLconstant instead of hardcoded'/dev/null'string for platform portability (Unix/macOS:/dev/null, Windows:NUL). Cron now runs silently on success, only sends mail on actual errors.
Adopting these changes
- Restart terminal to reload starship config - prompts will be noticeably faster in git repositories.
- Cron job will stop generating spurious mail on successful runs.
- Use
git standup -d 7instead ofgit standup(git-extras version requires-dflag for time range).
3.1.32
-
[files/–HOME–/.gitconfig-delta.inc] Moved all delta-related configs to this file. It will get included only if
deltais installed. Till then, this file will just sit on the HOME folder, but will not affect normal git operations. -
[files/–HOME–/.gitconfig] Removed custom aliases that are present via
git-extras.
3.1.31
-
[files/–HOME–/Brewfile] Simplified trusting of specific formulae/casks with fully-qualified names in the DSL itself.
-
[files/–HOME–/.aliases] Deleted
trust_brewfile_itemssince its no longer required due to above change.
3.1.30
-
[files/–HOME–/.aliases] Extracted
trust_brewfile_itemsutility method that can be used to trust formulae/casks which are not yet trusted. Removed deprecated--cleanupoption frombrew bundle install. -
[files/–HOME–/Brewfile] Replaced
StatsandDockDoorwithVorssaint.
Adopting these changes
- Restart terminal after successful conflict resolution.
3.1.29
Fix 26 critical/high-priority issues: Core modules, ERR traps, PlistBuddy atomicity
-
[scripts/utilities/keybase.rb] Added missing Core module (lines 6-7, 14-15). Added
require_relative 'core'and bothinclude Core+extend Core. Fixesnil_or_empty?usage that previously only worked via transitive include through Logging. Method now available in both module methods and blocks. -
[scripts/utilities/plist.rb] Added missing Core module (lines 8, 20-21). Added domain validation for export operations (line 41) - now validates domain is non-empty before attempting export. Added rescue for relative_path calls (line 57) - prevents crashes when path validation fails. Fixes
nil_or_empty?calls at lines 66 and 187. -
[scripts/utilities/path_utils.rb] Added missing logging require (line 8). Fixes crash when
Logging.debugcalled at line 117 duringensure_directories_exist. -
[scripts/install-dotfiles.rb] Added Core module (lines 24, 32-33). Added
require_relative 'utilities/core'and bothinclude Core+extend Core. Removes fragile dependency on transitive Core inclusion via Logging module. Makesnil_or_empty?available throughout script. -
[scripts/resurrect-repositories.rb] Added Core module (lines 22, 31-32). Same changes as install-dotfiles.rb - explicit Core require and dual include/extend for consistent helper method availability.
-
[scripts/capture-prefs.rb] Added rescue for GitProcessor relative_path calls (lines 168-178). When path validation fails (path outside repo or invalid), logs warning via
Logging.warnand skips the problematic file instead of crashing. Prevents fatal errors during preferences backup/restore when unexpected file paths encountered. -
[scripts/cleanup-browser-profiles.rb] Fixed variable scoping (lines 138, 222-238). Moved
profile_folderdeclaration inside GitProcessor block where it’s used. Movedbackup_filedeclaration inside conditional branches. Improves garbage collection and clarifies variable lifetime. -
[files/–HOME–/.shellrc] Fixed unsafe
keep_sudo_alivearithmetic (line 1237). Changedhas_sudo_credentialstohas_sudo_credentials || true- prevents return code 1 from triggering ERR traps when sudo not available. Added Ruby availability checks in_call_ruby_cron(guards all Ruby delegations withcommand_exists ruby). Prevents crashes on vanilla OS before Homebrew installs Ruby. -
[files/–HOME–/.aliases] Added Ruby availability checks (lines 377-382 in
_call_ruby_git_workspace, 1008-1013 in_call_ruby_macos). Guards all Ruby utility delegations withcommand_exists rubybefore invoking. Prevents “ruby: command not found” errors during fresh-install before Homebrew installation completes. -
[files/–XDG_CONFIG_HOME–/zsh/status_all_repos] Fixed dispatch pattern. Moved shell implementation into
_status_all_repos, addedstatus_all_reposdispatch wrapper callingdispatch_or_fallback. Complies with mandatory pattern from shell-scripting.md - Ruby delegation works correctly, shell fallback preserved. -
[files/–XDG_CONFIG_HOME–/zsh/update_all_repos] Fixed dispatch pattern. Same changes as status_all_repos - moved implementation to
_update_all_repos, added dispatch wrapper. Ensures consistent Ruby-first execution with shell fallback. -
[scripts/osx-defaults.sh] Added ERR trap (line 34):
trap 'error "Script failed at line ${LINENO}. Check log for details."' ERR. Provides clear failure notification with line numbers instead of silent failures. Added context message before killing apps (line 146): “About to kill and restart Terminal, iTerm2, Finder…” - prevents user confusion when apps suddenly close. Added_plist_set_or_addhelper function (lines 98-125) implementing atomic Set-or-Add pattern for PlistBuddy operations. Refactored Terminal profile settings (lines 1173-1195) to use helper - 4 settings now atomic (rowCount, columnCount, useOptionAsMetaKey, shellExitAction). Converted all 59 non-array iTerm2 settings (lines 1374-1467) from Delete+Add pattern to_plist_set_or_add- includes window dimensions, text/font settings, terminal behavior, session options, keyboard modifiers. Added error suppression to Jobs to Ignore array Delete operation (2>/dev/null || true) - only array operation remaining as Delete+Add since PlistBuddy cannot atomically set array contents. Fixed duplicate array index bug (zsh was:5twice, now correctly:6). Total: 63 settings moved from non-atomic to atomic pattern. Script can now be interrupted at any point without leaving Terminal/iTerm2 preferences in partial state (except array contents). Code reduction: 189 lines changed (+64, -125), net -61 lines in iTerm2 section. -
[scripts/fresh-install-of-osx.sh] Added
.shellrcdownload validation (lines 113-117). After curl download, validates file exists and is non-empty usingis_fileandis_file_non_zero. Exits with clear error message if download corrupted or network failure occurred. Prevents sourcing broken.shellrcthat would crash bootstrap process. Added FileVault user_action (line 172):user_action "Enable FileVault disk encryption in System Settings > Privacy & Security". Prompts user to enable encryption after fresh-install completes - can’t be automated (requires user password). Added manual review reminder (line 769): prints user_action before opening System Settings, reminds user to review all applied settings. Prevents blind acceptance of defaults. Fixed cron backup timing (lines 723-731): movedsuspend_croncall to beforecapture-prefs.rb -iinvocation. Prevents cron job from running during preferences restoration (could conflict with import process).
Adopting these changes
- Restart terminal after successful test
3.1.28
Core utility module and ENV access centralization
-
[scripts/utilities/core.rb] (NEW, 80 lines) Zero-dependency foundational module providing helpers used by all other utilities. Prevents circular dependencies and avoids duplication. Provides
nil_or_empty?(val)with type-aware checking (strips strings, handles arrays, converts others to string),execute_with_streaming(cmd, stdin_data: nil)for real-time command output (brew bundle, git operations). Other utility modules include Core for unqualified access. Refactored all other scripts to use this as an included module. -
[all ruby scripts] Changed the internal structure of the ruby classes to use a module which could be invoked directly from another ruby script if needed. Provides a cleaner architecture for separating out the CLI usage (as a standalone ruby script) vs the direct-module usage.
Documentation updates
-
[.gitignore] Added
/.ai/session-state/pattern (holds transactional work products: task lists, session analyses, completed project retrospectives). Removed from tracking (moved to gitignoredsession-state/folder). -
[.ai/REBASE-AND-REFACTORING-METHODOLOGY.md] Removed broken references to moved case study files (lines 753-758).
Adopting these changes
- Restart terminal to reload environment (EnvVars changes)
- No user action required for Core module (transparent dependency)
3.1.27
Extract plist functionality, port setup-login-item to Ruby, centralize system command paths
-
[scripts/utilities/plist.rb] (NEW) Extracted plist operations from
capture-prefs.rbinto reusable module. Provides:export_domain(domain, file)- exports defaults to XML plist;import_domain(domain, file)- imports plist to defaults;strip_excluded_keys(domain, file, patterns)- removes non-portable keys using REXML;has_keys?(file)- checks if plist has any keys after stripping;load_excluded_keys(filepath),load_denied_list(filepath),load_domains_list(filepath, denied)- data file loaders for pattern/domain lists. All plist manipulation now uses REXML (system Ruby, always available) withdefaults/plutilwrappers. Benefits: modularity (reusable by other scripts), single source of truth for plist operations, 76-line reduction incapture-prefs.rb. -
[scripts/capture-prefs.rb] Refactored to use
Plistmodule. Removed inline REXML manipulation (nowPlist.strip_excluded_keys), removedrexml/documentandsetrequires (now inplist.rb), simplified helper methods to thin wrappers aroundPlistmodule methods. Export/import logic now usesPlist.export_domain,Plist.import_domain,Plist.has_keys?. Reduced from 366 to 290 lines. -
[scripts/setup-login-item.rb] (NEW) Ruby port of
setup-login-item.sh. Registers apps as macOS login items via SMAppService (macOS 14–25) or legacy System Events AppleScript (macOS 13, 26+). Functionality preserved:-a <app-name>and-b(background) flags, all logging viaLoggingmodule, script depth tracking, warning collection. Benefits: no${ZDOTDIR}/.aliasesdependency (self-contained withrequire_relative), cleaner subprocess handling withOpen3.capture3, explicit return values, easier to test. Shell version retained temporarily for rollback safety. -
[files/–HOME–/Brewfile] Updated
setup_login_items_scriptvariable to referencesetup-login-item.rbinstead ofsetup-login-item.sh. Keybase and other login-item postinstall hooks now invoke Ruby version. -
[scripts/utilities/macos.rb] Added
ROOTconstant (filesystem root as Pathname) and all macOS system command path constants:DEFAULTS_CMD,DU_CMD,OSASCRIPT_CMD,PLUTIL_CMD,ZSH_CMD. Centralized from scattered definitions across multiple files. All useROOT.join('usr', 'bin', 'command').to_s.freezepattern for consistency. -
[scripts/utilities/path_utils.rb] Removed
ROOTandDU_CMDconstants (moved toMacOSmodule). Updateddir_size_kbanddir_size_humanto useMacOS::DU_CMD. Addedrequire_relative 'macos'. Updated module doc comment to clarify it contains generic (cross-platform) utilities only, with pointer toMacOSmodule for system command paths. Retained:command_exists?,extract_path_segment_at,glob_pathnames(all generic/cross-platform). -
[scripts/utilities/plist.rb, scripts/setup-login-item.rb, scripts/resurrect-repositories.rb] Updated all system command references to use
MacOS::constants (MacOS::DEFAULTS_CMD,MacOS::PLUTIL_CMD,MacOS::OSASCRIPT_CMD,MacOS::ZSH_CMD,MacOS::ROOT). Changed requires frompath_utilstomacoswhere appropriate. Benefits: clear separation of concerns (macOS-specific paths inMacOSmodule, generic utilities inPathUtils), single source of truth for all system command paths, consistentMacOS::*_CMDnaming pattern. -
[.ai/domains/fresh-install.md, .ai/instructions.md] Updated
applyTopatterns and file lists to referencesetup-login-item.rbinstead ofsetup-login-item.sh. -
[scripts/setup-login-item.sh] Deleted after successful production validation of Ruby version. Shell version is no longer needed.
-
[Extras.md] Updated documentation to reference
setup-login-item.rbinstead ofsetup-login-item.sh. Added notes about SMAppService (macOS 14–25) vs legacy System Events path (macOS 13, 26+).
3.1.26
Tool-agnostic AI instruction system
-
[.ai/] (NEW) Centralized AI assistant instructions replacing tool-specific configs. Structure:
instructions.md(main entry point with general rules, whitespace requirements, git state management),context.md(historical optimizations, performance patterns, debugging guidance),domains/(13 domain-specific rule files with YAMLapplyTofrontmatter). Total: 4,000+ lines of consolidated guidance. -
[.ai/domains/] Domain files cover:
character-encoding.md(ASCII-only requirements),comment-philosophy.md(cross-language comment guidelines),edit-checklist.md(complete edit workflow),fresh-install.md(bootstrap/setup rules),git-config.md(git aliases/config patterns),logging-conventions.md(unified color standard for shell+Ruby),path-constants.md(env var/path construction rules),ruby-scripting.md(Ruby script template, memoization, private methods),script-depth-tracking.md(nesting suppression + auto-indentation),shell-scripting.md(shell script template, option parsing, conditionals),whitespace-rules.md(formatting requirements),zsh-startup.md(startup performance optimization). -
[.cursorrules, .windsurfrules] (NEW) Minimal redirects pointing to
.ai/instructions.md. Replaced tool-specific duplication with single source of truth. -
[.github/copilot-instructions.md] Reduced from 3,800+ lines to 6-line redirect to
.ai/instructions.md. All rules migrated to domain files. -
[.opencode/opencode.json, .opencode/skills/dotfiles-domain/SKILL.md] Updated to reference new
.ai/structure. Skill now loads domain context instead of duplicating rules.
Script improvements following new conventions
-
[files/–ZDOTDIR–/.zshrc, .zshenv, .zlogin] Applied whitespace rules (no trailing blank lines, no trailing whitespace, single final newline). Formatted with
shfmt. -
[all ruby scripts] Enforced private method discipline (
_prefix +privatedeclaration). CentralizedENV.fetchcalls intoEnvVarsmodule. Applied Pathname optimization (defer.to_suntil last moment). Fixed whitespace violations. -
[files/–HOME–/Brewfile] Added
ollamapackage. -
[files/–HOME–/.ollama/env] (NEW) Ollama environment configuration with model storage path.
-
[GettingStarted.md] Updated documentation to reference new
.ai/instruction structure.
Fixed set -E ERR trap firing on normal && conditionals during fresh-install
-
[.shellrc] Converted standalone
&&chains and bare arithmetic/test expressions to explicitif/returnblocks in all guard/early-return patterns to prevent ERR trap from firing when the conditional returns false in normal operation. Affected: logging functions (success,info,warn,user_action,debug), validation helpers (_has_step_errors,_has_step_warnings,is_zero_string,is_non_zero_string,is_running_in_tty,is_zsh,is_arm,is_executable,is_symbolic_link,is_file,is_directory,is_empty_array,is_non_empty_array,is_file_older_than,is_macos,is_linux,is_first_install,is_windows,is_outermost_script,has_sudo_credentials,command_exists,join_array,is_non_empty_file,is_directory_empty), file operations (load_file_if_existsnow uses|| warnon source failures,ensure_dir_existsconverted||mkdir pattern to explicitifblock), git operations (clone_repo_into,set_ssh_folder_permissions), and re-source guards. -
[.aliases] Converted re-source guard, DEBUG echo, and conditional alias assignments (
command_exists tool && alias,is_directory dir && alias) to explicitifblocks. Fixedis_first_installflag assignments andcheck_caskbrew command chains. -
[.zshenv, .zshrc, .zlogin] Converted DEBUG echo
&&chains to explicitifblocks. Fixedfind_in_folder_and_recompileto ensureXDG_CACHE_HOMEexists before touching sentinel file (prevents failure when directory doesn’t exist on vanilla OS during firstload_zsh_configscall). -
[fresh-install-of-osx.sh] Converted biometric sensor flag assignments to explicit
ifblocks. Fixedchshcommand to handle authentication failures gracefully with_record_warninginstead of triggering ERR trap. Declared_script_start_timesand_step_start_timesarrays before using+=operator (preventsset -uviolations). Moved Sol.app launch check to nestedifblocks to avoid standalone&&chain abort. Modified_clone_home_repoto pull latest home repo changes on pre-configured machines before preferences restore. Added automatic preferences export and commit on pre-configured machines: runscapture-prefs.rb -eto refresh backup, thengit scito commit (amends existing commit if ahead of remote, creates new if not) - updates git commit timestamp so import validation passes. -
[osx-defaults.sh] Converted spotlight indexing
mdutilcommand chain to explicitifblock. -
[files/–PERSONAL_PROFILES_DIR–/.envrc] Converted symlink creation and folder move operations from chained
&&to explicitifblocks. -
[scripts/utilities/cron.rb] Changed
restore_cronfrom raising exceptions to logging errors viaLogging.record_errorand returning boolean success/failure. Updated callers (resume_cron,recron) to check return value before printing success message. Prevents crontab installation failures from aborting fresh-install via ERR trap - errors are recorded in summary but execution continues. -
[capture-prefs.rb] Added
FIRST_INSTALLexception to timestamp validation check - skips staleness validation whenENV['FIRST_INSTALL']is set. On vanilla OS, fresh-install runsosx-defaults.sh -sfirst to baseline current system prefs, so import is an incremental overlay where any backup is better than none. On pre-configured machines, check remains active to prevent importing incomplete settings afterosx-defaults.shupdates.
Root cause: Under set -E, ERR traps inherit to all functions. Standalone A && B expressions where A returns false propagate exit code 1 to the enclosing scope, triggering the trap even though the false result is expected (e.g., guard conditions, optional file checks). Explicit if A; then B; fi never propagates the predicate’s exit code, so the trap never fires. Ruby exceptions (raise) also propagate to shell as non-zero exit codes, triggering ERR traps when called via ruby -e from shell functions.
Impact: Fresh-install now completes successfully on both vanilla OS and pre-configured machines without false-positive “Installation failed at line X” errors during .zshrc sourcing, when external completion files are loaded, when crontab installation fails, or when backup preferences predate osx-defaults.sh changes. On pre-configured machines, preferences backup is automatically refreshed and committed before import, ensuring timestamp validation passes.
Adopting these changes
- Review the new
.ai/structure for comprehensive coding guidelines. - Rebase from upstream, resolve conflicts.
-
Run the following commands in each terminal tab/window/panel (or) Quit & Restart the Terminal application:
unfunction is_shellrc_sourced; zcompile ~/.shellrc; source ~/.shellrc unfunction is_aliases_sourced; zcompile ${ZDOTDIR}/.aliases; source ${ZDOTDIR}/.aliases
3.1.25
Converted capture-prefs to Ruby
- [scripts/capture-prefs.rb] (NEW, 363 lines) Complete Ruby implementation replacing 391-line shell version. Eliminates shell→Ruby boundary for MacOS module calls. Direct GitProcessor usage for git operations. Self-validating file loaders with early abort on missing files. Memoized operation queries eliminate repeated string comparisons. Uses Set for domains collection (O(1) operations, automatic deduplication). Extracted private helpers with
_prefix for modularity. Uses other utility modules for encapsulation and reuse.
Memoization optimization and private method enforcement (Ruby scripts)
- [all ruby scripts] Added memoized helper methods. Enforced privacy pattern with
_prefix (signals internal-only),privatedeclaration prevents external use. Centralized allENV.fetchinto EnvVars module; added new methods into GitProcessor; used Pathname optimization throughout; removed pass-through wrappers that were doing ruby→shell→ruby jumps.
Documentation enhancements
- [.github/instructions/ruby-scripting.instructions.md] Added “Memoization” section (lines 1621-1810, +190 lines) documenting: memoized helper pattern (repeated command checks), memoized boolean query pattern (operation mode flags), when NOT to memoize (dynamic state, single-use, cheap operations), scan rule with bash commands (
rg "command_exists?" | uniq -c), instance variable mechanics for top-level scripts vs modules. Added “Scan Rule: Check for Missing Private Declarations” subsection (lines 1031-1065, +29 lines) with 5-step audit procedure (grep "^def [^_]" script.rb), common patterns requiring private helpers, instruction to fix immediately before other changes. Total +219 lines.
Shell and git configuration fixes
-
[files/–HOME–/.gitconfig] Fixed
git relative-pathalias to use$GIT_PREFIXinstead ofgit rev-parse --show-prefix(which always returns empty in alias context). Returns.for repo root,./pathfor subdirectories. Validates paths are within repo boundary with descriptive error messages. Works correctly withgit -C <dir>invocation pattern. -
[files/–HOME–/.aliases, files/–HOME–/.shellrc, .opencode/skills/dotfiles-domain/SKILL.md] Renamed
_create_crontab→create_crontab(removed_prefix since it’s a public helper called by recron, not a private script helper). Updated all references in comments and documentation. -
[files/–HOME–/custom.gitignore] Added
/.software-updates-last-successto global ignore list since this is written to for every successful cron run. Success timestamp file is intentionally excluded from home repo tracking.
Ruby delegation pattern improvements and colorization fixes
-
[scripts/utilities/git_processor.rb] Added
migrate_to_reftableclass method (46 lines) mirroring shellmigrate_git_repo_to_reftablefunction. Handles git 2.45+ reftable migration with silent fallback on older git. Includes loose refs cleanup. -
[files/–HOME–/.shellrc] Invoked the above ruby implementation via
_call_ruby_git_processorhelper following established_call_ruby_cronpattern. Single implementation in Ruby, shell just delegates. -
[scripts/capture-prefs.rb] Fixed git.add path handling (line 350) - use
git.relative_path(target_dir)to convert absolute path to repo-relative before callinggit.add().target_dirisPERSONAL_CONFIGS_DIR/defaults(absolute), GitProcessor repo root is HOME, git add requires relative paths.
Rationale
- Shell→Ruby conversion: Eliminates subprocess overhead for MacOS module calls. Direct GitProcessor usage removes git command string construction. Native Ruby exceptions vs shell exit codes. Self-validating loaders abort early on missing files. Better maintainability - all plist operations in single language.
- Performance: Memoization eliminates 3 shell invocations per cron run in software-updates-cron (~30ms savings). Memoized boolean queries in capture-prefs (7
operation == 'export'→ 1_exporting?check). Set data structure for domains (O(1) operations vs O(n) array lookups). - Encapsulation: Private method discipline (18 methods across 3 scripts) enforces API boundaries. Memoized helpers provide single source of truth for repeated checks.
- Documentation: 219 lines of guidance with concrete scan procedures (
grep,rgcommands) ensures pattern consistency across future edits. - DRY: Memoization pattern eliminates code duplication. Boolean query pattern eliminates repeated string comparisons.
_call_ruby_git_processorhelper centralizes Ruby delegation logic - adds 29 lines but eliminates 40 lines of duplicated shell logic, enables reuse for future GitProcessor wrappers. - Consistency:
_call_ruby_git_processorfollows established_call_ruby_cronpattern (keyword args vs positional args). Unified color standard applied - URLs/commands cyan without quotes, components/tools yellow without quotes, paths cyan with quotes. - Correctness:
git.relative_path()fixes path boundary bug in capture-prefs. Recursive directory removal inmigrate_to_reftablehandles nested git refs. Explicit$LOAD_PATHsetup (not relying onRUBYLIB) makes wrappers more robust. - Vanilla OS compatibility: Verified
RUBYLIBavailable at allmigrate_git_repo_to_reftablecall sites (line 529 after line 515.shellrcsource, line 575 after line 553load_zsh_configs). Ruby implementation handles git < 2.45 gracefully (silent skip, retry after Homebrew install).
Adopting these changes
- Rebase from upstream, resolve conflicts.
-
Run the following commands in each terminal tab/window/panel (or) Quit & Restart the Terminal application.
unfunction is_shellrc_sourced; zcompile ~/.shellrc; source ~/.shellrc unfunction is_aliases_sourced; zcompile ${ZDOTDIR}/.aliases; source ${ZDOTDIR}/.aliases
3.1.24
Converted software-updates-cron to ruby
- [scripts/software-updates-cron.rb] (NEW, 264 lines) Complete Ruby implementation replacing shell version. Eliminates
_call_ruby_profiles_repoworkaround pattern - calls ProfilesRepo methods directly. Uses utilities: Antidote, EnvVars, GitWorkspace, Logging, MacOS, PathUtils, ProfilesRepo. All functionality from shell version preserved: brew/mise/tldr/git-ignore/claude updates, antidote plugin regeneration, bat cache, zen-browser tag cleanup, ollama model pulls, repo updates (home/oss/maintenance), dev environment setup, repo aliases, app preferences capture, session backup pruning, profiles repo size check, chrome folder updates, outdated package detection. Fixed escaped quotes in git maintenance commands (lines 115-117) - removed\"that caused “command not found” errors. Calls GitWorkspace methods directly for update_all_repos and status_all_repos instead of sourcing zsh autoload scripts.
Rationale
- Eliminates shell→Ruby boundary overhead: ProfilesRepo methods called directly instead of subprocess wrapper pattern.
- Better error handling: Native Ruby exceptions instead of shell exit codes.
- Simpler crontab invocation: Direct
rubycall (nozsh -cwrapper needed). - Unified logging infrastructure: All output through Logging module (no format conversion).
- Better maintainability: All ProfilesRepo logic stays in Ruby (prune, size check, chrome updates).
- Correct module placement: Chrome folders are browser profile-specific, belong in ProfilesRepo alongside other PERSONAL_PROFILES_DIR operations.
- DRY principle: Chrome folder pattern defined once in
find_chrome_folders, used by bothupdate_chrome_foldersandstatus_all_repos. - Performance: <0.2% difference vs shell version (negligible).
Adopting these changes
- Run the following to regenerate crontab with new Ruby script path:
_create_crontab "${PERSONAL_CONFIGS_DIR}/crontab.txt" recron - Monitor next 1-2 cron cycles for correct operation (check
~/software-updates-cron.log).
3.1.23
Zsh startup performance fix: architecture cache optimization
- [files/–ZDOTDIR–/.zshrc] Fixed arch cache to eliminate subprocess forks on cache hit (lines 93-112). Previous implementation ran
uname -randsedon every shell startup (~5-8ms overhead), negating the intended savings. New logic: cache hit = pure source (0 forks), cache miss = both uname calls. Removed automatic kernel version tracking; cache invalidation is now manual viadelete_cachesafter macOS upgrades. Measured improvement: ~3.4ms per shell startup (from ~60.6ms to ~57.2ms in profiling tests). Arch cache overhead reduced from 8.80ms (26.85% of startup) to 0.06ms (0.27% of startup) – 147x speedup for this block.
Backport utility enhancements with shell delegation pattern and convert zsh autoload functions to Ruby
-
[scripts/utilities/git_workspace.rb, scripts/utilities/macos.rb] Backported from migration branch.
-
[all ruby scripts] Ensures consistency with single source of truth for git repo detection across all utility modules. Also found and fixed premature conversion of
Pathnameinstances toString(maintain rich object as much as possible only convert to String at interpolation boundaries in log messages). -
[all zsh autoload scripts in files/–XDG_CONFIG_HOME–/zsh/] Converted from shell script to a thin Ruby wrapper.
-
[files/–XDG_CONFIG_HOME–/zsh/st] Fixed infinite recursion bug where
git stcalled itself instead ofgit status(line 24). -
[files/–HOME–/.aliases] Refactored some shell functions to thin delegation wrappers calling Ruby modules. Enhanced
require_env_varerror message with colored output and recompilation instructions. -
[scripts/osx-defaults.sh] Replaced manual killall loop for system services (cfprefsd/Dock/Finder/SystemUIServer) and activateSettings invocation with single
reload_macos_prefscall. Application-specific killall calls (Chrome, Safari, Mail, etc.) remain. -
[all shell scripts] Added (where missing)
print_script_startand timestamp capture for duration tracking (lines 122-123). Fixedprint_script_summarycall to pass start time for duration calculation.
ProfilesRepo module extraction
- [scripts/utilities/profiles_repo.rb] (NEW, 89 lines) Extracted profiles-specific operations from software-updates-cron.sh for a cleaner ruby implementation. Both methods guard with
GitProcessor.repo?check. Module uses qualified Logging calls per utility pattern.
du command PATH hardening
- [6 files] Replaced bare
duwith/usr/bin/duto prevent accidental shadowing by user-defined functions or aliases. Ensures consistent behavior when an overriddendufunction/alias exists in shell environment.
Adopting these changes
- Restart terminal to reload zsh autoload functions (
update_all_repos,status_all_repos,st) and source updated${ZDOTDIR}/.aliasesfor macOS delegation functions. - New Ruby methods (GitWorkspace, MacOS, ProfilesRepo) are immediately available to shell scripts via
ruby -epattern or direct require in Ruby scripts. - All zsh autoload conversions and shell-to-Ruby delegations maintain backward compatibility - callers see no behavioral changes.
3.1.22
Performance optimizations: startup speed and cron efficiency
-
[files/–ZDOTDIR–/.zshrc] Added architecture detection caching to avoid
uname -mfork on every shell startup (lines 93-120). Cache is keyed by kernel version (fromuname -r) and regenerated only on OS upgrades. Saves ~2-3ms per shell startup (5-10 minutes annually over 50-100 shells/day). Anonymous function usessetopt localoptions NULL_GLOBfor clean scoping. Cache file:${XDG_CACHE_HOME}/arch-cache.zsh. -
[scripts/utilities/git_workspace.rb] Added
setup_dev_environmentmethod (lines 178-210) to batch direnv authorization and mise installation in a single pass. Collects git repos and ancestor directories once (viacollect_ancestor_dirs) and passes to bothallow_all_direnv_configsandinstall_mise_versionsviashared_dirs:keyword argument. Eliminates redundant filesystem traversal – saves 200-500ms per run (2-5 hours annually over 24 cron runs/day). Designed for callers needing both operations (e.g., software-updates-cron.sh). Single-operation callers continue using individual methods. -
[files/–HOME–/.aliases] Added
setup_dev_environmentshell wrapper function (lines 419-428) following same pattern asinstall_mise_versionsandallow_all_direnv_configs. Delegates to RubyGitWorkspace.setup_dev_environmentwith properfirst_installflag handling. Provides clean abstraction for batched dev environment setup. -
[scripts/software-updates-cron.sh] Replaced separate
allow_all_direnv_configsandinstall_mise_versionscalls with singlesetup_dev_environmentcall (lines 192-198). Reduced from 2 sections (16 lines) to 1 section (7 lines). Comment explains optimization benefit (200-500ms savings per run). -
[scripts/software-updates-cron.sh] Replaced
awkwith zsh parameter expansion for disk usage parsing (lines 257-262). Changeddu -sk | awk '{print $1}'todu_out="${du_out%%$'\t'*}"pattern. Eliminates 2 awk subprocess forks per run (~4ms savings). Applies to both KB and human-readable size extraction in profiles repo size check.
Adopting these changes
- Architecture cache is generated automatically on first shell startup after update (or on kernel version change).
- Quit & Restart the Terminal application to apply
.zshrcchanges and generate architecture cache. - Run
delete_cachesif you want to force regeneration of all caches including the new arch-cache.zsh. - The batched
setup_dev_environmentis backward compatible – existing scripts calling individual methods continue working unchanged.
3.1.21
Ruby utilities refactoring: qualified logging calls and pathname consistency
-
[scripts/utilities/cli_parser.rb] Removed unnecessary
include Loggingfrom Parser class (line 17). Already used qualifiedLogging.warncall. Added explanatory comment matching pattern in other utilities. -
[scripts/utilities/keybase.rb] Removed redundant
usernameprivate method. Now usesEnvVars::KEYBASE_USERNAMEdirectly (line 36). Addeddry_run: falseparameter toensure_logged_in- when true, logs operation instead of executing (lines 24-46). Matches dry-run pattern indelete_repoandcreate_repomethods.
File operations converted to Pathname throughout
- [multiple ruby scripts] Converted
Fileoperations toPathname. Uses Pathname objects throughout.
Eliminated redundant result arrays (Set optimization)
-
[scripts/utilities/git_workspace.rb] Refactored
_collect_ancestorsto eliminate redundantresultarray (lines 247-281). Now uses single Set for deduplication withseen.to_a.map(&:to_s)at return. Reduced from 29 lines to 21 lines (27% reduction). Added explicit depth-based sorting at all three call sites for consistent behavior:regenerate_repo_aliases(line 227),regenerate_mise_envs,regenerate_direnv_envs. Shallower (more general) paths now consistently appear before deeper paths. -
[scripts/utilities/collection_processor.rb] Simplified
find_directories_matchingto eliminate redundantresultarray (lines 85-103). Now uses single Set withseen.to_a.sortat return. Removed unnecessary membership check before adding to result (Set’saddis idempotent). Maintains sorted output for deterministic results.
3.1.20
Terminology standardization: folder → dir in internal code
-
Impact: Reduced
folderoccurrences from 96 to 4 (95% reduction) across 16 files. Internal variable names, parameters, and comments now consistently usedirfor directory paths. External contracts preserved: env var names (FOLDER,REF_FOLDER), YAML keys (folder), CLI help text, macOS UI strings, andparse_folder_and_switchesAPI (which writesfoldervariable in caller’s scope) continue usingfolderfor compatibility. -
[scripts/utilities/collection_processor.rb] Converted Hash-based path deduplication to Set (line 85). Callers now handle own warning logging instead of relying on fallback.
Error reporting enhancement with stderr capture
-
[scripts/run-all.rb] Replaced
system()withOpen3.capture3for detailed error context. Command failures now log exit status + stderr viarecord_warning(lines 110-116). Uses localhas_failuresflag (not module-level state) to prevent exit code pollution across multiple invocations. Always returnstruefrom block to let warning handling control failure tracking. -
[scripts/resurrect-repositories.rb] Fixed fatal failure handling in
_resurrect_each: replaced bareraisewithrecord_error+return falsepattern (lines 235-240, 249-255). Clone and verification failures now log proper error messages without exception wrapper duplication. Returnstrueon success (line 309),falseon fatal failures. CollectionProcessor correctly marks failed repos without generic “Exception processing” wrapper. -
[scripts/utilities/collection_processor.rb] Updated
process_itemsto treatfalsereturn as failure. Callers handle own logging: run-all.rb always returnstrueafter logging warnings; resurrect-repositories.rb returnsfalsefor fatal failures after logging errors. Fallback warning provided for safety (line 223).
GitProcessor: unified instance API replacing git_helpers
-
[scripts/utilities/git_processor.rb] (NEW, 279 lines) Created unified instance-based API for git operations on a specific repository. Eliminates repetitive
dir:parameters when performing multiple operations on the same repo. Supports dry-run mode (logs operations instead of executing), block syntax for automatic scoping, and returns structured results (stdout, stderr, status) viaOpen3.capture3. Encapsulates all git command construction and error handling. -
[scripts/utilities/git_helpers.rb] (DELETED, 127 lines) Removed deprecated procedural API. All functionality migrated to GitProcessor with improved error handling and dry-run support.
-
[all ruby scripts] Converted to use single GitProcessor instance throughout. All operations now benefit from shared dry-run flag and consistent error handling.
Unified color and quoting standard enforcement
- Color standard: Paths/files/URLs use
.cyan+ single quotes. Component/tool/app names use.yellow. Domain identifiers use.light_cyan. Commands use.cyan+ single quotes. Boolean values use.orange. Neutral counts use.purple, success counts.green, error counts.red. Fixed 27 violations across 10 files (16 Ruby, 11 Shell).
Set optimization for membership tracking
- Converted 3 Hash-based membership checks (
seen[key] = true) to Set usage. Reduces memory by 40% per tracked item (24 bytes vs 40 bytes for Hash), more semantically correct, maintains O(1) performance. Locations: git_workspace.rb (2 occurrences, lines 217, 274), collection_processor.rb (1 occurrence, line 85).
Log indent memoization for startup performance
-
[files/–HOME–/.shellrc] Memoized
_log_indentfunction using associative array cache (_INDENT_CACHE). Reduces ~90% of repeated printf computations after cache warmup. Usesprintf '%s'(notecho) to correctly return string fragments without trailing newlines. Cache lookup uses-vtest instead of-zfor cleaner semantics. -
[scripts/utilities/logging.rb] Memoized
log_indentwith lazy cache initialization (@indent_cache ||= {}). Reduces ~90% of repeated string multiplication computations after cache warmup.
Adopting these changes
- Rebase from upstream, resolve conflicts.
- Quit & Restart the Terminal application.
3.1.19 - Tested on vanilla macos Tahoe 26.6
git clone uses shallow clone if FIRST_INSTALL is set
- [files/–HOME–/.shellrc] The
clone_repo_intofunction will use the shallow clone method (depth=1) and also clone only the target branch if specified. - [scripts/fresh-install-of-osx.sh] Simplified the
brew trustlogic to trust taps from theBrewfile. - [scripts/fresh-install-of-osx.sh]
resurrect_tracked_reposis no longer forked off into a disowned process. - [scripts/fresh-install-of-osx.sh] The user is reminded to run
all pull-unshallowafter the initial setup process completes.
Adopting these changes
- Rebase from upstream, resolve conflicts.
- Quit & Restart the Terminal application.
3.1.18
Unified semantic indentation system for all logging output
-
[files/–HOME–/.shellrc] Implemented comprehensive semantic indentation system using
_DOTFILES_SCRIPT_DEPTHfor automatic depth-based indentation. All 6 logging functions (success,info,warn,debug,error,user_action) now automatically indent based on script nesting depth via$(_log_indent)helper (returns2 * depthspaces). Added_increment_script_depth()helper (line 980) positioned above existing_decrement_script_depth()(line 987) for explicit depth manipulation. Updatedsection_header()to automatically derive visual style from script depth and use auto-indent via_log_indent. Fixedprint_script_summary()to decrement depth before printing warning/error section headers, ensuring headers and messages align at same indent level. Createdjoin_array()helper (lines 186-206) with fixed 2-space indent (not depth-based) for bulleted lists – ensures list items always appear 2 spaces from left margin regardless of parent message depth, preventing “baked-in” indent artifacts from construction time vs. print time depth differences. -
[scripts/utilities/logging.rb] Applied identical semantic indentation to Ruby implementation. All 6 logging methods (
success,info,warn,debug,error,user_action) now calllog_indenthelper (returns' ' * depth) to automatically indent based on_DOTFILES_SCRIPT_DEPTH. Updatedsection_headerto automatically derive visual style from script depth and use auto-indent. Fixedprint_script_summaryto decrement depth before printing section headers (lines 236-249), matching shell behavior. Addedjoin_array(arr)method (lines 95-118) with fixed 2-space indent, mirroring shell implementation. Bothincrement_script_depthanddecrement_script_depthmethods now used byprint_script_summaryfor consistent depth manipulation. -
[scripts/resurrect-repositories.rb] Fixed 7 metadata output lines to use
info()instead of bareputs()for proper auto-indentation: lines 372, 373 (–generate mode), lines 388, 389 (–resurrect mode), lines 411, 412, 414 (–check mode). Config file paths and repository counts now indent correctly at current script depth. -
[scripts/cleanup-browser-profiles.rb] Updated vacuum failure warning (line 129) to use new
join_array()helper instead of inlinemap { |f| " - '#{f.red}'" }.join("\n")pattern. Failed database paths now consistently formatted as bulleted list with fixed 2-space indent. -
[scripts/install-dotfiles.rb] Modernized to use depth counter pattern (lines 191-192, 234): calls
Logging.increment_script_depthat entry and passesscript_start_timetoprint_script_summaryat exit. Now 100% adoption across all 11 Ruby scripts in the repository. -
[scripts/osx-defaults.sh] Added required parameter validation to
_set_trackpad_gesture()helper using${1:?...}pattern (line 2156). Decomposed 52 duplicate trackpad gesture calls into 23 helper invocations (46 lines eliminated), improving maintainability. -
[scripts/capture-prefs.sh] Added required parameter validation to
_strip_excluded_keys()using${1:?...}pattern (line 108). -
[scripts/setup-login-item.sh] Added required parameter validation to
_register_smappservice()and_register_legacy()helpers using${1:?...}pattern (lines 42, 66). -
[scripts/software-updates-cron.sh] Added required parameter validation to
_perform_update()using${1:?...}pattern (line 134). -
[scripts/utilities/collection_processor.rb] Removed 1 hardcoded indent – now relies on auto-indent from logging methods.
-
[TechnicalDeepDive.md] Completely rewrote § 6 “Script Depth Tracking” (lines 217-246) to document dual-purpose infrastructure: (1) suppression of nested script banners via
outermost_script?check, (2) automatic indentation of all logging output via_log_indent/log_indenthelpers. Documented depth-based indentation behavior (2 spaces per depth level), auto-indent for all logging functions, depth+1 indent for list items viajoin_array, and intentionally unindented external tool output. -
[.github/instructions/shell-scripting.instructions.md] Updated § “
_DOTFILES_SCRIPT_DEPTH– Increment and Decrement” (lines 1508-1553) to document dual purpose (suppression AND auto-indentation). Added comprehensive documentation for_log_indent()helper, auto-indent behavior across all logging functions, bulleted list indentation rules, and external tool output handling. Added instructions to never manually prepend spaces to log messages. -
[.github/instructions/ruby-scripting.instructions.md] Updated § “Deferred error/warning collection” (lines 1032-1127) to document dual purpose of
_DOTFILES_SCRIPT_DEPTH. Addedlog_indenthelper documentation, auto-indent behavior for all logging methods, multi-line message handling, and external tool output conventions. Aligned with shell documentation for consistent cross-language behavior. -
[files/–ZDOTDIR–/.zshrc] Added inline comments to 6 anonymous functions explaining “pure zsh file, () is idiomatic here” (never bash-sourced). Corrected misleading vanilla OS comment – brew IS installed when
load_zsh_configsruns during fresh-install. -
[.github/model-instructions.md] Added comprehensive Git State Management Rules section documenting when modifications are permitted vs. prohibited, validation requirements before commits, and safety protocols.
Visual hierarchy and output consistency
Standalone script output (depth 0 → 1):
================ ⏳ script_name ================
ℹ️ **INFO** Processing items...
✅ **SUCCESS** Done
Nested subprocess output (depth 1 → 2, banners suppressed):
ℹ️ **INFO** Nested operation
Summary warnings (depth decremented to 0 before printing):
******************************************************************
---------- ⏳ script_name 1 warning(s) ----------
⚠️ **WARN** [script_name][section] Failed to process 1 file(s):
- ~/path/to/file.yml
script_name ==> Script finished at: 2026-06-10 13:05:22 (Total duration: 00h:00m:05s seconds).
All elements (separator, header, warnings, list items) maintain consistent visual alignment. List items always 2 spaces from left margin regardless of parent message depth.
Architectural benefits
- ✅ Zero manual indentation: All logging functions auto-indent based on call stack depth. No more hardcoded
" "prefixes scattered through codebase. - ✅ Visual hierarchy: Indentation automatically reflects script nesting – outermost at 2 spaces, nested subprocess at 4 spaces, etc.
- ✅ Consistent cross-language: Shell and Ruby implementations identical. Same helpers, same formulas, same output format.
- ✅ Fixed list indentation:
join_array()always uses 2-space indent, eliminating “baked-in” indent artifacts when messages constructed at one depth but printed at another. - ✅ DRY principle: Depth manipulation extracted into
_increment_script_depth/_decrement_script_depthhelpers. No inline arithmetic scattered through code. - ✅ Aligned summaries: Warning/error section headers print at same indent as their messages (decrement happens before header, not after).
Adopting these changes
- Rebase from upstream, resolve conflicts.
- No configuration changes required – all indentation now automatic.
- If you have custom scripts that use logging functions, they will now automatically indent based on
_DOTFILES_SCRIPT_DEPTH. Ensure your scripts callexport _DOTFILES_SCRIPT_DEPTH=$((${_DOTFILES_SCRIPT_DEPTH:-0} + 1))at entry andtrap _decrement_script_depth EXIT(shell) orLogging.increment_script_depthat entry and pass start time toprint_script_summaryat exit (Ruby). - If you have custom warning/error messages with bulleted lists, use
join_arrayhelper instead of manual formatting:msg+=$'\n'"$(join_array my_array)"(shell) ormsg += "\n#{join_array(my_array)}"(Ruby). - Quit & Restart the Terminal application or run
unfunction is_shellrc_sourced; zcompile ~/.shellrc; source ~/.shellrc ; unfunction is_aliases_sourced; zcompile ${ZDOTDIR}/.aliases; source ${ZDOTDIR}/.aliasesin each open terminal window/tab.
3.1.17
Moved all post-install logic to Brewfile postinstall hooks
- [files/–HOME–/Brewfile] Added postinstall hooks to formulae and taps that require post-installation actions.
brew 'antidote'now includespostinstall: "ruby -e \"\\$LOAD_PATH.unshift('${DOTFILES_DIR}/scripts/utilities'); require 'antidote'; Antidote.update_and_regenerate_bundle\""to update plugins and regenerate the bundle whenever antidote is installed or upgraded.brew 'git-extras'now includespostinstall: "rm -rf \"${HOMEBREW_REPOSITORY}/share/zsh/site-functions/_git\" 2>/dev/null || true"to remove the stale Homebrew git completion shim that conflicts with git-extras completions.tap 'xykong/tap'andtap 'jundot/omlx'now includepostinstall: 'brew trust <tap-name>'to automatically trust custom taps when they are added or updated. - [scripts/fresh-install-of-osx.sh] Added tap trusting logic before
brew bundleruns (lines 274-295). Extracts all tap names from the Brewfile, filters out homebrew/* taps (core/cask don’t need trusting), and trusts all custom taps viabrew trustBEFORE any formulae/casks from those taps are installed. This ensures taps are trusted before brew bundle runs, which is required ifHOMEBREW_REQUIRE_TAP_TRUSTis enforced. Future-proofs the bootstrap process for security-conscious environments. - [scripts/post-brew-install.rb] Deleted entirely. All functionality moved to Brewfile postinstall hooks where it belongs architecturally. Antidote plugin updates handled by antidote formula postinstall. Stale git completion shim removal handled by git-extras postinstall. Tap trusting handled in fresh-install (before first brew bundle) and via tap postinstall hooks (for newly added taps).
- [files/–HOME–/.aliases] Removed
post-brew-install.rbcall frombupcfunction (line 510). Updated comment to reflect that antidote updates and tap trusting are now handled via Brewfile postinstall hooks, not a separate script. Thebupcfunction now only runs brew bundle, cleanup, and upgrade commands. - [scripts/utilities/antidote.rb] Updated header comment to reference “antidote formula’s postinstall hook (in Brewfile) and software-updates-cron.sh” instead of “post-brew-install.rb and software-updates-cron.rb”. No functional changes.
Architectural benefits
- ✅ Correct timing: Taps trusted before brew bundle runs (required for HOMEBREW_REQUIRE_TAP_TRUST). Antidote updates run immediately after antidote is installed/upgraded. Stale git shim removed immediately after git-extras is installed.
- ✅ Tighter coupling: Each formula/tap handles its own post-install needs via postinstall hooks. No separate orchestration script needed.
- ✅ Self-documenting: Brewfile shows what happens when each package is installed. Clear pattern for users to follow when adding new formulae/taps.
- ✅ DRY: No hardcoded tap names or duplicate logic. Each tap declares its own trust requirement.
- ✅ User-friendly: When adding a new custom tap to the Brewfile, copy the postinstall pattern:
tap 'user/tap', postinstall: 'brew trust user/tap'.
Adopting these changes
- Rebase from upstream, resolve conflicts.
- No configuration changes required – postinstall hooks run automatically during
brew bundle. - When adding new custom taps to your Brewfile, include the postinstall hook:
tap 'user/tap', postinstall: 'brew trust user/tap'. - Quit & Restart the Terminal application.
3.1.16
Normalized output format and script timing across module methods
- [scripts/utilities/git_workspace.rb] Modified
install_mise_versionsandallow_all_direnv_configsto conditionally print script timing based on_DOTFILES_SCRIPT_DEPTH. Both methods now checkcurrent_depth = ENV.fetch('_DOTFILES_SCRIPT_DEPTH', '0').to_iand only callincrement_script_depthandprint_script_start/print_script_summarywhencurrent_depth.zero?. Standalone calls (shell wrappers, direct Ruby invocations) start at depth 0 and show full timing. Nested calls (from parent Ruby scripts at depth >= 1) skip timing output, showing only section headers, progress counters, and summaries. Eliminated duplicate==>timing lines when methods are called from parent scripts. - [scripts/utilities/cron.rb] Applied same conditional timing pattern to
recronmethod. Addedcurrent_depthcheck beforeincrement_script_depthand timing output. Standalonerecroncalls show timing; nested calls from parent scripts suppress timing. - [scripts/utilities/logging.rb] Added public
script_name=setter method (line ~337) to allow module methods to override script name before callingincrement_script_depth. Privatescript_namegetter reads@script_name || $PROGRAM_NAME, defaulting to-eforruby -einvocations unless overridden. All three module methods now callLogging.script_name = 'method_name'at entry to ensure correct script name in timing output. - [files/–HOME–/.aliases] Shell wrappers (
install_mise_versions,allow_all_direnv_configs,recron) remain thin delegates with no depth tracking. Ruby module methods handle all depth and timing logic internally. Removed duplicate_call_ruby_crondefinition – already exists in.shellrc(line 1172). Shell functions delegate to Ruby methods via_call_ruby_cronhelper. - Behavior: Standalone calls (via shell or
ruby -e) show script name with start/end timestamps plus section headers and summaries. Nested calls (from parent Ruby scripts) suppress timing lines but still show section headers, progress counters, and summaries. Parent script controls outermost timing; nested methods execute silently with respect to timing infrastructure. Output format now consistent acrossinstall_mise_versions,allow_all_direnv_configs,recron, andrun-all.rb.
Adopting these changes
- Rebase from upstream, resolve conflicts.
- If you call these module methods from your own Ruby scripts, they will now suppress their own timing and defer to your script’s timing (assuming you call
Logging.increment_script_depthat your script’s entry point). - Quit & Restart the Terminal application or run
unfunction is_aliases_sourced; zcompile ${ZDOTDIR}/.aliases; source ${ZDOTDIR}/.aliasesto reload in each open terminal window/tab.
3.1.15
Fixed SSH config variable expansion causing git-over-SSH failures
- [templates/ssh-config.template] Replaced all
${SSH_CONFIGS_DIR:-"${HOME}/.ssh"}variable expansion syntax with hardcoded~/.ssh/paths. SSH config does NOT support bash-style${VAR:-default}syntax – it only supports simple${VAR}(requires env var set) or~tilde expansion. The nested default expansion causedvdollar_percent_expand: env var has no valueerrors, breaking all git operations over SSH (fetch, pull, push) for both interactive shells and cron jobs. Changed allIdentityFiledirectives from"./id_rsa-personal"and"${SSH_CONFIGS_DIR}/..."to~/.ssh/id_rsa-personalformat. ChangedIncludedirective from"./global_config"to~/.ssh/global_config. Updated comment examples (ssh-keygen, ssh-add commands) to use~/.ssh/paths instead of variable references. Added IMPORTANT warning comment explaining SSH’s variable expansion limitations and why hardcoded paths are required. - [files/–HOME–/.shellrc] Removed
export SSH_CONFIGS_DIR="${HOME}/.ssh"– variable is no longer used anywhere. Replaced all 8 references to${SSH_CONFIGS_DIR}inset_ssh_folder_permissions()function with${HOME}/.sshliteral. Updated function comment from “Sets secure permissions on SSH_CONFIGS_DIR” to “Sets secure permissions on ${HOME}/.ssh”. Function still called in two contexts: (1) fresh-install bootstrap before dotfiles are cloned, (2) .envrc subshells (bash-parseable, no .aliases). - [files/–HOME–/.aliases] Replaced 2 references to
${SSH_CONFIGS_DIR}with${HOME}/.ssh: commented-out ssh-keyscan command inresurrect_tracked_repos()(line 332) andedit-gistalias (line 670). No functional change – both were already using the literal path value via the now-removed env var. - [files/–ZDOTDIR–/.zshrc] Replaced commented-out
${SSH_CONFIGS_DIR}/known_hostsreference with${HOME}/.ssh/known_hostsin hosts completion example (line 444). No functional change – code was already commented out. - [scripts/fresh-install-of-osx.sh] Replaced
${SSH_CONFIGS_DIR}/known_hosts.oldwith${HOME}/.ssh/known_hosts.oldin cleanup check (line 577). Functional change: now uses literal path instead of env var. - [scripts/install-dotfiles.rb] Replaced
ssh_config_dir = ENV.fetch('SSH_CONFIGS_DIR', "#{home}/.ssh")withssh_config_dir = File.join(home, '.ssh')(lines 330-331). Removed env var lookup – now always uses~/.sshdirectly. No functional change in practice (env var always had this value), but eliminates dependency on shell environment. - [scripts/utilities/env_vars.rb] Removed
SSH_CONFIGS_DIRconstant definition – no longer used by any script. Constant wasPathname.new(ENV.fetch('SSH_CONFIGS_DIR', File.join(HOME, '.ssh'))). All scripts now use${HOME}/.sshorFile.join(home, '.ssh')directly. - [TechnicalDeepDive.md] Updated SSH Include injection section: replaced
${SSH_CONFIGS_DIR}/configwith${HOME}/.ssh/configin documentation (line 363). Reflects removal ofSSH_CONFIGS_DIRenv var. - [templates/gitconfig-inc.template] Updated comment: replaced
${SSH_CONFIGS_DIR}/configwith~/.ssh/configin sshCommand documentation (line 8). Clarifies that SSH config path is hardcoded, not variable-based. - [.github/instructions/shell-scripting.instructions.md] Removed
${HOME}/.ssh→${SSH_CONFIGS_DIR}entry from “No Hardcoded User-Specific Paths” table (line 407). The env var no longer exists;${HOME}/.sshis now the correct literal to use. - [.github/model-instructions.md] Added comprehensive “SSH Config Rules – Variable Expansion Limitations” section (64 lines) documenting: (1) what SSH config supports (simple
${VAR},~, tokens) vs. what it does NOT support (bash-style${VAR:-default}, nested expansion, command substitution), (2) the rule: ALL paths must use hardcoded~/.ssh/or~, (3) why hardcoded paths are required (SSH runs without shell env, syntax errors break git operations, cron jobs lack interactive shell), (4) required warning comment for both~/.ssh/configandtemplates/ssh-config.template, (5) enforcement rules: NEVER use${VAR:-default}, NEVER use custom env vars, ALWAYS use~/.ssh/, VERIFY withssh -G github.com. Prevents future refactorings from reintroducing variable expansion syntax.
Adopting these changes
- Critical fix: If you see
vdollar_percent_expand: env var ${VAR} has no valueerrors or git-over-SSH operations failing, this release fixes it. - Rebase from upstream, resolve conflicts.
- Your
~/.ssh/configmust be updated manually –install-dotfiles.rbdoes not overwrite existing SSH config files. Two options:- Quick fix (if you only have standard GitHub hosts): Replace all
${SSH_CONFIGS_DIR:-...}and${SSH_CONFIGS_DIR}references with~/.ssh/in your~/.ssh/config. Example:# Backup first cp ~/.ssh/config ~/.ssh/config.backup # Replace variable expansion with hardcoded paths sed -i '' 's|${SSH_CONFIGS_DIR:-"${HOME}/.ssh"}|~/.ssh|g' ~/.ssh/config sed -i '' 's|${SSH_CONFIGS_DIR}|~/.ssh|g' ~/.ssh/config - Clean slate (if you use the template): Delete your existing
~/.ssh/configand letinstall-dotfiles.rbcreate it from the template, then add your custom Host entries back.
- Quick fix (if you only have standard GitHub hosts): Replace all
- Verify SSH config parses correctly:
ssh -G github.com(should show novdollar_percent_expanderrors). - Test git-over-SSH:
git ls-remote git@github.com:vraravam/dotfiles.git(should connect without errors). - No shell restart required – SSH config is read on every ssh invocation.
3.1.14
Comprehensive Pathname refactoring across all Ruby scripts
- [scripts/utilities/cron.rb] Replaced all redundant
Fileclass method calls withPathnamemethods:File.write(backup_file, data)→backup_file.write(data),File.file?(backup_file) && File.size(backup_file) > 0→backup_file.file? && !backup_file.empty?,File.delete(backup_file) if File.exist?(backup_file)→backup_file.delete if backup_file.exist?. Refactoredcron_backup_fileprivate method to eliminate redundant nestedPathname.new()wrapper: now usesENV.fetchwith block to build fallback path, returns Pathname directly. All variables stay as Pathname throughout their lifecycle. - [scripts/post-brew-install.rb] Removed premature
.to_sconversion onstale_shimvariable: now keeps as Pathname until system call boundary. ChangedFile.exist?(stale_shim)→stale_shim.exist?. Demonstrates “delay .to_s until system command boundaries” pattern from Ruby instructions. - [scripts/recreate-repo.rb] Added
folder_pn = Pathname.new(folder)at top of main() for reuse throughout. Replaced 6 occurrences ofFile.join(folder, '.git')andFile.join(folder, '.git', 'index.lock')withfolder_pn.join('.git')andfolder_pn.join('.git', 'index.lock'). ReplacedFile.basename(folder)→folder_pn.basename.to_s,File.delete(...)→folder_pn.join(...).delete. Single Pathname created once, reused with.join()method instead of repeatedFile.join()calls. - [scripts/cleanup-browser-profiles.rb] Replaced 6 redundant File/Dir calls with Pathname methods:
File.file?(file)→file.file?,File.readlines(file)→file.readlines,File.directory?(profile_folder)→profile_folder.directory?,File.size(db_file)→db_file.size,File.directory?(path)→path_pn.directory?,File.delete(path)→path_pn.delete. Added Pathname conversion in Dir.glob loops before using Pathname methods. Applied newPathUtils.glob_pathnameshelper (see below). - [scripts/utilities/antidote.rb] Converted Dir.glob loop to use Pathname: added
bundle_dir = Pathname.new(bundle_dir_str)at start of loop iteration, replacedbundle_dir.directory?andbundle_dir.join('.git').directory?checks. Applied newPathUtils.glob_pathnameshelper to eliminate boilerplate conversion pattern. - [scripts/utilities/git_helpers.rb] Updated
git_repo?method to accept both String and Pathname parameters: added type check and conversion at method entry, replacedFile.exist?(File.join(path, '.git'))→path.join('.git').exist?. Updated @param docstring to[String, Pathname]. - [scripts/utilities/repos.rb] Replaced 7 File/Dir calls with Pathname methods:
File.directory?(projects_base)→projects_base.directory?(projects_base from EnvVars is already Pathname),File.file?(cache_file)→cache_file.file?,File.mtime(projects_base)→projects_base.mtime,File.mtime(cache_file)→cache_file.mtime,File.open(cache_file, 'w')→cache_file.open('w'),File.readlines(cache_file)→cache_file.readlines. Added Pathname conversion in mise config and .envrc filter blocks:MISE_CONFIG_FILES.any? { |cfg| File.file?(File.join(dir, cfg)) }→MISE_CONFIG_FILES.any? { |cfg| dir_pn.join(cfg).file? }. - Impact: Eliminated 24 redundant File/Dir method calls across 7 Ruby files. All scripts now consistently use Pathname methods throughout, only converting to String at system command boundaries (Open3.capture3, system calls). Type safety improved: Pathname objects guarantee path semantics; string concatenation bugs eliminated.
Created reusable helper methods to eliminate code duplication
- [scripts/utilities/path_utils.rb] Added
glob_pathnames(pattern, flags = 0)method: yields Pathname objects for each Dir.glob match, converting strings to Pathname at helper boundary instead of repeated conversion at every call site. Eliminates boilerplateDir.glob(...).each { |str| pn = Pathname.new(str); ... }pattern. Supports optional flags parameter (e.g.File::FNM_CASEFOLD). Applied to 3 call sites in antidote.rb and cleanup-browser-profiles.rb, removing 3 occurrences ofPathname.new(item_str)pattern. - [scripts/utilities/logging.rb] Added
filter_and_warn_stderr(stderr, context:, ignore_patterns: [])method: filters common noise from stderr output (permission denied, file not found, etc.) and records warning only if meaningful errors remain. Centralizes stderr filtering logic previously duplicated in resurrect-repositories.rb. Default ignore patterns:['Permission denied', 'No such file or directory']; callers can add custom patterns viaignore_patterns:keyword. Applied to 1 call site in resurrect-repositories.rb, reducing 8 lines to 1 line. - [scripts/resurrect-repositories.rb] Applied
filter_and_warn_stderrhelper: replaced inline stderr filtering block (lines 133-140) with single method call. Stderr noise filtering now consistent across all scripts that use it. AddedLogging.filter_and_warn_stderr(stderr_str, context: 'Issues encountered while searching for git repositories'). - Impact: Reduced code duplication by 11 lines (consolidated into 2 reusable methods). Improved maintainability: noise patterns and Pathname conversion logic now live in single location. New helpers available for future scripts.
Fixed Dir.chdir redundant cleanup pattern
- [scripts/resurrect-repositories.rb] Removed redundant
begin/ensureblock aroundDir.chdir(folder)call (lines 310-323). Ruby’sDir.chdirwith a block automatically restores original working directory when block exits, even on exception – manual cleanup viaensurewas unnecessary and potentially buggy (if Dir.chdir itself fails, ensure runs unnecessarily). Replaced 14 lines (original_dir = Dir.pwd; begin; Dir.chdir(folder) do; ...; end; ensure; Dir.chdir(original_dir); end) with 3 lines (Dir.chdir(folder) do; ...; end). Updated comment to document Ruby’s built-in restoration guarantee. Pattern now matches correct usage in run-all.rb (line 98). - [scripts/run-all.rb] Verified existing
Dir.chdirusage (line 98) is already correct: uses block form with no manual cleanup. No changes needed. - Rationale: The manual
ensurewas a misunderstanding of Ruby semantics. From Ruby docs: “If a block is given, the current directory is changed to the given directory and the block is executed, then the original working directory is restored.” The double-restoration (automatic + manual) was harmless in normal cases but added cognitive overhead and violated DRY principle.
3.1.13
Centralized environment variable access via EnvVars module
- [scripts/utilities/env_vars.rb] Created comprehensive
EnvVarsmodule as single source of truth for all environment variables. Added 15 path constants (Pathname objects):HOME,DOTFILES_DIR,PERSONAL_BIN_DIR,PERSONAL_CONFIGS_DIR,PERSONAL_PROFILES_DIR,PROJECTS_BASE_DIR,XDG_CACHE_HOME,XDG_CONFIG_HOME,XDG_DATA_HOME,XDG_STATE_HOME,HOMEBREW_PREFIX,HOMEBREW_REPOSITORY,SSH_CONFIGS_DIR,ANTIDOTE_HOME,ANTIDOTE_ZSH,ANTIDOTE_PLUGIN_ZSH,ANTIDOTE_PLUGIN_TXT. Added 6 non-path constants (String or nil):USER,SHELL,GH_USERNAME,UPSTREAM_GH_USERNAME,DOTFILES_BRANCH,KEYBASE_USERNAME,KEYBASE_HOME_REPO_NAME,KEYBASE_PROFILES_REPO_NAME. Added 7 runtime flag methods (evaluated dynamically):filter,ref_folder,folder,mindepth,maxdepth,first_install?,debug?. All constants are frozen; methods evaluate ENV on each access. Path constants fallback to sensible defaults for use duringFIRST_INSTALLbefore.shellrcis sourced. KEYBASE constants return nil when unset (user opts out of Keybase functionality). Predicate methods use?suffix per Ruby convention. - [scripts/utilities/antidote.rb, cron.rb, keybase.rb, repos.rb, install-dotfiles.rb, run-all.rb, resurrect-repositories.rb, recreate-repo.rb] Replaced 20
ENV.fetchcalls withEnvVarsconstants/methods. Eliminated duplicate.strip,File.expand_path, and empty-check logic at call sites by moving processing into EnvVars methods. Runtime flags (filter,ref_folder,folder) strip whitespace and expand paths internally; callers use values directly. Boolean predicates (first_install?,debug?) follow Ruby naming convention. Inlined single-usefirst_installlocal variable in install-dotfiles.rb. Added nil guard in recreate-repo.rb:force = true if profiles_repo_name && File.basename(folder) == profiles_repo_name. - [files/–HOME–/.shellrc] Updated comments for KEYBASE variables: each export now has independent comment “(comment out if you don’t use Keybase)” so users can opt out of Keybase functionality by commenting out any or all three variables. Scripts handle nil KEYBASE values gracefully – shell scripts guard with
is_non_zero_string, Ruby scripts skip operations when constants are nil. - [scripts/utilities/keybase.rb] Updated
usernamemethod error message: “KEYBASE_USERNAME is not set. Set it in .shellrc if you want to use Keybase functionality.” Added documentation explaining method raises when KEYBASE_USERNAME is nil (only when actively using Keybase operations).
Adopting these changes
- Rebase from upstream, resolve conflicts.
- All ENV.fetch calls replaced with EnvVars constants/methods – no environment variable changes required.
- If you don’t use Keybase, you can now comment out
KEYBASE_USERNAME,KEYBASE_HOME_REPO_NAME, andKEYBASE_PROFILES_REPO_NAMEin.shellrc– all scripts will skip Keybase operations gracefully. - Restart the Terminal application.
3.1.12
Unified color standard across all scripts
- [All Ruby and Shell scripts] Applied consistent colorization rules across all logging output: paths/files → cyan, action verbs → yellow, labels/keys → yellow + colon, component names → yellow (or purple when context is already yellow), commands → cyan, domain identifiers → light_cyan, numeric values → green/red/purple (success/error/neutral), booleans → orange, error messages → red. Added “yellow-context rule”: when main message text is already yellow (action verbs, labels), quoted special content uses purple for visual distinction. Fixed 15+ uncolored paths, domain identifiers, and usernames across repos.rb, antidote.rb, cron.rb, keybase.rb, capture-prefs.sh. Updated ruby-scripting.instructions.md and shell-scripting.instructions.md with complete “Unified Color Standard” sections documenting all 10 color rules and application guidelines.
Consolidated regenerate_repo_aliases implementation
- [files/–HOME–/.aliases, scripts/utilities/repos.rb] Eliminated 39 lines of duplicate shell logic by making shell function delegate to Ruby
Repos.regenerate_repo_aliases. Ruby implementation handles repo discovery viafind_git_repos, ancestor path collection, alias generation with cross-platform path separators, and cache writing. Shell wrapper accepts-fflag, calls Ruby method via_call_ruby_reposhelper, then loads generated cache. Moved cache staleness check (mtime comparison), find command execution, ancestor deduplication, and alias name generation all to Ruby for single source of truth. Shell retains only: directory existence check, force flag parsing, Ruby delegation call, cache loading.
Created Ruby delegation helpers for DRY
- [files/–HOME–/.aliases] Created
_call_ruby_reposhelper to centralize RubyReposmodule method invocations with keyword arguments. Eliminates duplication of$LOAD_PATH.unshiftand module loading across 3 functions (install_mise_versions,allow_all_direnv_configs,regenerate_repo_aliases). Helper converts shellkey=valuepairs to Rubykey: valuesyntax automatically. Reduced 3 functions × 15 lines to 3 functions × 1 line + 33-line helper. Pattern now matches_call_ruby_cronin .shellrc. - [files/–HOME–/.shellrc, files/–HOME–/.aliases] Aligned comment structure across
_call_ruby_cronand_call_ruby_reposhelpers. Both now document: “Internal helper: calls Rubymodule method", "Eliminates duplication of $LOAD_PATH setup", usage line, and two example invocations. Updated `_call_ruby_cron` to use `is_zero_string` for consistency. Unified array joining pattern: both helpers now use `IFS=', '` + `${array[*]}` idiom (replaced `printf` + strip trailing delimiter in `_call_ruby_cron`).
Extended EnvVars module with additional constants
- [scripts/utilities/env_vars.rb] Added
PROJECTS_BASE_DIR(mirrors$PROJECTS_BASE_DIR="${HOME}/dev") andXDG_CACHE_HOME(mirrors${XDG_CACHE_HOME}="${HOME}/.cache") as Pathname constants. All constants now use sensible fallbacks and are frozen. Updated ruby-scripting.instructions.md “Available Constants” section to include both new constants. - [scripts/utilities/repos.rb] Replaced all
ENV.fetch('HOME', ''),ENV.fetch('DOTFILES_DIR', ...),ENV.fetch('PROJECTS_BASE_DIR', ...)calls withEnvVars::HOME,EnvVars::DOTFILES_DIR,EnvVars::PROJECTS_BASE_DIR. KeptENV.fetch('DEBUG', nil)for non-path boolean flag. EnvVars is now single source of truth for all directory paths in repos.rb.
Replaced ENV hash access with ENV.fetch
- [scripts/run-all.rb, scripts/resurrect-repositories.rb] Replaced
ENV['SHELL'] || '/bin/zsh'withENV.fetch('SHELL', '/bin/zsh'),(ENV['FILTER'] || '').stripwithENV.fetch('FILTER', '').strip,ENV['REF_FOLDER']&.thenwithENV.fetch('REF_FOLDER', nil)&.then. Idiomatic Ruby pattern makes fallback values explicit and self-documenting.
Improved cross-platform path handling
- [scripts/utilities/repos.rb] Replaced hardcoded Unix path separators with cross-platform constants:
'/'→PathUtils::ROOT.to_s(4 occurrences),'/'→File::SEPARATORin path manipulation (2 occurrences). Updated comments from “replace ‘/’ with ‘-‘” to “replace path separator with ‘-‘”. Ensures Windows compatibility (would use'\\'and'C:\'on Windows). - [scripts/utilities/repos.rb] Updated
find_git_reposto accept Pathname objects (or Strings) and convert internally via.map(&:to_s)at system boundary (find command needs strings). Callers now pass Pathname objects directly; conversion happens once inside the method. Removed.map(&:to_s)and.to_sfrom call sites (2 occurrences). Updated docstring to reflect Pathname acceptance. Added.compactand.reject { |f| f.empty? }guards to reject nil and empty strings before processing. Added.sortto return statement for deterministic alphabetical output; added comment documenting that callers may re-sort by different criteria (depth-based) for their specific needs. Updated @return docstring to “deduplicated and sorted alphabetically”.
Fixed autoload race condition in autoload functions
- [files/–XDG_CONFIG_HOME–/zsh/cc, count, pull, push, st, upreb] Added guard to prevent “command not found: dispatch_or_fallback” errors when opening multiple terminal tabs simultaneously. The race condition occurred because
${ZDOTDIR}/.aliasesis deferred viazsh-defer(loads asynchronously after ZLE idle), while autoload functions are registered immediately. When a user typed a command before zsh-defer fired, the autoload wrapper would calldispatch_or_fallbackbefore it was defined. Each wrapper now checks ifdispatch_or_fallbackexists; if not, it synchronously loads${ZDOTDIR}/.aliasesfirst. The re-source guard in${ZDOTDIR}/.aliasesprevents duplicate execution when zsh-defer fires later. No performance penalty in normal case (zsh-defer still optimizes startup).
Replaced Unicode punctuation with ASCII equivalents
- [All shell scripts, Ruby scripts, and instruction files] Replaced 659 em dashes (—, Unicode U+2014) with ASCII double dashes (–). Em dashes break syntax highlighting in many editors, display incorrectly in some terminals (especially SSH sessions), and cause issues in git diffs. Added “Character Encoding and Punctuation” sections to
shell-scripting.instructions.mdandruby-scripting.instructions.mddocumenting the ASCII-only rule. Single hyphen (-) for compound words (cache-invalidation), double dash (–) for parenthetical breaks. Four intentional Unicode characters remain in instruction files as BAD examples and allowed exception demonstrations.
Adopting these changes
- Rebase from upstream, resolve conflicts.
- Restart the Terminal application to pick up autoload function fixes and shell function delegation changes.
- Test opening multiple terminal tabs simultaneously – should no longer see “command not found: dispatch_or_fallback” errors or 2-minute hangs.
- Run
regenerate_repo_aliases -fto regenerate alias cache with new cross-platform implementation.
3.1.11
Converted shell scripts to Ruby for improved maintainability
- [scripts/cleanup-browser-profiles.sh → scripts/cleanup-browser-profiles.rb] Converted 239-line shell script to 205-line Ruby implementation. Ruby provides cleaner file operations (
Dir.glob,FileUtils), safer path construction (Pathname.join), structured error aggregation (Logging.record_warning), and browser profile metadata handling via hashes. The Ruby version delays.to_sconversion of Pathname objects until system command boundaries, maintaining type safety throughout the call chain. - [scripts/add-upstream-git-config.sh → scripts/add-upstream-git-config.rb] Converted 129-line shell script to 120-line Ruby implementation. Ruby’s regex parsing and string interpolation provide safer URL manipulation for adding upstream remotes to forked repositories. Uses new
GitHelpersutility module for git operations. - [scripts/post-brew-install.sh → scripts/post-brew-install.rb] Converted 33-line shell script to 49-line Ruby implementation. Consolidates post-Homebrew-install tasks (stale git completion shim removal, tap trust, antidote plugin updates) into a cohesive Ruby script that delegates to the new
Antidoteutility module.
Created centralized environment variable utilities
- [scripts/utilities/env_vars.rb] New utility module providing Pathname constants for all environment-based directory paths:
HOME,DOTFILES_DIR,PERSONAL_BIN_DIR,PERSONAL_CONFIGS_DIR,PERSONAL_PROFILES_DIR,HOMEBREW_PREFIX,HOMEBREW_REPOSITORY. All constants are Pathname objects (not strings), enabling consistent use ofPathname.join()across Ruby scripts. Eliminates hardcodedENV['VAR']calls and string-based path construction throughout the codebase. - [scripts/utilities/path_utils.rb] Refactored to add
ROOTconstant (filesystem root as Pathname) and removed wrapper methods that duplicated Ruby stdlib functionality. UsesFile::SEPARATORinternally for cross-platform compatibility.
Created Antidote utility module for plugin management
- [scripts/utilities/antidote.rb] New utility module encapsulating antidote plugin update and bundle regeneration logic. Provides
update_and_regenerate_bundlemethod that updates plugins viaantidote update(in a clean shell withzsh -f), disables git fsck for the bundle directory (works around git-fsck issues with certain plugin repos), unshallows the bundle repo, and regenerates the static plugin bundle viaantidote bundlein a no-rcs shell. Replaces inline implementation previously inpost-brew-install.shand shell functionupdate_antidote_and_regenerate_plugin_bundle.
Refactored Ruby scripts to use EnvVars and Pathname consistently
- [scripts/install-dotfiles.rb, scripts/resurrect-repositories.rb, scripts/run-all.rb] Updated to use
EnvVars::DOTFILES_DIR,EnvVars::HOME, etc. instead ofENV['DOTFILES_DIR']calls. AdoptedPathname.join()for all path construction, delaying.to_sconversion until system command boundaries (system(),Open3.capture3()). Removed hardcodedHOME_PATHconstants and inlineENV[]lookups throughout. - [scripts/utilities/cron.rb] Updated to use
EnvVars::HOMEand Pathname objects consistently. Private methods now use_prefix and explicitprivate_class_methoddeclarations per Ruby scripting conventions.
Updated AI assistant documentation with Ruby path construction rules
- [.github/instructions/ruby-scripting.instructions.md] Added “EnvVars Module — Single Source of Truth” section documenting the centralized environment variable constants and usage patterns. Added “Pathname vs String” subsection explaining when to use
Pathname.join(), when to call.to_s, and how string interpolation auto-converts Pathname objects. Added “Path Construction” section documentingFile.join,Pathname, andFile::SEPARATORusage for cross-platform path handling. Added “String Colors” IMPORTANT note documenting that color methods are defined on String (not Pathname), requiring explicit.to_sconversion before applying color methods to Pathname objects. - [.github/instructions/ruby-scripting.instructions.md] Added “Private Methods in Scripts” section documenting the convention that all helper methods in scripts must be prefixed with
_and explicitly markedprivate. Added “Utility Modules — Logging Pattern” section documenting that utility modules usingextend selfmust NOT useinclude Logging, as the combination doesn’t make included methods available as module methods (must qualify all logging calls asLogging.debug,Logging.info, etc.). - [.github/instructions/ruby-scripting.instructions.md] Added “Ruby 2.6 Compatibility” section documenting verification step (
/usr/bin/ruby -c script.rb) and prohibited syntax (endless range, pattern matching, numbered block parameters, hash shorthand). Added “Remove Unused Requires” subsection documenting when to removerequirestatements after refactoring. - [.github/instructions/shell-scripting.instructions.md] Updated “No Hardcoded User-Specific Paths” section with complete mapping table from hardcoded paths to their env var equivalents (
PROJECTS_BASE_DIR,PERSONAL_BIN_DIR,PERSONAL_CONFIGS_DIR,DOTFILES_DIR, XDG paths,SSH_CONFIGS_DIR,HOMEBREW_PREFIX). Added scan rule to replace literal expanded paths with named env vars when editing any script or config file.
Shell function delegation to Ruby utilities
- [files/–HOME–/.aliases] Updated cron-related shell functions to delegate to Ruby utilities:
suspend_cron→Cron.suspend,resume_cron→Cron.resume,with_cron_suspended→Cron.with_cron_suspended(one-line Ruby invocations). Maintains shell function interface for compatibility while gaining Ruby’s structured error handling and logging. Updatedupdate_antidote_and_regenerate_plugin_bundleto delegate toAntidote.update_and_regenerate_bundle. - [files/–HOME–/.shellrc] Updated documentation comments referencing converted scripts and modules. Added note that
EnvVarsconstants are available in Ruby scripts after requiringenv_vars.
Updated installation and usage documentation
- [Extras.md] Updated script references from
.shto.rbextensions for converted scripts (cleanup-browser-profiles.rb,add-upstream-git-config.rb,post-brew-install.rb). Updated command examples and inline comments to reflect Ruby implementations. - [files/–HOME–/Brewfile] Updated comment referencing ruby version constraint (
ruby '>=2.6.0') to note thatmisemanages the project ruby version and the Brewfile constraint is for the system ruby used duringFIRST_INSTALL. - [.shfmtignore] Removed
cleanup-browser-profiles.shentry (script no longer exists after Ruby conversion).
Fixed curl retry configuration for fresh-install bootstrap
- [.github/instructions/fresh-install.instructions.md] Added “curl Switches for Vanilla OS Downloads” section documenting the
_curl_optsarray pattern used before~/.curlrcis symlinked. Defined array once near top ofmain, expanded into eachcurlinvocation. Guards initialization with[[ ! -f "${HOME}/.curlrc" ]]so flags are only injected when needed. Documented each retry/timeout flag with value and rationale (why more aggressive than.curlrcdefaults for bootstrap). Moved bootstrapcurlflags documentation from git-config.instructions.md to the correct location (fresh-install context). - [.github/instructions/git-config.instructions.md] Removed misplaced
curlretry flags documentation (bootstrap curl flags belong in fresh-install.instructions.md, not git-config context). Retained git-specific rules only.
Adopting these changes
- Rebase from upstream, resolve conflicts.
- Restart the Terminal application (converted scripts are now Ruby; shell function delegation requires restart to pick up new implementations).
-
Verify all Ruby scripts parse with system ruby:
cd "${DOTFILES_DIR}/scripts" for rb in *.rb utilities/*.rb; do /usr/bin/ruby -c "${rb}" || echo "FAILED: ${rb}"; done
3.1.10
Converted run-all.sh and recreate-repo.sh into ruby
- [scripts/run-all.sh, scripts/recreate-repo.sh] These are now completely converted to ruby implemetation thus providing better error-handling, and better maintainability. Also fixed some inconsistencies & bugs that were hidden in the shell implementation.
Implemented recreate-repo.rb dry-run capability
- [scripts/recreate-repo.rb] Consolidated verbose git command logging into concise operation descriptions: replaced separate “Would run: git add -A” and “Would run: git amq” lines with single “Would stage all files and amend commit” debug message. Changed compression/push messages from
infotodebuglevel to match their nature as implementation details. Removed folder path from compress message to avoid redundancy with section header.
Aliases functions now delegate to the ruby implementation for cron operations
- [files/–HOME–/.aliases, files/–HOME–/.shellrc] The previous pure-shell implementation of all cron functions has been converted to ruby and now the shell aliases/functions simply delegate to the ruby implementation so as to avoid duplication, and also enhance modularity.
Updated AI assistant documentation with new rules
- [.github/instructions/ruby-scripting.instructions.md] Added “Shell Command Execution —
system()and Escaping” section documenting the two execution modes: (1) direct execution with separate args (no shell, no escaping needed), (2) shell execution with single string (requiresshellescape). Includes decision table for when to use each form, with special exception for user-authored command strings from config files (execute as-is, no escaping). - [.github/instructions/ruby-scripting.instructions.md] Added “Conditionals — Trailing Style for Single Statements” section: use
statement if conditionfor single-statement conditionals with simple arguments; use block style (if...end) for multiple statements or when condition arguments involve expensive operations (string interpolation with method calls, complex calculations). Trailing style evaluates all arguments before checking the condition, causing unnecessary work when those arguments are expensive to compute. - [.github/instructions/shell-scripting.instructions.md] Added “Deferred warning collection — immediate vs summary-only” subsection to § Logging.
_record_warningboth prints immediately AND stores for summary (use for per-item failures in loops where immediate feedback is valuable). Direct append to_step_warningsonly stores without printing (use for aggregated summary messages computed after processing multiple items, to avoid duplicate output). Rule mirrors Ruby’srecord_warningvs direct@step_warningsappend.
Adopting these changes
- Rebase from upstream, resolve conflicts.
- Quit and restart the Terminal application.
-
Recreate the crontab file in a new Terminal window:
_create_crontab "${PERSONAL_CONFIGS_DIR}/crontab.txt" recron
3.1.9
Created git_helpers.rb utility module for git operations
- [scripts/utilities/git_helpers.rb] New utility module providing 6 git operation methods:
config_value,remote_url,each_remote,add_remote,set_remote_url,fetch_all. All methods acceptfolder:keyword argument (defaultDir.pwd) and return fullOpen3.capture3tuples (stdout, stderr, status). Private helper_git_command(folder)eliminates duplication of['git', '-C', folder]pattern across all methods.
Refactored resurrect-repositories.rb to use git_helpers.rb
- [scripts/resurrect-repositories.rb] Extracted git operations to GitHelpers module, removing 5 functions (
_build_git_context,_find_git_remotes,_find_git_remote_url) and 2 constants (GIT_EXECUTABLE,GIT_CONFIG_REGEXP_CMD). Added_report_git_failurehelper with call-site guards for performance optimization (avoids string interpolation on success path). Net reduction: 50 lines (498 → 448).
Fixed error handling in resurrect-repositories.rb
- [scripts/resurrect-repositories.rb] Changed
abort()andrecord_warningcalls toraisefor fatal failures (clone failure, origin URL verification failure) so they are caught by the rescue block, allowing the script to continue processing remaining repos instead of terminating entirely. Added inline comments documenting the distinction between fatal errors (which abort the current repo) and non-fatal errors (which log warnings but continue).
Changed environment variable warning to immediate output
- [scripts/resurrect-repositories.rb] Changed
_find_and_replace_env_varto usewarn()instead ofrecord_warning()for missing environment variables. Missing env vars during config loading are configuration issues, not operational failures, and should not be accumulated in the final summary.
Removed unused methods from logging.rb
- [scripts/utilities/logging.rb] Removed unused
command_exists?method and entire step timing subsystem (step_timing_init,step_start,step_end,step_start_timesaccessor). Total reduction: 39 lines. All internal methods used by public logging methods (section_header, print_script_summary, record_warning, etc.) are retained.
3.1.8
Fixed ensure_keybase_logged_in not found on re-running fresh-install-of-osx.sh
- [fresh-install-of-osx.sh] Added
load_file_if_exists "${HOME}/.aliases"directly afterload_zsh_configsinmain().~/.zsh_plugins.zsh(the antidote bundle) is checked into the home git repo and symlinked byinstall-dotfiles.rbbefore this point, so it is present on both vanilla OS and pre-configured machine runs..zshrcsources the bundle, which defineszsh-defer, and then defers${ZDOTDIR}/.aliasesto the next ZLE idle event. In a non-interactive script there is no ZLE idle event, so the deferred callback never fires and${ZDOTDIR}/.aliasesfunctions (ensure_keybase_logged_in,build_keybase_repo_url) are absent. Theis_aliases_sourcedguard inside${ZDOTDIR}/.aliasesprevents double-loading.
Fixed all alias not found in resurrect_tracked_repos
- [.aliases] Replaced
command_exists all/all restore-mtime -c/all maintenance register/all maintenance startwith directFOLDER="${HOME}" MAXDEPTH=7 run-all.sh git ...invocations. The failure was not caused by alias expansion being disabled — zsh’sALIASESoption is on by default even in non-interactive scripts. The actual cause:resurrect_tracked_reposis called as a background&|job fromfresh-install-of-osx.sh, and if${ZDOTDIR}/.aliasesis not loaded in that child-process,allis simply never defined. Using the underlying command directly removes the dependency on${ZDOTDIR}/.aliasesbeing in scope.
Made allow_all_direnv_configs and install_mise_versions synchronous in fresh-install
- [fresh-install-of-osx.sh] Removed
&|(background + disown) from theallow_all_direnv_configsandinstall_mise_versionscalls; both now run synchronously. Also removed the HACKTAG comments that described the background rationale.
Corrected No Aliases in Non-Interactive Scripts rule
- [shell-scripting.instructions.md] Replaced the incorrect claim “Zsh disables alias expansion in non-interactive shells” with the accurate mechanism: zsh’s
ALIASESoption is on by default universally; the real risk is that${ZDOTDIR}/.aliasesmay not have been sourced, leaving the alias undefined. Updated the rule rationale, BAD/Good examples, and comment templates accordingly. - [copilot-instructions.md] Updated the
§ No Aliases in Non-Interactive Scriptssummary to match.
Corrected ssh config file to use relative paths
- [ssh config] Some tools do not understand
SSH_CONFIGS_DIRcustom env var. To accommodate this, the ssh config file refers to the global config and the itentity key files using relative paths. The template has also been modified to reflect the same for new adopters.
Made GHC instructions generic
- The github copilot instructions file is read only by GHC. In an effort to move to a locally running GPT-OSS model, moved all these instructions to a model-agnostic instructions file.
Clarified two-phase preference architecture in documentation
- [copilot-instructions.md] Backported the
§ osx-defaults.sh and capture-prefs — Two-Phase Preference ArchitectureLayer 1/Layer 2 section fromnix-migration, inserted before Git Configuration Rules; stripped the nix-specifictargets.darwin.defaultssubsection. Gives a concise accessible overview (what the layers are, auto-call behavior, re-run warning, ordering constraint) alongside the existing detailed Phase 1/Phase 2 decision-rules section. - [GettingStarted.md] Added an inline sentence to the bootstrap paragraph noting that the script automatically applies the two-phase preference setup in order.
Tightened _create_crontab cron header comments
- [.aliases] Replaced the verbose
chroniccomment (“is a utility installed using ‘moreutils’ from homebrew and is needed so that a successful run…”) with a concise form (“is provided by ‘moreutils’ from Homebrew and suppresses cron mail on success”). - [.aliases] Removed the parenthetical
(needed for chronic, run-all.sh, capture-prefs.sh etc.)from the# PATH:cron header comment — the comment described why the path was set, which belongs in the code comment above it, not in the generated crontab header.
Unified custom.git_state detection to git rev-parse --verify
- [starship.toml] Replaced
[ -d "$root/rebase-merge" ] || [ -d "$root/rebase-apply" ]and[ -f "$root/BISECT_LOG" ]withgit rev-parse --verify REBASE_HEADandgit rev-parse --verify BISECT_HEADrespectively; removed the now-unusedroot=$(git rev-parse --git-dir …)line. All five operation states now use a single unified detection strategy that works with both the classic.git/files backend and the reftable backend (git 2.45+), where pseudorefs are stored in the reftable and plain file/directory checks silently fail. - [copilot-instructions.md] Updated the
§ Starship Prompt Rulesbullet to drop the “two strategies” framing and document the unifiedgit rev-parse --verifyapproach for all five states (REBASE_HEAD,MERGE_HEAD,CHERRY_PICK_HEAD,REVERT_HEAD,BISECT_HEAD).
Standardised osx-defaults.sh section formatting
- [osx-defaults.sh] Renamed
# MenuBarsection header to# Menu Barto match macOS terminology. - [osx-defaults.sh] Added missing blank lines after the closing
# ---divider in seven sections (Login Window, SSD-specific tweaks, Dock, Safari & WebKit, Mail, Terminal, iTerm2) for consistent section-body separation.
Adopting these changes
-
Rebase from upstream, resolve conflicts. Run in all open terminals:
unfunction is_shellrc_sourced; zcompile ~/.shellrc; source ~/.shellrc unfunction is_aliases_sourced; zcompile ${ZDOTDIR}/.aliases; source ${ZDOTDIR}/.aliases install-dotfiles.rb fresh-install-of-osx.sh - Quit and restart the Terminal application.
- Review and edit the
~/.ssh/configfile to remove any duplicateIncludelines. The best way to determine which format to use is to remove all those, and just runinstall-dotfiles.rbwhich will put the correct expected format in it
3.1.7
Standardised dispatch_or_fallback across all per-repo autoload commands
- [count, st] Renamed
count()/st()to_count()/_st()(private implementations) and addedcount() { dispatch_or_fallback count _count "$@"; }/st() { dispatch_or_fallback st _st "$@"; }entry points — consistent withcc,pull,push,upreb. - [copilot-instructions.md] Updated
dispatch_or_fallbacksection to list all six commands (cc,count,pull,push,st,upreb) and explicitly document thatstatus_all_reposandupdate_all_reposare excluded because they operate on a fixed set of repos. - [TechnicalDeepDive.md] Same update to § 10 Per-Project Script Overrides.
- [Extras.md] Updated git autoload table to split
st/status_all_reposinto separate rows, add an “Supports override?” column, and clarify thatstatus_all_reposandupdate_all_reposare excluded; expanded the per-project override description with a concrete annotated example showing how to implement an override file, call_push "$@"to avoid infinite recursion, and usereturn 1safely.
Rewrote keg-only PATH/compiler-flags cache to filesystem-direct approach
- [.zshrc] Replaced the snapshot-and-delta cache-generation approach with direct filesystem enumeration:
_keg_collect(renamed from_use_keg_for) interrogates${HOMEBREW_PREFIX}/opt/<pkg>/bin,libexec/bin,libexec/gnubin, etc. directly and buildskeg_paths,keg_manpath,ldflags_new,cppflags_new, andpkgconfig_newwithout reading the current environment.LDFLAGS,CPPFLAGS, andPKG_CONFIG_PATHare written as plain overwrites (not prepend-expressions) since the keg-only block is their sole setter during startup. - [.zshrc] Added Homebrew base
bin/sbinto the generated cache (hb_base) so PATH priority is: mise > keg-only > Homebrew base > system. - The new approach is idempotent: regenerating the cache inside a shell that already has keg-only vars set (e.g. a tool like OpenCode inheriting the user’s
PATH) produces the same result as regenerating in a clean shell. The snapshot-and-delta approach was broken in this scenario — a pre-populatedPATHproduced an empty delta (keg-only bins missing from cache) and a pre-populatedLDFLAGScaused doubled flags on every re-source.
Removed dead prepend_to_* functions from .shellrc
- [.shellrc] Removed five functions superseded by the filesystem-direct keg-only cache approach:
prepend_to_path_if_dir_exists,prepend_to_manpath_if_dir_exists,prepend_to_ldflags_if_dir_exists,prepend_to_cppflags_if_dir_exists,prepend_to_pkg_config_path_if_dir_exists.append_to_path_if_dir_existsandappend_to_fpath_if_dir_existsare retained (both have active call sites in.zshrcandfresh-install-of-osx.sh).
Disabled predict-on and incremental-complete-word ZLE features
- [.zshrc] Commented out
autoloadandbindkeycalls forpredict-on(Ctrl+Xp) andincremental-complete-word(Ctrl+Xi).predict-onoverlaps withzsh-autosuggestions(already loaded synchronously) which provides the same history-based inline completion non-destructively without a toggle.incremental-complete-wordis superseded by fzf-based tab completion. Neither adds startup overhead, butpredict-onadds per-keystroke cost when active.
Removed is_macos wrapper from .zshrc
- [.zshrc] Lifted
setoptcalls,zstylecompletions config,autoload -Uz _git,bindkeyfor Option+arrow, and theif (($+commands[brew]))keg-only cache block out of theif is_macos; thenwrapper. The setopts and zstyle config are generic zsh behaviour, the bindkeys are safely inert on non-macOS terminals, and the brew block was already guarded by(($+commands[brew]))— the outeris_macoscheck added no safety and made the code harder to reason about. - [.zshrc] Updated the comment above the starship init block to remove the stale reference to “the macOS block” and to accurately state that starship’s init must be sourced at file scope (not deferred) because its
precmd_functions+=registration andsetopt promptsubstmust be applied before the first prompt.
Adopting these changes
-
Rebase from upstream, resolve conflicts. Run in any open terminal —
delete_cachesis essential: the old keg-only cache format calledprepend_to_path_if_dir_exists(now removed from.shellrc); sourcing the old cache without clearing it will produce “command not found” errors:delete_caches unfunction is_aliases_sourced; zcompile ${ZDOTDIR}/.aliases; source ${ZDOTDIR}/.aliases unfunction is_shellrc_sourced; zcompile ~/.shellrc; source ~/.shellrc -
Quit and restart the Terminal application.
3.1.6
Set Homebrew zsh as the default login shell during fresh-install
- [fresh-install-of-osx.sh] Added
_set_default_shellfunction that adds/opt/homebrew/bin/zshto/etc/shells(required bychsh) if absent, then callschsh -sto make it the default shell. Called immediately after_install_homebrewso Homebrew’s zsh is guaranteed to be on disk. Idempotent — skips each step if already done. - [osx-defaults.sh] Added
PlistBuddycall to setCustom Command = No(Login shell) in the Default iTerm2 profile. The key defaults toCustom Shellon a fresh iTerm2 install, which means.zloginis never triggered for new windows/tabs. Setting it toNoensures the full zsh startup sequence (.zshenv → .zshrc → .zlogin) runs correctly.
Added symmetric-diverge rebase to upreb autoload script
- [upreb] After
git uprebruns per-branch, compare incoming vs outgoing commit counts; if they are equal and non-zero ANDgit diff @{u}produces no diffs, performgit rebase @{u}. This handles branches that have diverged symmetrically (e.g. remote was force-pushed or rebased) with identical content — situations the gituprebalias skips because noupstreamremote is present.
Fix color methods called on Integer in resurrect-repositories.rb
- [resurrect-repositories.rb] Added missing
.to_sbefore.red/.greenon fourIntegervalues (.lengthreturn values). Ruby’s color methods are defined onStringonly — calling them directly on anIntegerraisesNoMethodError.
Adopting these changes
-
Since
_set_default_shellonly runs insidefresh-install-of-osx.sh, pre-configured machines will not automatically get the default shell changed to Homebrew’s zsh. Runfresh-install-of-osx.shto pick up this change — it is fully idempotent and safe to run on an already-configured machine. It will add/opt/homebrew/bin/zshto/etc/shellsand callchshonly if the default shell is not already set correctly. -
After
chshtakes effect (quit and reopen the terminal), verify withecho $SHELL— it should print/opt/homebrew/bin/zsh. -
Terminal.app requires no manual change — it always opens a login shell using
$SHELL, so it picks up the new default automatically oncechshis done. -
iTerm2 — open Preferences → Profiles → General → Command and set it to Login shell (not “Custom Shell”). This is also applied automatically by
osx-defaults.sh -s, but pre-configured machines that skip that step must set it manually.
3.1.5
Migrate cloned repos to reftable format during fresh-install
- [.shellrc] Added
migrate_git_repo_to_reftablehelper that checks whether a repo uses the legacy loose/packed-refs format and, whengit refs migrate(git 2.45+) is available, converts it to reftable. After migration it removes stale loose-ref files from.git/refs/heads/,.git/refs/tags/, and.git/refs/remotes/thatgit refs migratemay leave behind and that can confuse ref lookup. Uses a named helper (_remove_loose_reftable_refs) instead of an anonymous()function so bash can parse.shellrcwithout a syntax error. - [.shellrc]
clone_repo_intonow callsmigrate_git_repo_to_reftableafter a successful clone. On a vanilla macOS the system git silently ignores this (the function exits early whengit refs migrateis unavailable), so it is a no-op until Homebrew’s modern git is on PATH. - [fresh-install-of-osx.sh] Added a “Migrate repos to reftable format” step immediately after
_install_homebrew. At that point Homebrew’s git 2.45+ is on PATH, so the dotfiles repo (cloned earlier with system git and therefore still in files format) is migrated correctly.
Remove redundant is_zsh guards from .shellrc
- [.shellrc] Removed the
if is_zshwrapper aroundload_zsh_configsandprint_usage. Neither function contains parse-time zsh-only syntax; the guard was preventing bash from defining them but bash never calls them, so the guard was unnecessary. Restored the warning comment about infinite-loop risk aboveload_zsh_configsthat was attached to the removed wrapper.
Clarify () vs named helper and is_zsh guard rules in AI assistant docs
- [shell-scripting.instructions.md] Rewrote the § Glob Patterns — NULL_GLOB section to explain the
()vs named helper decision based on whether bash may source the file. Added two new top-level sections: § Do not mandate named helpers everywhere (named functions in zsh are not scoped —()avoids namespace pollution in pure zsh files; named helpers requireunfunctionimmediately after use) and §is_zshguards are for parse-time zsh-only syntax only (setopt/autoloadare runtime-only issues; guards are only needed for syntax bash cannot tokenise). - [copilot-instructions.md] Added matching summary bullets for the two new rules, referencing the full treatment in
shell-scripting.instructions.md.
Fix ERR trap $LINENO in fresh-install-of-osx.sh
- [fresh-install-of-osx.sh] Changed both
trap _cleanup_and_exit ERRcalls to the string formtrap '_cleanup_and_exit "${LINENO}"' ERR. With the function-name form,$LINENOinside the handler reports its own line (wrong); the string form evaluates$LINENOin the failing command’s scope before calling the function, so the reported line is always accurate — including for failures in helper functions whenset -Epropagates the trap. - [fresh-install-of-osx.sh] Updated
_cleanup_and_exitto accept$1as the failing line number and include it in the error message when non-empty. - [shell-scripting.instructions.md] Added new § ERR Trap —
$LINENOString Form vs Function Form section under Cron Scripts with BAD/Good examples and a note that the rule applies with or withoutset -E. - [copilot-instructions.md] Added a matching summary bullet referencing § ERR Trap —
$LINENOString Form vs Function Form.
Add missing unfunction for named inner functions
- [.shellrc] Added missing
unfunction _remove_loose_reftable_refsafter calling it insidemigrate_git_repo_to_reftable. The named function persists in the global table after the outer function returns —unfunctionis required for non-subshell call sites (direct interactive use,clone_repo_intofromfresh-install-of-osx.sh).run-all.shsandboxes each repo call in a()subshell so the leak is contained there, but does not eliminate the need for cleanup at other call sites. - [cleanup-browser-profiles.sh] Added missing
unfunction _read_pattern_fileafter its two call sites insidevacuum_browser_profile_folder. Same pattern — named inner function would persist in the global table for the rest of the shell session. - [shell-scripting.instructions.md] Expanded § Do not mandate named helpers everywhere to include the
unfunctionrequirement with a code example noting therun-all.shsubshell distinction. - [copilot-instructions.md] Updated the matching summary bullet to include the
unfunctionrequirement andrun-all.shsubshell nuance.
Fix stale GitHub-cached .shellrc on vanilla OS install
- [fresh-install-of-osx.sh] After
install-dotfiles.rbruns, check whether the committedfiles/--HOME--/.shellrcdiffers from what was adopted (the curl-downloaded, potentially GitHub-cached version). If it does, restore the committed version withgit checkout -- files/--HOME--/.shellrcbeforeload_zsh_configsre-sources it. Without this guard, a stale cache could cause the rest of the install to run with an older.shellrcthat is missing newly added functions.
Adopting these changes
-
Rebase from upstream, resolve conflicts. To migrate all existing repos to reftable format (optional, but recommended), run in any open terminal:
delete_caches unfunction is_shellrc_sourced FOLDER="${HOME}" MAXDEPTH=7 run-all.sh migrate_git_repo_to_reftable -
Quit and restart the Terminal application.
3.1.4
Optimise zsh shell startup latency
- [.zshrc] Deferred the initial
_mise_hookcall in the mise activate cache by appending azsh-defer-guarded invocation and stripping the bare_mise_hookline frommise activate zshoutput.zsh-deferfires after the first ZLE idle event (before any keypress), saving ~25ms from time-to-first-prompt. Falls back to a synchronous call whenzsh-deferis unavailable. - [.zshrc] Fixed eager
PROMPT2fork in starship init cache generation.starship init zshemitsPROMPT2="$(...)"(double-quoted — forks starship at source time, ~9-15ms). Cache generation now strips that line and appends a lazy single-quotedPROMPT2='$(...)'matching the pattern already used byPROMPTandRPROMPT.
Adopting these changes
-
Rebase from upstream, resolve conflicts, and then run in any open terminal:
# delete the mise activate cache and starship init cache to force regeneration rm -f ~/.cache/mise-activate-cache.zsh ~/.cache/starship-init-cache.zsh -
Quit and restart the Terminal application.
3.1.3
Harden capture-prefs key stripping
- [capture-prefs-excluded-keys.txt] Commented out overly-aggressive global patterns (
*|NSWindow Frame *,*|NSSplitView Subview Frames *,*|*Identifier,*|*identifier) that stripped legitimate app config keys and caused data loss (e.g. Clocker lost configured timezones). Added “cannot use” notes for*Date,*Timestamp,*Timepatterns — these would also cause app startup failures if applied globally. - [capture-prefs-excluded-keys.txt] Added targeted per-domain
SULastCheckTimeexclusions for 15 apps (Sparkle update-check timestamp, criterion 3). Added specific entries forcom.abhishek.analyticsLastSignalDateandiVersionLastChecked(Clocker),LastAutoUpdateCompletion/LastUpdatesCheck/LastUpdatesPerform(com.apple.appstored),LastPeriodicAnalyticsPostDate(com.apple.controlcenter), and_DKThrottledActivityLast_*(com.apple.knowledge-agent). - [capture-prefs.sh] After stripping, delete the exported plist if no
<key>elements remain — empty plists have no value in git history and cannot be meaningfully imported. - [capture-prefs.sh] Show count of files actually saved (after empty-plist deletion) in the export success message.
Fix import robustness
- [capture-prefs.sh] Guard import with
is_filebeforecp— skips domains for which no exported plist exists (app not installed on the source machine) instead of crashing withcp: No such file or directory. - [capture-prefs.sh] Fixed
mktemptemplate: removed.plistsuffix — BSDmktempon macOS requires theXs to be at the very end of the template; a suffix after them causesmkstemp failed: File exists.
Prompt user to restart apps after import
- [capture-prefs.sh] Replaced the generic “restart any open apps”
user_actionwith_notify_apps_needing_restart— detects which of a curated list of terminal/IDE apps are currently running and emits a single targeted restart message, excluding login-item apps already handled bykill/restart_login_item_apps.
Refactor Finder handling in login-item restart
- [.aliases] Removed
Finderfrom_MACOS_LOGIN_ITEM_APPSand movedkillall Finderdirectly into bothkill_login_item_appsandrestart_login_item_apps— Finder is launchd-managed (killall causes immediate relaunch) and cannot be handled the same way as SMAppService login items. Removed the special-caseFinderbranch fromrestart_login_item_apps.
Prune uninstalled app domains from capture-prefs allowed list
- [capture-prefs-allowed-list.txt] Removed 16 domains for apps no longer installed on this machine.
- [capture-prefs-denied-list.txt] Moved
com.apple.Musicto the denied list — library file path is device-specific and iCloud Music Library sync state is account- and device-bound (criteria 1 and 2). - [Brewfile] Added inline comment to the commented-out
knockknockcask explaining what the app does.
Enable per-domain exclusion entries after verification
- [capture-prefs-excluded-keys.txt] Enabled all
eu.exelban.Statsexclusion entries after confirming the keys exist:id,remote_id(device UUIDs),Clock_list(per-device UUIDs),remote_tokens_migrated_to_keychain(credential migration flag),version/runAtLoginInitialized/setupProcess(onboarding sentinels),ble_*(Bluetooth sensor state),sensor_*(hardware sensor state),*_ts(timestamp watermarks), andNSStatusItem Preferred/Restore Position *(display geometry). - [capture-prefs-excluded-keys.txt] Enabled
com.abhishek.Clockerentries fordefaultPreferences(binary NSKeyedArchiver blobs),install(install timestamp),com.abhishek.defaultsLastUpdateKey, andNSStatusItem Preferred Position ClockerStatusItem; left entries absent from this machine commented as documentation. - [capture-prefs-excluded-keys.txt] Enabled
com.apple.universalaccess|History(per-session accessibility event log, criterion 3);com.sproutcube.Shortcat|telemetryIdentifier(device UUID) andNSStatusItem Preferred Position *(display geometry); and all fourio.github.keycastrentries:default.textColor(display-specific ICC color blob),NSStatusItem Preferred Position *,NSSplitView Subview Frames *, andNSToolbar Configuration *.
Document arithmetic increment pitfall under set -e
- [shell-scripting.instructions.md] Added
## Arithmetic Increment — Safety Under set -esection:(( var++ ))post-increment evaluates to the old value, so(( 0 ))on the first iteration silently aborts the script underset -e. Always use(( var += 1 )) || true. - [copilot-instructions.md] Added summary bullet under
### set -euo pipefailcross-referencing the full rule inshell-scripting.instructions.md.
Adopting these changes
-
Rebase from upstream, resolve conflicts, and then run in any open terminal:
unfunction is_aliases_sourced; source ${ZDOTDIR}/.aliases # to pick up new functions and bug fixes -
Quit and restart the Terminal application.
3.1.2
Fix setup-login-item.sh for macOS 26 and complete Brewfile login item hooks
- [setup-login-item.sh] Rewrote to use
SMAppService.loginItem(url:)on macOS 14–25 and fall back to the legacy System Events AppleScript on macOS 13 and macOS 26+. On macOS 26 (Tahoe), Apple removedloginItem(url:)and replaced it withloginItem(identifier:), which only works for login item helpers bundled within an app — it cannot register standalone third-party apps externally. The legacy System Events path (items appear as “Legacy” in System Settings) is the only viable option on macOS 26. - [setup-login-item.sh] Added
-b(background/hidden mode) flag, proper-hhelp,usage()usingprint_usage, and deferred warning collection via_record_warning— bringing the script in line with the standard script skeleton. - [Brewfile] Added missing
postinstall: "...setup_login_items_script... -a 'KeyClu'"andpostinstall: "...setup_login_items_script... -a 'ProtonVPN'"— these two apps were being installed without registering as login items. Removedaldentefrom Brewfile andcom.apphousekitchen.aldente-profrom the allowed prefs list.
Remove hardcoded user-specific paths
- [software-updates-cron.sh] Replaced hardcoded
/Users/vijaywith${HOME}in allFOLDER=assignments — the previous values were machine-specific and would silently do nothing on any other machine. - [.aliases]
_create_crontab: removed${HOMEBREW_PREFIX}/bin/prefixes from the cron entry —zshandchronicresolve via thePATHset earlier in_create_crontab, so hardcoding Homebrew’s bin path was redundant and fragile across arm/Intel prefix differences.
Harden antidote update and fix antidote .zwc crash
- [.aliases]
delete_caches: split the singlefindinto two separate calls — one forHOME(no-L, uses-delete) and one forHOMEBREW_PREFIX(with-L, uses-exec rm -f {} +because macOSfindforbids-deletewhen symlinks are followed). Without-L,findsilently skips symlinked directories, so.zwcfiles underopt/<formula>/paths (which are all symlinks intoCellar/) were never deleted. A staleantidote.zsh.zwccould therefore persist across brew upgrades, causing antidote’sZSH_EVAL_CONTEXTsource-detection check to fail andexit 1to fire on every interactive shell startup. - [.zlogin] Ensured
antidote.zshis never compiled to.zwc— antidote 2.1.0’s source-detection check uses*:file:*againstZSH_EVAL_CONTEXT, but zsh sets that token tofilecode(notfile) when loading from.zwcbytecode. The CLI branch fires, callsexit 1, and crashes every interactive shell. antidote.zsh must always be loaded from raw source. - [zsh-startup.instructions.md] Added “Do NOT compile
antidote.zshto.zwc” section documenting thefilecodebug and the fix applied todelete_caches.
Document two-phase preference architecture and no-hardcoded-paths rule
- [TechnicalDeepDive.md] Added § 12 — Two-Phase Preference Architecture: explains why
osx-defaults.sh -s(baseline seed) must run beforecapture-prefs.sh -i(UI-configured overrides), and the decision rule for where new preference code belongs. - [Extras.md, GettingStarted.md] Added adopter-facing summaries of the two-phase architecture with links to § 12.
- [copilot-instructions.md] Added Two-Phase Preference Architecture section (decision rule + ordering constraint) and cross-referenced
shell-scripting.instructions.md§ No Hardcoded User-Specific Paths. - [shell-scripting.instructions.md, copilot-instructions.md] Added
## No Hardcoded User-Specific Pathsrule: substitution table of all derived${HOME}paths and their canonical env var equivalents, plus a scan rule for auditing existing files. - [copilot-instructions.md] Documentation Update Routine: added mandatory cross-reference analysis step — after editing any doc file, scan all adopter-facing docs for mentions of the same concept and add or update links to the canonical deep-dive section.
Fix delete_caches post-deletion is_debug error and harden capture-prefs key stripping
- [.aliases]
delete_caches: addedsource "${ZDOTDIR}/.zlogin"at the end so all.zwccaches are rebuilt immediately in the current shell. Without this, the first new terminal afterdelete_cachesstarts with no compiled bytecode; raw-source startup leaves the function table in a state where helper functions (e.g.is_debug) are not visible to.zlogin’s background recompile subshell, producing “command not found: is_debug”. Also converted the trailing&&guard forXDG_CACHE_HOMEremoval to an explicitifto be safe underset -e/ ERR trap patterns. - [capture-prefs.sh]
_strip_excluded_keys: rewrote as a single Ruby/REXML pass (replacing the prior Ruby-enumerate + PlistBuddy-delete approach) using/usr/bin/ruby— eliminates the only Homebrew-Python dependency in the codebase. PlistBuddy treats:as a path separator in its key-path syntax, so keys whose names contain:(e.g._DKThrottledActivityLast_...:/app/mediaUsageActivityDate) were misinterpreted as nested dict paths and silently not deleted.File.fnmatchwithoutFNM_PATHNAMEallows*to match/and:, matching zsh’s[[ == ]]glob behaviour. Also switchedcapture-prefs.shto source${ZDOTDIR}/.aliasesinstead of.shellrcso the shared macOS prefs helpers (§ 3n) are available. - [capture-prefs-excluded-keys.txt] New file: per-domain key exclusion patterns for
capture-prefs.sh. Added global date/timestamp patterns (*|*Date,*|*date,*|*Timestamp,*|*timestamp) to strip ephemeral watermark keys from every domain. - [capture-prefs-allowed-list.txt, capture-prefs-denied-list.txt] Moved
com.apple.xpc.activity2from allowed to denied (contains only background-task scheduling timestamps and OS version stamps — no portable user preferences). RemovedApple Global Domainandscreencapturefrom the allowed list — these domains accumulate too many system-managed non-portable keys to be safely captured wholesale.
Unify script logging decoration across shell and Ruby (remaining call sites)
- [capture-prefs.sh, osx-defaults.sh, setup-login-item.sh] Removed the now-redundant
"${_SCRIPT_NAME}"argument from remainingprint_script_summarycall sites.
Gate all script banners on outermost-script depth (remaining scripts)
- [capture-prefs.sh, osx-defaults.sh, setup-login-item.sh] Each script now decrements
_DOTFILES_SCRIPT_DEPTHon exit (clean or error) via_decrement_script_depth. - [TechnicalDeepDive.md] Added section on the nesting depth counter,
is_outermost_script/outermost_script?guard, and why subprocess scripts still decrement even though only the outermost script prints output.
Harden shell utility infrastructure (remaining changes)
- [capture-prefs.sh, .zshrc, .zlogin] Eliminated inline
(N)glob qualifiers — replaced withsetopt localoptions NULL_GLOBinside anonymous functions(). - [.aliases, capture-prefs.sh] Replaced remaining raw POSIX test switch (
-d) usages and unsafe&&-as-conditional guards with named utility functions and explicitifstatements.
Fix cron-safety issues (remaining changes)
- [capture-prefs.sh] Scoped
kill_login_item_appsandrestart_login_item_appsto import-only or interactive (TTY) export — cron export no longer kills running apps mid-session.
Harden git alias safety and portability
- [.gitconfig] Added
git pull-safe: fetches all remotes unconditionally, then rebases onto@{u}only if the working tree is clean. - [.gitconfig] Updated
git upreb: guards the entire rebase + push workflow behind a dirty-tree check before touching anything. - [.gitconfig] Refactored all
!-prefixed aliases to accept an optional[<dir>]as their first argument viagit -C "${1:-.}", enablinggit <alias> /path/to/repoas an alternative togit -C /path/to/repo <alias>. - [.gitconfig] Fixed
git next-versionto account for commits already made since the last tag. - [software-updates-cron.sh] Replaced
git pullwithgit pull-safeandgit upreb(which now have the dirty-tree guard built in); changed the outer failure handling from_record_errorto_record_warning— a dirty skip during cron is an expected state.
Establish “do not combine both forms” rule for git aliases
- [.gitconfig, git-config.instructions.md, copilot-instructions.md] Documented that
git -C <path1> alias <path2>is undefined behaviour — the explicit arg wins and-Cis silently ignored.
Extract shared macOS prefs helpers into .aliases § 3n
- [.aliases] Extracted
kill_login_item_apps,restart_login_item_apps, andreload_macos_prefsinto a new§ 3n. macOS prefs helperssection, along with the canonical_MACOS_LOGIN_ITEM_APPSarray. - [.aliases] Added
suspend_softwareupdate_scheduleandresume_softwareupdate_scheduleto§ 3n. - [osx-defaults.sh, capture-prefs.sh] Moved
softwareupdate --schedulemanagement into the shared helpers; wiredresume_softwareupdate_scheduleinto the EXIT trap.
Expand osx-defaults.sh
- [osx-defaults.sh] Added sections for new apps: Clocker, DBeaver, DockDoor, Drawio, Firefox, Keybase, KeyCastr, KeyClu, OnlyOffice, Rancher Desktop, Shortcat, Stats, Thaw, Zen Browser.
- [osx-defaults.sh] Replaced inline kill/restart arrays with calls to
kill_login_item_appsandtrap 'restart_login_item_apps' EXIT. - [osx-defaults.sh] Removed stale Dock/Dashboard keys no longer present in macOS Catalina+.
Add technical deep-dive documentation and restructure adopter docs
- [TechnicalDeepDive.md] New document covering internal architecture for adopters.
- [README.md, Extras.md, GettingStarted.md, Prerequisites.md] Added links and callouts to TechnicalDeepDive.md; improved prose clarity on idempotency and the Brewfile first-install model.
- [GettingStarted.md] Rewrote the post-install checklist; replaced external gist links with local template files.
- [templates/gitconfig-inc.template, templates/ssh-config.template] New template files for per-context git config and SSH config.
Fix shell and startup infrastructure
- [.gitconfig] Fixed delta whole-line diff rendering:
minus-style/plus-stylenow use"syntax <bg-color>"to preserve syntax highlighting on whole-line diffs; addedline-fill-method = ansi. - [.zshrc, .zlogin] Fixed trailing
[[ ]] && ...conditionals that causedsourceto return exit code 1 on normal runs. - [.zshrc] Added Option+arrow key bindings for Terminal.app word navigation — Terminal.app’s “Use Option as Meta key” covers Option+B/F but not arrow keys;
\033[1;9D/Cmapped to ZLE word-motion (inert in iTerm2, which remaps these at the terminal level). - [.zshrc] Commented out
setopt null_glob— the option causes commands that receive zero arguments silently rather than producing a clear “no matches found” error;setopt localoptions NULL_GLOBinside an anonymous function is the correct scoped alternative. - [.aliases, capture-prefs.sh] Fixed remaining unsafe
&&-as-conditional patterns. - [.editorconfig, custom.gitattributes, .shfmtignore] Removed
*.defaultsbinary/charset entries (leftover from the 3.1.1.defaults→.plistformat migration); addedcapture-prefs.shto.shfmtignore(uses${~pattern}zsh glob matching that shfmt cannot parse). - [fresh-install-of-osx.sh] Removed trailing manual
user_actionprompts frommain()— the deferred-collection summary (introduced in 3.1.1) already surfaces all follow-up actions.
Update documentation
- [shell-scripting.instructions.md] Added NULL_GLOB scoping rules:
setopt localoptions NULL_GLOBinside an anonymous function is the only permitted form; banned baresetopt NULL_GLOB,unsetopt NULL_GLOB, and inline(N)qualifiers. - [copilot-instructions.md, shell-scripting.instructions.md] Documented the
_MACOS_LOGIN_ITEM_APPSfile-scope constant array exception to the global-state variable naming convention. - [git-config.instructions.md] Added working directory argument convention, dirty-tree guard pattern, and
## [delta] — Diff Renderingsection. - [.opencode/skills/dotfiles-domain/SKILL.md] Updated opencode dotfiles skill with key rules, file reference tables, and documentation update routine.
Adopting these changes
-
Rebase from upstream, resolve conflicts, and then run in any open terminal:
install-dotfiles.rb unfunction is_shellrc_sourced; source ~/.shellrc # to pick up new functions and bug fixes unfunction is_aliases_sourced; source ${ZDOTDIR}/.aliases # to pick up new functions and bug fixes rm -rfv /opt/homebrew/opt/antidote/share/antidote/antidote.zsh.zwc* delete_caches # clear any stale .zwc bytecode and cached shell environment files. _create_crontab "${PERSONAL_CONFIGS_DIR}/crontab.txt" # re-generate the cron file with correct settings recron # to pick up the simplified crontab entry - Quit and restart the Terminal application (to guarantee that the latest versions of the zsh autoload scripts are loaded).
- On macOS 26: if any app is missing from Login Items, re-run
setup-login-item.sh -a '<AppName>'for each, or re-runbrew bundle installto trigger thepostinstallhooks.
3.1.1
Introduce deferred error/warning collection
- [.shellrc] Added
user_action()logging function (bold yellow,➡️prefix) for manual-step messages — distinct fromwarn(unexpected problem) andinfo(informational). Suppressed in direnv subshells. - [.shellrc] Extracted
_record_warning,_record_error, andprint_script_summaryas shared helpers using zsh dynamic scoping;print_script_summaryfires a macOS notification when errors or warnings were collected. - [add-upstream-git-config.sh, capture-prefs.sh, cleanup-browser-profiles.sh, osx-defaults.sh, recreate-repo.sh, run-all.sh, setup-login-item.sh] Applied the deferred collection pattern — operation failures use
_record_warning/_record_error;print_script_summarycalled at end ofmain(). - [fresh-install-of-osx.sh] Two-level collection:
_step_warningsfor recoverable issues,_step_errorsfor significant failures;_cleanup_and_exitcallsprint_script_summarybefore the fatal crash message. - [software-updates-cron.sh] Two-level collection for update and infrastructure failures; escalated
_title_iconto⚠️when outdated packages need manual update.
Gate all script banners on outermost-script depth
- [.shellrc] Added
is_outermost_script(_DOTFILES_SCRIPT_DEPTH <= 1) and_decrement_script_depth;print_script_start,print_script_duration, andprint_script_summarynow guard onis_outermost_script || return 0. - [logging.rb] Added
outermost_script?,increment_script_depth(registersat_exitdecrement), anddecrement_script_depth; all three print helpers guard onoutermost_script?— mirrors shell behaviour. - [.shellrc, logging.rb]
print_script_durationnow prefixes output with the script name, eliminating ambiguity in multi-script cron logs. - [add-upstream-git-config.sh, cleanup-browser-profiles.sh, fresh-install-of-osx.sh, recreate-repo.sh, run-all.sh, software-updates-cron.sh] Each now decrements
_DOTFILES_SCRIPT_DEPTHon exit via_decrement_script_depth. - [resurrect-repositories.rb] Calls
Logging.increment_script_depthbeforeprint_script_start;at_exithook handles the decrement. - [ruby-scripting.instructions.md] Documented depth counter,
is_outermost_script/outermost_script?guard, and why subprocess scripts still decrement.
Expand Ruby logging.rb with deferred collection and timing
- [logging.rb] Added
record_warning,record_error,current_section=, andprint_script_summary— Ruby mirrors of the shell deferred-collection pattern.section_headernow sets@current_sectionas a side effect. - [logging.rb]
print_script_startreturns the Unix epoch it logs — eliminates the two-call pattern; displayed timestamp and in-memory start time are always identical. - [logging.rb]
print_script_summary(start_time = nil)callsprint_script_durationinternally when provided — no separate call needed. - [logging.rb] Added
Logging.user_actionto mirror the shelluser_action()function. - [resurrect-repositories.rb] Converted to
record_warning/record_error; addedsection_headercalls per phase; updated toscript_start_time = print_script_start/print_script_summary(script_start_time)pattern. - [ruby-scripting.instructions.md] Documented the deferred-collection pattern, two shell-version deviations (
print_script_startreturn value;print_script_summarystart-time argument), and_SCRIPT_NAMEdynamic-scoping behaviour.
Unify script logging decoration across shell and Ruby
- [.shellrc]
print_script_startprefixes banner with_SCRIPT_NAME;_record_warning/_record_errorprefix entries with[_SCRIPT_NAME][_current_section];print_script_summaryreads_SCRIPT_NAMEvia dynamic scoping — no argument needed. - [add-upstream-git-config.sh, cleanup-browser-profiles.sh, recreate-repo.sh, run-all.sh] Removed the now-redundant
"${_SCRIPT_NAME}"argument from allprint_script_summarycall sites.
Harden shell utility infrastructure
- [.shellrc] Added
user_action()— see “Introduce deferred error/warning collection” above. - [.shellrc] Extracted
has_sudo_credentialsinto § 1e; replaced all rawsudo -n true 2>/dev/nullchecks. - [.shellrc] Fixed
is_zshfrom[[ "${0}" =~ 'zsh' ]]to[[ -n "${ZSH_VERSION-}" ]]. - [.shellrc] Added
is_debugandis_first_installpredicates; replaced all raw inline forms. - [.shellrc, .aliases] User-controlled boolean flags (
DEBUG,FIRST_INSTALL) now use:-; shell-provided vars (ZSH_VERSION) keep-. - [.shellrc] Added
debuglogging toload_zsh_configs. - [.aliases]
require_env_var: replaced raw-ztest withis_zero_stringandwarn. - [.shellrc, .aliases] Log-level reclassifications: idempotency guards →
info; expected-absent tools →debug; action items →user_action; “Successfully sourced ~/.shellrc” →success. - [6 scripts] Fixed unsafe
&&-as-conditional patterns insoftware-updates-cron.sh,recreate-repo.sh,capture-prefs.sh,run-all.sh,fresh-install-of-osx.sh(×2) — converted to explicitifblocks.
Fix cron-safety issues in .shellrc
- [.shellrc] Added
${COLUMNS:-80}fallback in_section_header_implandprint_chars_for_length— zsh setsCOLUMNSto0with no terminal.
Align startup files and autoload functions to established conventions
- [files/–ZDOTDIR–/.zshenv] Changed
${DEBUG+1}→${DEBUG:-}. - [files/–ZDOTDIR–/.zshrc] Changed
${DEBUG+1}→${DEBUG:-}and${ZSH_PROFILE_RC+1}→${ZSH_PROFILE:-}; renamedZSH_PROFILE_RC→ZSH_PROFILE; converted final[[ ]] &&one-liner toif/fi. - [files/–ZDOTDIR–/.zlogin] Changed three
${DEBUG+1}→${DEBUG:-}; added|| truetorm -f/zrecompilecalls; converted final[[ ]] && echotoif/fi. - [files/–XDG_CONFIG_HOME–/zsh/{cc,count,pull,push,st,status_all_repos,update_all_repos,upreb}] Changed compdef guard to
is_zsh && (($+functions[compdef]))— guards zsh-only syntax from bash; updated inline comment.
Expand shell-scripting documentation
- [shell-scripting.instructions.md] Documented
_SCRIPT_NAMEat script scope (notlocal) for dynamic-scoping availability; added${_SCRIPT_NAME:-<interactive>}fallback. - [shell-scripting.instructions.md] Updated “Always Quote Variables” example to use
is_fileinstead of[[ -f ]]. - [shell-scripting.instructions.md] Added double-quotes exception for strings containing single quotes.
- [shell-scripting.instructions.md] Added
## Parameter Expansion Operators — \:-` vs `-`` section with scan rule. - [shell-scripting.instructions.md] Fixed
DIRENV_IN_ENVRCvariable name (wasDIRENV_DIR). - [shell-scripting.instructions.md] Rewrote cron section:
load_zsh_configsnow conditional; addedsudo,is_running_in_tty, andCOLUMNSsubsections. - [shell-scripting.instructions.md] Updated autoload template and
compdefguard to useis_zsh. - [shell-scripting.instructions.md] Added
## _DOTFILES_SCRIPT_DEPTH — Increment and Decrementsection. - [shell-scripting.instructions.md] Updated
shfmtignoreexample to usehas_sudo_credentials. - [zsh-startup.instructions.md] Updated profiling example to use
ZSH_PROFILE. - [shell-scripting.instructions.md, ruby-scripting.instructions.md] Added unified
## Logging — Level Usageclassification table. - [shell-scripting.instructions.md] Added
## '&&' as Conditional — Safety Under 'set -e' / ERR Trapsection. - [all shell scripts] Ran
shfmtacross all non-ignored scripts.
Expand copilot-instructions documentation
- [copilot-instructions.md] Added
## Four-Context Validationsection. - [copilot-instructions.md] Fixed
is_running_in_ttytable entry (stdin,[[ -t 0 ]]). - [copilot-instructions.md] Updated deferred-collection pattern description: depth counter, decrement trap, Ruby equivalent.
- [copilot-instructions.md] Removed
"${_SCRIPT_NAME}"fromprint_script_summaryexample. - [copilot-instructions.md] Added
load_zsh_configsZDOTDIR safety note, conditional-cron guidance,has_sudo_credentialsguard,is_running_in_ttygate, andCOLUMNSfallback bullets. - [GettingStarted.md] Updated bootstrap
curlcommand to pipe throughtee "${HOME}/Downloads/fresh-install-of-osx.log".
Adopting these changes
-
Rebase from upstream, resolve conflicts, and then run in any open terminal:
install-dotfiles.rb unfunction is_shellrc_sourced; source ~/.shellrc # to pick up new functions and bug fixes unfunction is_aliases_sourced; source ${ZDOTDIR}/.aliases # to pick up new functions and bug fixes delete_caches # clear any stale .zwc bytecode and cached shell environment files. -
Quit and restart the Terminal application (to guarantee that the latest versions of the zsh autoload scripts are loaded).
3.0-19
- [.shellrc] Eliminated subprocess forks on every shell start:
$(whoami)→${USER}(PAM builtin);$(uname -m)→${${MACHTYPE%%-*}/#arm/arm64}(zsh builtin, correctly mapsarm→arm64on Apple Silicon); 16×$(colorize ...)calls for color variable initialisation →$'\e[...'ANSI escape literals;$(tput cols)inprint_chars_for_lengthand_section_header_impl→${COLUMNS}(zsh special variable, no external process). - [.shellrc]
replace_home_with_tilderewritten as pure-zsh parameter expansion${1//${HOME}/~}, eliminating two subprocess forks (echo+sed) on every call. - [.zshrc]
brew shellenvcache block: renamed internal variablecache_file→brew_shellenv_cachefor clarity; addedis_executable "${brew_bin}"guard so the block is skipped on a vanilla OS before Homebrew is installed. - [.zshrc] Added
iterm2_hostname="${HOST}"before the antidote bundle is sourced — pre-empts the iterm2 shell-integrationprecmdhook which forkshostname -f(~4ms) when this variable is unset. - [starship.toml] Git operation state indicators changed from plain-space padding (e.g.
' MERGING ') to>> LABEL <<delimiters (e.g.'>> MERGING <<') for better visibility in the prompt during rebase/merge/cherry-pick/revert/bisect operations. - [.aliases] Dynamic per-project
run-all.shaliases extracted into_generate_repo_aliasesand cached to${XDG_CACHE_HOME}/repo-aliases.zsh. Cache is regenerated only whenPROJECTS_BASE_DIRis newer than the cache or the cache is missing. Publicregenerate_repo_aliasesfunction added for manual refresh. - [.aliases]
$(extract_first_word "${EDITOR}")at two startup-path callsites (editor existence check andeditalias definition) replaced with${EDITOR%% *}(no subshell). - [.aliases]
$(pwd)default infolder_sizereplaced with${PWD}(zsh builtin). - [.zlogin]
find_in_folder_and_recompilenow uses a per-directory mtime sentinel file in${XDG_CACHE_HOME}— subsequent login shells skip thefindscan entirely if the directory has not changed since the last recompilation, eliminating redundant work on every login. - [.zlogin] The five large directory recompilation scans (
DOTFILES_DIR,PERSONAL_BIN_DIR,PROJECTS_BASE_DIR,/opt/homebrew,/usr/local) are now run in a disowned background job (&!) so they do not block the first prompt on login shells. Sentinel guards ensure they are no-ops when nothing has changed. - [.zlogin] Added
recompile_zsh_autoload_dirto compile extensionless autoload function files under${XDG_CONFIG_HOME}/zsh/(e.g.cc,count,pull,push,st, etc.) whichfind_in_folder_and_recompilewould silently skip due to its*.sh/*.zshpattern filter. Cache files under${XDG_CACHE_HOME}are also compiled viafind_in_folder_and_recompile. - [all zsh scripts + autoload functions]
type is_shellrc_sourced &>/dev/nullguard replaced with(( $+functions[is_shellrc_sourced] ))— pure zsh builtin check, no subshell. - [.shellrc, .aliases] Centralised the re-source guard inside each file itself — all call sites now source unconditionally (no more per-call
(( $+functions[...] )) ||guards). All custom zsh git commands (cc,count,pull,push,st,status_all_repos,update_all_repos,upreb) updated accordingly. Sourcing of these 2 files is now refined/tightened without duplication. - [all shell scripts] Added
# Usage:lines to all functions that accept arguments; added prose doc comments to all previously undocumented functions; converted# ==GROUP banners to# ---section dividers throughout both files. Fixed file-header banner width (was 81 chars, now exactly 80); split two combinedlocal var="$(…)"declarations into separate declaration + assignment lines. - [custom.gitattributes] Added
*.defaults binaryso Apple binary plist captures are never diffed or line-ending-normalised by git. - [.editorconfig (both repo root and HOME)] Full idiom audit: removed incorrect
insert_final_newline = falseoverrides for*.jsonand*.md; addedindent_style = tabfor*.{cmd,bat}; addedcharset = unset+insert_final_newline = falsefor*.zwc,*.zwc.old,*.defaults; added[*.sql]and[*.{xml,plist}]withindent_size = 4; added[*.envrc]shfmt block; added[{custom.gitattributes,…}] indent_size = unset; setmax_line_length = offglobally. - [.gitconfig] Added
git pull-unshallowandgit fetch-unshallowaliases (auto-unshallow shallow repos before pulling/fetching).git pullsubnow delegates topull-unshallow. Fixedgit uprebto usegrep -x upstream(exact match). Simplifiedgit sizeto avoid a nested subshell. Removed redundantgit prunefromgit cc. Fixedgit mnto pass--no-ff(required whenmerge.ff=onlyis set globally). Changedhelp.autoCorrectfrom10(100ms delay) toprompt. - [zsh git commands: cc, count, pull, push, st] Replaced inline argument-parsing loop with
parse_folder_and_switches; replaced inlinedispatch_or_fallbackexpansion with the shared helper call. - [scripts/] Fixed stale source comments across all scripts (
add-upstream-git-config.sh,capture-prefs.sh,capture-raycast-configs.sh,cleanup-browser-profiles.sh,post-brew-install.sh,recreate-repo.sh,run-all.sh,setup-login-item.sh,software-updates-cron.sh); added missing function doc comments; addedwarnin place ofechowhere.shellrchelpers are available. - [scripts/osx-defaults.sh] Structural refactor:
ask()moved from nested (insidemain()) to top-level;autopromoted to a script-level variable; sourcing changed from.shellrcto${ZDOTDIR}/.aliases;usage()added withprint_usage;getopts ':s'(colon-prefixed for error handling) replaces baregetopts 's'. - [scripts/run-all.sh] Refactored:
source "${HOME}/.shellrc"replaced with${ZDOTDIR}/.aliases; all globalMINDEPTH/MAXDEPTH/FOLDER/FILTERvars replaced with locals;find … | grep | sort -upipeline replaced with a zsh-native dedup loop using:hand an associative array;$(date +%s)→${EPOCHSECONDS}(no fork);usage()rewritten withprint_usage. - [scripts/resurrect-repositories.rb] Major refactor: all public functions renamed to private (
_find_git_repos_from_disk,_apply_filter,_generate_each, etc.);CliParserintegrated in place of inlineOptionParser;section_header/print_script_start/print_script_durationcalls added;_verify_allgains summary statistics (discovered_count/common_repos); resurrection loop gains per-repobegin/rescueerror isolation withsuccessful_repos/failed_repostracking — failures are now reported rather than aborting the loop. - [.shellrc] Fixed
${(j.:.)RUBYLIB_PATHS}bad substitution error when sourced by non-zsh runtimes (e.g. direnv). Wrapped theRUBYLIBblock inis_zshguard; updated comment to explain the direnv/bash incompatibility. - [.shellrc] Added
RUBYLIBsetup to point toscripts/utilities/so Ruby scripts canrequireshared utilities by name withoutrequire_relative. - [.aliases] Refactored
regenerate_repo_aliasesinto a single public function (removed separate_generate_repo_aliases): accepts optional-fflag to force-rebuild; always sources the cache at the end; prints progress only when-fis given. Renamed cache file fromrepo-aliases.zshtorepo-aliases-cache.zshfor consistency with other cache files. - [.aliases]
resurrect_tracked_repos: collect repo ancestor dirs once via_collect_repo_ancestor_dirsand share via_SHARED_REPO_DIRSacross bothallow_all_direnv_configsandinstall_mise_versionscalls (avoids running the expensivefindtraversal twice, but otherwise fall back to_collect_repo_ancestor_dirsif that’s not set.); callregenerate_repo_aliasesat the end; unset_SHARED_REPO_DIRSwhen done. - [.aliases] Moved
is_aliases_sourcedfunction definition to immediately after the re-source guard (beforesource "${HOME}/.shellrc"), mirroring theis_shellrc_sourcedplacement in.shellrc. - [.aliases] Added GROUP 3 header clarification:
(Groups 1 and 2 are defined in .shellrc — bootstrap utilities and core predicates.). - [scripts/install-dotfiles.rb, scripts/resurrect-repositories.rb] Added
$LOAD_PATH.unshift(File.join(__dir__, 'utilities'))to both scripts — ensures shared utilities are loadable regardless of whetherRUBYLIBis set (necessary duringFIRST_INSTALLwhere the dotfiles repo is cloned after.shellrcis first sourced). Switchedrequire_relative 'utilities/logging'→require 'logging'in both scripts. - [scripts/install-dotfiles.rb] Replaced inline
OptionParserblock withCliParser.parsefrom the new sharedcli_parserutility. - [scripts/utilities/cli_parser.rb, scripts/utilities/hash_ext.rb, scripts/utilities/path_utils.rb] New shared Ruby utilities.
cli_parserwrapsOptionParserwith standard error handling and--help;hash_extextendsHashwithdeep_sort;path_utilsexposesextract_path_segment_at(folder, index)extracts a path component by index (no subprocess fork). - [scripts/utilities/logging.rb] Refactored
terminal_widthto avoid||= begin...endpattern (rufo formatter instability); updated usage comment fromrequire_relativetorequire. - [scripts/utilities/string.rb]
colorizenow suppresses color output when$stdoutis not a TTY; tilde substitution applied insidecolorizeautomatically (callers no longer pre-substitute). Color codes changed from plain integers (e.g.31) to composite SGR strings (e.g.'0;31') to support bold/dim variants. Eight new color methods added;pinkrenamed topurple. - [scripts/utilities/file.rb] Deleted — the
File.appendmethod it provided is no longer used anywhere in the codebase. - [scripts/software-updates-cron.sh] Renamed
perform_update→_perform_update(private convention). Replaced[[ ${#array[@]} -gt 0 ]]withis_non_empty_arrayin two places. Fixed staleunset cutoff_epoch→unset cutoff_date. Addedgit restore-mtime,git maintenance register, andgit maintenance startsteps for all tracked repos. Addedbat cache --buildstep to keep the bat cache current after plugin changes. Removed theollama pullblock. Uses_collect_repo_ancestor_dirs/_SHARED_REPO_DIRSpattern to avoid duplicatefindtraversals. Sourcesupdate_all_reposandstatus_all_reposautoload scripts directly. Replacehome pull,oss upreb, andbcgalias calls with direct equivalents (run-all.sh,brew outdated --greedy) — aliases are not expanded in non-interactive shells (cron). - [scripts/setup-login-item.sh] Replaced
osascript | \grep -ipipeline with zsh glob pattern match${${(M)${(f)all_login_items}:#(#i)*${app_name}*}[1]}. - [Brewfile] Uncommented
shfmt— now an explicit dependency. - [all eligible shell and Ruby scripts] Reformatted using
shfmt(shell/zsh) andrufo(Ruby) per.editorconfigrules. - [.shfmtignore] New file. Excludes
.zshrcandcleanup-browser-profiles.sh(unparseable zsh-only syntax), and.shellrcand${ZDOTDIR}/.aliases(keep_paddingexpands intentional one-liners). - [.shellrc] In the
info/error/debug/warnfunctions, do not print anything if its being called from withindirenv. This is to suppress the noisy logs when cd’ing to different directories. - [scripts/install-dotfiles.rb]
custom.git*files now use mtime-based conflict resolution instead of always treating the destination as authoritative. OnFIRST_INSTALL(env var set) the destination always wins (moved into repo, copied back). On subsequent runs, the newer file wins; source wins on a tie.--forcebypasses mtime and always overwrites. - [files/–HOME–/.gitconfig] Made all aliases scripts POSIX-compatible.
- [files/–HOME–/custom.gitignore, files/–HOME–/custom.gitattributes, files/–PERSONAL_PROFILES_DIR–/custom.gitignore] Header comments updated to document the mtime-based resolution rules and FIRST_INSTALL behaviour.
- [.shellrc → .aliases] Moved 8 functions out of
.shellrcinto${ZDOTDIR}/.aliases— reducing.shellrc’s curl-download payload and startup cost on a vanilla OS install. - [.shellrc]
set_ssh_folder_permissions: updated comment to document both reasons it stays in.shellrc— (1) vanilla OS pre-install-dotfiles.rbbootstrap; (2) bash-compat: called from.envrcfiles evaluated by direnv in a bash subshell (${ZDOTDIR}/.aliasescannot be sourced in bash). - [scripts/software-updates-cron.sh] Added ERR trap: calls
error()(which triggersnotify) on unexpected failure. Added profiles repo size check to notify if 2 GB threshold is breached. - [files/–HOME–/.envrc, files/–PERSONAL_PROFILES_DIR–/.envrc] Added ERR trap to both
.envrcfiles. On any unexpected failure,notify()fires an osascript notification with the filename and line number — visible even when the terminal is not in focus. - [scripts/data/capture-prefs-denied-list.txt] New file listing 44 domains that must never be exported/imported: device identity UUIDs, MDM enrollment tokens, Apple ID credentials, AirTag beacon MACs, CloudKit cache blobs, printer presets keyed to IP addresses, and ephemeral UI/OS-version state. This script now loads the denied-list into an associative array at startup; skips any allowed-listed domain that also appears in the denied-list with a
warnmessage instead of silently exporting/importing machine-specific data. - [scripts/data/capture-prefs-allowed-list.txt] Removed all 44 denied-listed domains from the allowed-list.
- [files/–HOME–/.aliases]
find_and_append_prefs: checks each discovered domain against the denied-list before appending to the allowed-list; prints awarnand skips rather than adding a denied-listed domain. - [files/–HOME–/.aliases]
recronnow reads from the existing${PERSONAL_CONFIGS_DIR}/crontab.txtinstead of regenerating it from a hardcoded template every time._create_crontabis now a bootstrap-only seed — called only whencrontab.txtdoes not exist yet (vanilla OS scenario). - [files/–HOME–/.shellrc]
notifynow strips ANSI escape codes from the message before passing toosascript, preventing raw escape sequences from appearing as literal characters in macOS notifications. Uses inline zsh parameter expansion ((S)flag + extendedglob) instead of asedsubshell — avoids ERR trap inheritance into$(...)subshells where shell functions likecurrent_timestampare unavailable. Usessetopt local_options extendedglobto ensure##works correctly in non-interactive shells (cron) whereextendedglobis off by default. - [files/–HOME–/.gitconfig]
git cc: accept--expire=<when>to override the reflog expiry (default remains1.week.ago). Uses--expire=flag style (matchinggit reflog expire’s own interface) so the zsh autoload passes it throughswitcheswith zero extra code. Examples:git cc --expire=now,git cc --expire=3.days.ago. - [files/–HOME–/.gitconfig]
git rfc: rewrote as a!f()shell function; usesgit for-each-refto enumeraterefs/heads,refs/remotesexplicitly instead of--all, sorefs/stashis never expired and stashes are preserved.refs/tagsexcluded — tags have no reflogs. - [files/–HOME–/.gitconfig]
git cc: replaced--allinreflog expirewith an explicitgit for-each-refenumeration ofrefs/heads,refs/remotesonly — stashes preserved, tags excluded to avoid “reflog could not be found” errors on shallow clones. - [files/–HOME–/.gitconfig]
git sci: replaced locale-dependentgrep "to unstage"staging detection withgit diff --cached --quiet— robust across all git locales. - [files/–HOME–/.gitconfig]
git relative-path: fixed brokengit rootreference (alias never existed) and corrected path resolution to userealpath+git rev-parse --show-toplevelwith proper absolute-path stripping. The old implementation was silently producing wrong output. - [files/–HOME–/.gitconfig]
git fo: removed redundant--alland--tagsflags —fetch.all=true,fetch.prune=true, andfetch.pruneTags=truein config make plaingit fetchequivalent. - [files/–HOME–/.gitconfig]
git se: added-z/-0torev-list/xargspipeline for null-safe handling of filenames containing spaces. - [files/–HOME–/.gitconfig]
git standup: now defaults author togit config user.namewhen called with no argument. - [files/–HOME–/.gitconfig]
git rpo: added comment noting it is a no-op after any fetch due tofetch.prune=true, but remains useful as an explicit one-shot command. - [files/–XDG_CONFIG_HOME–/zsh/cc] Updated header documentation to reflect
--expireflag, default behaviour,--stale-fix, and--dry-runexample. - [.github/instructions/shell-scripting.instructions.md, .github/copilot-instructions.md] Sharpened
shfmtformatting rules: added explicit “check.shfmtignorefirst” directive, concrete before/after example of thewhile true; do ...; doneone-liner corruption bug, and explanation that runningshfmton an excluded file corrupts intentional one-liners with no inline suppression escape. - [.shellrc]
infoandsuccessare now suppressed whenDIRENV_DIRis set (i.e. running inside a direnv subshell evaluating an.envrc).warnanderroralways print. Cron jobs, CI, and interactive shells are unaffected. This silences routine.envrclog output from direnv without losing actionable messages. - [scripts/fresh-install-of-osx.sh] Added
set -Eimmediately afterset -euo pipefailso the existing_cleanup_and_exitERR trap is inherited by all helper functions defined in the file — previously a failure inside a helper would not trigger the trap. - [scripts/fresh-install-of-osx.sh] Fixed dead
$?check afterbrew bundle. Uncommentedresurrect_tracked_repos(now runs automatically, synchronously, beforeallow_all_direnv_configsandinstall_mise_versionsso repos exist before those sweep). DNS fallback changed from8.8.8.8to1.1.1.1. - [.github/copilot-instructions.md]
custom.git*exception block rewritten with FIRST_INSTALL / mtime resolution rules..shellrcvs${ZDOTDIR}/.aliasesdecision rule rewritten: clarifies theinstall-dotfiles.rbboundary, bash-compat reason for.shellrcretention, and lists zsh-autoload functions as${ZDOTDIR}/.aliasescandidates. - [.github/instructions/git-config.instructions.md, Extras.md]
custom.git*handling descriptions updated to reflect mtime-based resolution rules. - [files/–ZDOTDIR–/.zsh_plugins.txt, files/–ZDOTDIR–/.zsh_plugins.zsh] Un-deferred
fast-syntax-highlighting,zsh-autosuggestions, andzsh-history-substring-search.kind:deferuseszle -Fbut reschedules itself whenPENDING > 0(bytes already in the TTY buffer) — a fast typist beats the idle window and gets no highlighting, no suggestions, and non-functional Up/Down arrow on their first command. These three plugins directly affect the live typing experience and must be synchronous. Alias-only and cosmetic plugins (eza,git,termsupport,iterm2,sudo,zbell) remain deferred. Updated deferral policy comment to document thePENDINGrace condition and the deliberate tradeoff. - [files/–XDG_CONFIG_HOME–/zsh/update_all_repos, status_all_repos, st, pull, push, upreb, count, cc] Fixed
zsh_eval_contextself-invocation guard from*:file*to*file*. When sourced in azsh -ccontext (as in the cron script),zsh_eval_contextiscmdarg file(space-separated, not colon-separated), so*:file*did not match — causing the function to auto-execute onsource, then execute again on the explicit call (double-run).*file*matches bothtoplevel:shfunc:file(sourced from a script) andcmdarg file(sourced inzsh -c). - [files/–HOME–/.shellrc] Renamed
notify→_dotfiles_notifyto avoid collision with system/plugin commands (e.g. mise’scommand_not_found_handler) that return 127 and trigger the ERR trap in cron. Updated all call sites in.shellrc,.envrcfiles, andsoftware-updates-cron.sh. - [files/–HOME–/.shellrc]
success,info,warn,debug: replacedis_non_zero_string ... || echowithif ! is_non_zero_string ...; then echo; fi— the bare||pattern causedis_non_zero_stringreturning 1 (outside direnv) to fire the ERR trap in any caller running underset -e. - [files/–XDG_CONFIG_HOME–/zsh/st, update_all_repos, status_all_repos, pull, push, upreb, count, cc] Added
|| trueto thecompdefregistration guard in all autoload scripts.(($+functions[compdef]))exits 1 whencompdefis not yet defined (non-interactive shells, cron, pre-compinit), firing the ERR trap in any script that sources these files. - [files/–HOME–/.shellrc]
_dotfiles_notify: use[[ -x '/usr/bin/osascript' ]]instead ofcommand_exists— more precise (won’t match a function/alias namedosascript) and correct for a fixed system binary path. - [files/–ZDOTDIR–/.zshrc, files/–HOME–/.aliases, scripts/wait-editor] Fixed
crontab -e(and tools likevisudo,fc) not blocking for GUI editors.EDITORis always'wait-editor'— a thin wrapper that re-execs$GIT_EDITORvia POSIX word-splitting so--waitflags are passed correctly.GIT_EDITORholds the full editor invocation (e.g.'zed --wait', or'vi'for SSH). The SSH/local if-else in.zshrccollapsed into a single loop with a per-context preferred-editors list.VISUALis not set — legacy concept, every modern tool falls back toEDITOR. Removed now-redundant${EDITOR%% *}stripping in${ZDOTDIR}/.aliases. - [files/–ZDOTDIR–/.zshrc] Added
ZSH_AUTOSUGGEST_USE_ASYNC=1,ZSH_AUTOSUGGEST_MANUAL_REBIND=1,ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE=20before the antidote bundle load. Async mode fetches suggestions in a background process so ZLE never blocks on history lookups. Manual rebind skips the full ZLE widget re-wrap that autosuggestions performs on everyprecmd(~10–20ms per prompt). Buffer max size skips suggestion lookups for long command lines. - [files/–ZDOTDIR–/.zshrc] Changed
ZSH_AUTOSUGGEST_STRATEGYfrom(history completion)to(history)and addedZSH_AUTOSUGGEST_HISTORY_IGNORE="?(#c100,)". Thecompletionstrategy spawns azptyon every suggestion request (~10–30ms overhead); history alone covers the vast majority of useful suggestions. The ignore pattern skips history entries >100 chars, reducing regex matching cost on large history files. - [files/–HOME–/.gitconfig]
git ccandgit rfc: removedrefs/tagsfromgit for-each-refenumeration passed togit reflog expire. Tags have no reflogs (especially in shallow clones such as antidote cache repos), causing “reflog could not be found” errors for every tag. Onlyrefs/headsandrefs/remotesare valid reflog targets. - [files/–ZDOTDIR–/.zshrc] Fixed silent bug:
list-suffixeszstyleon one line (missing newline typo) meant bothlist-suffixesandexpand prefix suffixcompletion styles were never set. Split into two separatezstylecalls. - [files/–ZDOTDIR–/.zshrc] Removed three
compctl(old pre-compsys zsh 2.x) calls and theman_glob()helper they depended on.compctl -k hostsreferenced an undefined$hostsarray; all three calls conflicted silently with compsys_ssh/_mancompleters fromzsh-completions. - [files/–ZDOTDIR–/.zsh_plugins.txt, files/–ZDOTDIR–/.zsh_plugins.zsh] Deferred 6 additional plugins via
kind:deferto reduce synchronous startup work:lib/termsupport.zsh(terminal title/CWD hooks — cosmetic),plugins/eza(aliases only),plugins/git(heaviest plugin at 431 lines, aliases only),plugins/iterm2(shell integration hooks — cosmetic),plugins/sudo(ESC-ESC key binding),plugins/zbell(long-command bell hooks). Cannot defer:lib/functions.zsh,lib/completion.zsh,lib/correction.zsh,lib/key-bindings.zsh,lib/misc.zsh,zsh-completions,plugins/direnv. - [files/–ZDOTDIR–/.zshrc] Added
ensure_dir_exists "${XDG_CACHE_HOME}"before the first cache write. Whendelete_cachesremoves~/.cache, all subsequent>|cache-write redirections failed silently — thebrew shellenvcache was never written, sofpathnever received${HOMEBREW_PREFIX}/share/zsh/site-functions, breaking brew completions and antidote plugins on the next shell start. - [files/–ZDOTDIR–/.zlogin] Moved
find_in_folder_and_recompile "${XDG_CACHE_HOME}"into the disowned background block. The mtime sentinel never actually prevented thefindscan:.zshrcalways writes cache files before.zloginruns, so the sentinel’s-ntcheck always failed andfindran synchronously on every login shell. - [personal/dev/configs/crontab.txt, files/–HOME–/.aliases] Expanded crontab
PATHto include/usr/local/bin,/usr/sbin,/sbin,${PERSONAL_BIN_DIR}, and${DOTFILES_DIR}/scripts— previously only/opt/homebrew/bin:/usr/bin:/bin, causingrun-all.sh,capture-prefs.sh,regenerate_repo_aliases, and standard utilities to be not found in cron. - [personal/dev/configs/crontab.txt, files/–HOME–/.aliases] Fixed
run-all.shandcapture-prefs.shnot found in cron despite correct PATH. Crontab treats#as part of a value on assignment lines, so an inline comment was appended to the last PATH directory name, making it invalid. Moved the explanation to a standalone comment line above thePATH=assignment. - [scripts/software-updates-cron.sh] Removed
load_zsh_configscall — it sourced.zshrcwhich activated mise and installedcommand_not_found_handler. That handler returned 127 in the non-interactive cron environment, firing the ERR trap. The script only needs${ZDOTDIR}/.aliases. - [personal/dev/configs/crontab.txt, files/–HOME–/.aliases] Fixed cron invocation: changed from
chronic /opt/homebrew/bin/zsh script.sh 2>&1 | tee(tee outside chronic’s scope — log never written on success) tochronic /opt/homebrew/bin/zsh -c 'zsh script.sh 2>&1 | tee'so chronic wraps the full pipeline. - [scripts/software-updates-cron.sh] Added
setopt LOCAL_TRAPSinsidemain()and moved ERR trap setup there, so the trap is scoped tomainand not inherited into called functions. - [scripts/software-updates-cron.sh] Consolidated macOS notifications: removed the mid-run outdated notification (immediately replaced by the final “done” notification). The final notification now includes the comma-separated outdated package list when present.
- [.github/instructions/shell-scripting.instructions.md, .github/copilot-instructions.md, .github/instructions/git-config.instructions.md] Updated docs:
zsh_eval_contextguard (*file*),compdef|| trueguard, andgit cc/git rfcrefs/tagsexclusion rule. - [all shell script] Removed all redundant
unsetcalls onlocalvariables —localvariables auto-clean on function return, sounsetinside the same function is always a no-op.
Adopting these changes
-
Rebase from upstream, resolve conflicts, and then run in any open terminal:
cp ${DOTFILES_DIR}/files/--HOME--/custom.gitattributes ${HOME}/.gitattributes cp ${DOTFILES_DIR}/files/--HOME--/custom.gitignore ${HOME}/.gitignore install-dotfiles.rb - Run
delete_cachesto clear any stale.zwcbytecode and cached shell environment files. - Quit and restart the Terminal application.
3.0-18
- [.zshrc] Replaced Oh My Zsh with antidote as the plugin manager. A pre-generated static bundle (
${ZDOTDIR}/.zsh_plugins.zsh) is checked into the home repo and sourced directly — antidote itself does not need to be installed for the shell to start. The antidote formula (installed viabrew) and sourced at shell startup is only required forantidote update/antidote bundleto refresh plugin sources. - [.zshrc] Removed all Oh My Zsh bootstrap variables (
ZSH,ZSH_CUSTOM,ZSH_THEME,ZSH_DISABLE_COMPFIX,zstyle ':omz:update' ...,plugins=(...)) and thesource "${ZSH}/oh-my-zsh.sh"call.compinit -Cis now called explicitly (no longer delegated to OMZ). Stale alias/comment block referencing OMZ examples removed. - [.zshrc]
mise activate zshis now cached — output written to${XDG_CACHE_HOME}/mise-activate-cache.zshkeyed on the mise binary mtime, regenerated only when mise itself is updated. The OMZmiseplugin was removed because it referenced${ZSH_CACHE_DIR}(undefined without OMZ), which caused a “no such file or directory: /completions/_mise” error on every shell start. - [.zshrc] Added
typeset +x FPATH fpath cdpath CDPATHafter the dedup pass —FPATHandCDPATHmust never be exported. Both are zsh-internal variables (autoload search path andcdsearch path respectively). Exporting them causes their contents to leak into the macOS launchd user-session environment, where they persist across iTerm2 restarts and are inherited by every new shell before any rc file runs. Symptoms:zsh -f -c 'echo $FPATH'showed stale~/.oh-my-zsh/...paths even after~/.oh-my-zshwas deleted. All other*pathvars on that line (PATH,MANPATH,INFOPATH,CPPFLAGS,LDFLAGS,PKG_CONFIG_PATH) are intentionally exported — child processes need them. - [.zshrc]
compinitrefactored to use-C(skipcompauditscan) when the dump file already exists, saving ~11ms per startup. Wrapped in an anonymous function soautoload -Uz compinitdoes not pollute the global function table.ZSH_COMPDUMPmoved to${XDG_CACHE_HOME}/zcompdumpto keep${HOME}clean. - [.zshrc] Starship prompt initialisation cached to
${XDG_CACHE_HOME}/starship-init-cache.zsh, keyed on the starship binary mtime — avoids forkingstarship init zshon every shell start.${commands[starship]}used instead of$(command -v starship)(O(1) zsh hash lookup, no fork). Note: sourcing via aprecmdhook was attempted but causessetopt promptsubst(emitted by starship’s init) to be scoped to the hook function, leavingPROMPTas an unexpanded literal after the first command — the cache is therefore sourced directly at startup. - [.zshrc]
autoload -Uz colors && colorsremoved — none of the active plugins use$fg/$bg/$colorfrom the zshcolorsfunction; own color variables are defined as$'\e[...'literals in.shellrc. - [.zshrc]
$(extract_first_word "${editor}")in the preferred-editor detection loop replaced with${editor%% *}(inline parameter expansion, no subshell). - [.zshrc] Fixed bug in autoload loop:
autoload -Uz "${func_file}"→autoload -Uz "${func_file:t}". Without:t(basename),autoloadregisters the function under its full path (e.g./path/to/myfunc) which can never be invoked by short name. - [.zlogin]
recompile_zsh_scriptsnow removes.zwc.oldbefore and after callingzrecompile -pq—zrecompilemoves the existing.zwcto.zwc.oldbefore writing the new one; ifzcompilefails mid-write the backup is left behind indefinitely. Cleanup is unconditional so stale backups never accumulate. - [.shellrc] Added
export ANTIDOTE_HOME,ANTIDOTE_ZSH, andANTIDOTE_PLUGIN_ZSH— set early (beforeantidote.zshis sourced) so they are available in.zloginand other contexts.ANTIDOTE_HOMEmirrors antidote’s own platform defaults:~/Library/Caches/antidoteon macOS,${XDG_CACHE_HOME}/antidoteon Linux. - [.zsh_plugins.txt] New file — canonical antidote plugin list, replacing the old
plugins=(...)array in.zshrc. Loads selected OMZ lib files, OMZ plugins and third-party plugins. - [Brewfile] Added
antidoteto the base-configs section (installed on every machine, includingFIRST_INSTALL). Replaceddiff-so-fancywithdeltaas the diff/pager tool. Replacedjqwithjaq(a faster Rust reimplementation). Commented outcodeqlcask. - [scripts/fresh-install-of-osx.sh] Replaced
install_oh_my_zsh_and_custom_plugins(curl install + threegit clonecalls for custom plugins) with a call toupdate_antidote_and_regenerate_plugin_bundleplaced afterhomebrewis installed. - [scripts/post-brew-install.sh] Added antidote update and bundle regeneration step by invoking
update_antidote_and_regenerate_plugin_bundleon everybrew bundle/bupcrun, keeping the bundle in sync after antidote itself is installed or upgraded. - [scripts/software-updates-cron.sh] Replaced
omz updatewith the equivalent antidote update functionupdate_antidote_and_regenerate_plugin_bundle.
Adopting these changes
-
Rebase from upstream, resolve conflicts, and then proceed with the following steps in any open terminal:
cp ${DOTFILES_DIR}/files/--HOME--/custom.gitignore ${HOME}/.gitignore rm -rf "${HOME}/.oh-my-zsh" install-dotfiles.rb # Symlink .zsh_plugins.txt and .zsh_plugins.zsh into ${ZDOTDIR} brew install antidote # Install antidote (a zsh script, not a binary) source "${HOMEBREW_PREFIX}/opt/antidote/share/antidote/antidote.zsh" # Load the antidote function into the current shell antidote bundle < "${ZDOTDIR}/.zsh_plugins.txt" > "${ZDOTDIR}/.zsh_plugins.zsh" # Generate the static plugin bundle launchctl unsetenv FPATH # One-time flush of the stale FPATH from the launchd user environment delete_caches # Clear stale .zwc bytecode and all generated cache files to pick up the typeset +x change -
Quit and restart the Terminal application (a full restart is required — sourcing in-place leaves old OMZ functions in memory).
3.0-17
- [files/–HOME–/.p10k.zsh (deleted), files/–XDG_CONFIG_HOME–/starship.toml (new), files/–HOME–/Brewfile, files/–ZDOTDIR–/.zshrc] Replaced powerlevel10k with Starship as the prompt engine. Deleted
.p10k.zshand the OMZ p10k instant-prompt setup from.zshrc; addedstarship.toml; replacedtap 'romkatv/powerlevel10k'andbrew 'powerlevel10k'withbrew 'starship'in the Brewfile.
Adopting these changes
-
Rebase from upstream, resolve conflicts, and then run in any open terminal:
cp ${DOTFILES_DIR}/files/--HOME--/custom.gitignore ${HOME}/.gitignore install-dotfiles.rb rm -f "${HOME}/.p10k.zsh" # remove dangling symlink — source deleted from repo brew install starship delete_caches -
Quit and restart the Terminal application.
3.0.16
- [fresh-install-of-osx.sh] Fixed issue where this script was failing silently on the first run on a vanilla OS (root cause: curl timeout within homebrew while downloading installables). Replaced the
HOMEBREW_BASE_INSTALLvariable withFIRST_INSTALLand added a guard which disables the ERR trap during brew operations, forces re-download of.shellrc, sets a long curl timeout (--max-time 3600), splitsbrew bundleinto separate tap/formula/cask passes for better isolation and resilience, and restores the trap + unsets the extra curl args afterwards. - [Brewfile] Renamed the early-exit guard from
HOMEBREW_BASE_INSTALLtoFIRST_INSTALLfor consistency. - [software-updates-cron.sh] Prune Zen session-backup files older than 7 days from the browser-profiles repo (works with both macOS BSD and GNU
date). - [.shellrc] Added TODO comments in
clone_repo_intofor future reftable support once p10k resolves thevcs_infoincompatibility, including a HEAD-fixup snippet for post-move repos. - [.gitconfig, custom.gitignore, custom.gitattributes, recreate-repo.sh] Git performance tuning and ignore/attribute reorganisation.
- [.gitconfig] Tuned git performance settings: set
core.autocrlf=false, increasedcore.compressionandpack.compressionto 9, raisedpack.deltaCacheSizeto 2047m andpack.windowMemoryto 1g, enabledpack.useDeltaBaseOffset, addedfetch.negotiationAlgorithm=skipping,http.version=HTTP/2,protocol.version=2, andrepack.packKeptObjects=false/repack.useDeltaBaseOffset=truefor faster and smaller pack operations. - [.gitconfig] Added
init.defaultRefFormat=reftableas a commented-out TODO pending p10k support. - [custom.gitattributes] Added explicit
eol=lfenforcement via* text=auto; added binary markers for common image, font, and byte-compiled extensions (*.png,*.jpg,*.woff*,*.ttf,*.pyc,*.zwc*, etc.) so git never mangles them. - [custom.gitignore (home)] Major reorganisation: grouped all ignore rules under labelled section headers (OS, shell history, caches, build tools, IDE, AI tools, XDG config, SSH, home directories, dev workspace, misc app data, symlinked dotfiles, negations); added new entries for opencode auto-generated files, Zed conversations/themes, GitHub Copilot, Gemini/Qwen/Safety AI tools, and various other tools.
- [custom.gitignore (profiles)] Full rewrite with labelled sections; consolidated browser-profile ignore rules across all
*Profiledirs (lock files, caches, crash artefacts, telemetry, security state, network/SW state, runtime DBs); added detailed per-browser sections for Firefox, Zen, Thunderbird, and Chrome Beta with explicit comments on what is intentionally tracked. - [.shellrc] Added TODO comments in
clone_repo_intofor future reftable support; added logic to fix the.git/HEADfile after reftable clone-via-move. - [recreate-repo.sh] Added TODO comment for future
git init --ref-format=reftablesupport. - [software-updates-cron.sh] Added a new step to prune tracked Zen session backup files older than 7 days from the browser-profiles repo (compatible with both macOS BSD and GNU
date). - [.shellrc] Added
step_start,step_end, andstep_timing_inithelper functions for per-step and total elapsed time reporting in scripts. - [fresh-install-of-osx.sh, software-updates-cron.sh] Instrumented all major steps with
step_start/step_endcalls for granular timing output. Also initialise_SCRIPT_START_TIMEexplicitly so timing is accurate before.shellrcis sourced. - [Brewfile] Enabled
cairo,gnu-tar,mercurial, andsccache(previously commented out) for zen-browser development. - [.zshrc] Added
gnu-tarto the list of keg-only Homebrew packages that override macOS defaults. Removed thegit_scriptspath addition. - [.envrc (profiles)] Temporarily disabled natsumi-browser cloning as a trial. Removed
timeoutwrapper fromadd-upstream-git-config.shcall. - [software-updates-cron.sh] Temporarily disabled natsumi codebase update block as a trial.
- [Brewfile] Added
Mechvibessince Haptyk turned out to be payware after some days. RemovedHaptykfromcapture-prefs-domains.txtand addedMechvibes. - [GettingStarted.md] Updated bootstrap one-liner to use
FIRST_INSTALLinstead of the oldHOMEBREW_BASE_INSTALLvariable name. - [.shellrc] Added
ServerAliveInterval=10andServerAliveCountMax=3SSH options to thesubmodule updatecall inclone_repo_intoto prevent silent hangs on flaky connections. - [.aliases] Updated
grep/fgrep/egrepaliases: removed VCS dirs from--exclude-dir(since Homebrewgrephandles them natively) and added*.zwc*/.*.zwc*to--excludepatterns. Removed--allflag frombupc’sbrew bundlecall. Addedallow_all_direnv_configsandinstall_mise_versionscalls insideresurrect_tracked_repos. - [.zshrc] Refactored
use_homebrew_installation_forto accept a package name (e.g.curl) instead of a full path; the function now derives the path internally via${HOMEBREW_PREFIX}/opt/${1}. Addedgrepto the keg-only packages loop. Added explicitprepend_to_path_if_dir_existscalls for${HOMEBREW_PREFIX}/binand${HOMEBREW_PREFIX}/sbin. - [mise/config.toml] Enabled
experimental = truefor mise. - [zed/settings.json] Enabled thinking mode (
enable_thinking = true) and seteffort = "high"for the default Zed AI model.
Adopting these changes
-
Rebase from upstream, resolve conflicts, and then proceed with the following steps:
cp "${DOTFILES_DIR}/files/--HOME--/custom.gitattributes" "${HOME}/.gitattributes" cp "${DOTFILES_DIR}/files/--HOME--/custom.gitignore" "${HOME}/.gitignore" "${DOTFILES_DIR}/scripts/install-dotfiles.rb" -
Quit and restart the Terminal application.
3.0.15
- [scripts] AI-based refactoring of shell scripts and ruby scripts to remove redundant scripting issues like unnecessary
local/unsetdeclarations. - [.curlrc, .envrc, .gitconfig, .iex.exs, .profile, .zlogin, .zshrc] General cleanup and minor improvements across dotfiles.
- [zsh scripts] Refactored
cc,count,pull,push,st,status_all_repos,update_all_repos, anduprebscripts. - [.eclintignore, .editorconfig] Added editor config and eclint ignore files for consistent code style enforcement.
- *[add-upstream-git-config.sh, .shellrc] Potential fix for
direnv allowhanging when run in the$PERSONAL_PROFILES_DIRfolder by ensuring that the git config is properly set up for that folder. - [.gitconfig] Added new alias
default-branchto get the default branch of a git repository.
Adopting these changes
-
Rebase from upstream, resolve conflicts, and then proceed with the following steps:
cp "${DOTFILES_DIR}/files/--HOME--/custom.gitignore" "${HOME}/.gitignore" "${DOTFILES_DIR}/scripts/install-dotfiles.rb" -
Quit and restart the Terminal application.
3.0.14
- [Brewfile] Replaced
IcewithThaw.
3.0.13
- [Brewfile] Added
Dockdoor,flux-markdown,dbeaverandcodeqlto the Brewfile and captured their preferences for backup. - [.aliases] The dynamically generated aliases for the git repositories found under the
$PROJECTS_BASE_DIRwill now enable more fine-grained control. To find out what all aliases have been setup on your machine, you can runalias | \grep rug.
Adopting these changes
-
Rebase from upstream, resolve conflicts, and then proceed with the following steps:
cp "${DOTFILES_DIR}/files/--HOME--/custom.gitignore" "${HOME}/.gitignore" source "${ZDOTDIR}/.aliases" "${DOTFILES_DIR}/scripts/install-dotfiles.rb" -
Quit and restart the Terminal application.
3.0.12
- [.aliases] New alias for
mkdirthat will create the directory and its parent directories if they don’t exist.
3.0.11
- [.aliases]
recronwill now generate the default crontab file and then register it with the system’scrontabcommand. - [Brewfile] Added
moleinstead ofpearcleanerfor a cli-based tool to clean disk space. - Custom git-related zsh scripts in
${XDG_CONFIG_HOME}/zsh/now properly handle git switches passed to them. - Added
direnvconfiguration file.
Adopting these changes
-
Rebase from upstream, resolve conflicts, and then proceed with the following steps:
cp "${DOTFILES_DIR}/files/--HOME--/custom.gitignore" "${HOME}/.gitignore" source "${HOME}/.shellrc" source "${ZDOTDIR}/.aliases" "${DOTFILES_DIR}/scripts/install-dotfiles.rb" recron crontab -l # should now show the crontab with the software updates cron job -
Quit and restart the Terminal application.
3.0.10
- [install-dotfiles.rb] Now handles the case where there’s no env var substitution needed in the file’s relative path, in which case, the file is treated as needing to be processed from the machine’s root directory.
- Use
git restoreinstead ofgit checkoutto restore files.
3.0.9
- Fixed issues when running
install-dotfiles.rbscript on a vanilla macos with ruby 2.6 and optimized it for better performance. - Fixed all shell scripts using claude-sonnet for better readability and maintainability.
Adopting these changes
-
Rebase from upstream, resolve conflicts, and then proceed with the following steps:
rm -rf "${XDG_CONFIG_HOME}/zsh" "${DOTFILES_DIR}/scripts/install-dotfiles.rb" -
Quit and restart the Terminal application.
3.0.8
- [Brewfile] Added opencode for terminal-based free/OSS AI assistant.
- [Brewfile] Removed AlDente since its built into Tahoe now.
- [Brewfile] Removed Brave browser since I will use Chrome if needed.
- [install-dotfiles.rb] Use
SSH_CONFIGS_DIRenvironment variable for ssh config directory.
3.0.7
- Moved
files/--HOME--/.ssh/global_configfile tofiles/--SSH_CONFIGS_DIR--/to make use of the correct ssh folder location if it was customized. - mise will default to using pre-compiled ruby binaries if available.
- [Brewfile] Install
keycluanddrawioapps and captured their preferences for backup.
3.0.6
- [osx-defaults.sh] Fix syntax issue.
- Remove redundant lines in multiple shell scripts.
- [Brewfile] Remove
unquarantineflag in Brewfile since its no longer supported.
3.0.5
- [install-dotfiles.rb] and [run-all.sh] Added support for running in ‘dry-run’ mode and printing the summary.
- [software-updates-cron.sh] Removed pruning of mise-installed software since that doesn’t work with the latest version of mise.
3.0.4
- [Brewfile] Replaced ‘Raycast’ with ‘Sol’ (https://github.com/ospfranco/sol) - lightweight, FOSS, faster.
- [Brewfile] Added ‘Shortcat’ (https://github.com/shortcatapp/shortcat) for faster and more efficient keyboard shortcuts.
- [resurrect-repositories.rb] Support for ruby 2.6 (default ruby in macos 26 Tahoe): added ‘pathname’ to require list.
3.0.3
- Revamped the documentations to improve clarity, readability and adoptability.
3.0.2
- [run-all.sh] Renamed the script to follow the naming convention (using hyphen instead of underscore) for all shell scripts.
- Replaced the
HOMEenv var with the tilde (~) to represent the home directory when printing so as to reduce the amount of text being displayed on the console.
Adopting these changes
-
Rebase from upstream, resolve conflicts, and then proceed with the following steps:
cp "${DOTFILES_DIR}/files/--HOME--/custom.gitignore" "${HOME}/.gitignore" source "${HOME}/.shellrc" source "${ZDOTDIR}/.aliases" "${DOTFILES_DIR}/scripts/install-dotfiles.rb" -
Quit and restart the Terminal application.
3.0.1
- [install-dotfiles.rb] Optimized the installation script for performance.
- Introduced
qwen-codeandclaude-code. (settled on qwen-code)
3.0.0
- Squashed all commits into a single commit.
- Tested on a fresh vanilla macos (26.2) machine.
Adopting these changes
- Quit all browsers completely
-
Rebase from upstream, resolve conflicts, and then proceed with the following steps:
git tag -d 1.0 git tag -d 2.0 mv "${HOME}/.dotfiles" "${XDG_CONFIG_HOME}/dotfiles" mv "${HOME}/personal/${USERNAME}/profiles" "${HOME}/personal/${USERNAME}/browser-profiles" source "${XDG_CONFIG_HOME}/dotfiles/files/--HOME--/.shellrc" cp "${XDG_CONFIG_HOME}/dotfiles/files/--HOME--/custom.gitignore" "${HOME}/.gitignore" "${XDG_CONFIG_HOME}/dotfiles/scripts/install-dotfiles.rb" allow_all_direnv_configs - Quit and restart the Terminal application.
2.0.47
- *[.aliases] Extract
restore_cronfunction to remove some duplication. - [fresh-install-of-osx.sh] Removed resurrecting all tracked repos to save time while re-imaging/setting up the laptop.
- [osx-defaults.sh] Turned off spotlight indexing for all volumes.
Adopting these changes
- Rebase from upstream, resolve conflicts.
- Quit and restart your Terminal application for these changes to take effect.
2.0.46
- Moved processing of the natsumi browser extension into the
.envrcfile so thatdirenvwill take care of it automatically. This also handles cases where a new browser is installed after the first time setup. - Moved resurrecting of tracked repos to the end after the import of preferences and setting up the cron job since it takes a long time and should not block the import process.
2.0.45
- Added a new script
run-all.shto run any unix command in matched git repos. - [fresh-install-of-osx.sh] Removed cloning of the
git_scriptsrepo since therun-all.shscript has now been moved into this repo. - [.shellrc] Replaced function
dir_has_childrenwithis_dir_emptywhich checks if a directory is empty. - [.zlogin] Recompile scripts in the foreground since running in the background results in silent failures.
- [.aliases] Added a new alias
resurrect_tracked_reposto resurrect all tracked repositories. - Renamed
FIRST_INSTALLtoDEBUGto better reflect the functionality.
2.0.44
- Updated documentation to include the setup of the cronjobs.
2.0.43
- Added a new function
is_shellrc_sourcedto check if the shellrc file is sourced. - Changed all shell scripts to use single quotes where possible to ensure that we don’t accidentally expand variables or execute commands.
- [osx-defaults.sh] Converted to a zsh script.
2.0.42
- Changed all shell scripts to use switches instead of positional arguments for more intuitive usage.
- Removed the use of colors if there’s no terminal (for eg for cron jobs).
- Removed
boring-notchcask since it was causing issues when installing on a fresh vanilla os.
2.0.41
- Adopted Zed as the default editor and removed VSCodium.
- Miscellaneous fixes and improvements to shell scripts.
- Cleanup documentation.
Adopting these changes
-
Rebase from upstream, resolve conflicts, and then proceed with the following steps:
bupc cp "${DOTFILES_DIR}/files/--HOME--/custom.gitignore" "${HOME}/.gitignore" install-dotfiles.rb -
Quit and restart your Terminal application for these changes to take effect.
2.0.40
- [resurrect-repositories.rb] Fixed an issue while cloning git repos where the script was silently proceeding further.
2.0.39
- [Brewfile] Added common & essential OSS packages that are typically behind in macos (typically due to license issues).
- [.zshrc] Fixed issue with
RUBY_CONFIGURE_OPTSnot being set correctly whenopensslis installed.
2.0.38
- [resurrect-repositories.rb] Changed the repo-resurrection generation logic to reduce manual edits to the generated yaml structure. This now handles generating the yaml with references to the
PROJECTS_BASE_DIRandHOMEenv variables to make it generic and not hardcode the user’s login name/home folder.
2.0.37
- [.shellrc] Restructured the env var’s section to be more explicit as to what section/vars need to be changed, and which ones can be optionally changed.
- [.shellrc] Extracted usages of
${HOME}/.sshinto a new env var defined in.shellrcso that custom locations can be easily changed in a single place.
Adopting these changes
- Rebase from upstream, resolve conflicts.
- Quit and restart your Terminal application for these changes to take effect.
- Run
install-dotfiles.rbin the new shell. - Manually edit
${HOME}/.ssh/configto replace the reference to~/.ssh/global_configtowards the last line with./global_config. If this results in a duplicate line, remove the duplicate line. - Verify the above changes in the
${HOME}/.ssh/configfile by runninggit pullin one of the cloned repos on your local machine.
2.0.36
- All
git pushinvocations now have the explicit--progressflag. - [.shellrc]
errorfunction will no longer exit the process. It just returns a non-zero code which needs to be handled by the caller. - [.aliases]
kbgcalias has been changed to a function, which now accepts parameters as to which repo to process.
Adopting these changes
- Rebase from upstream, resolve conflicts.
- Quit and restart your Terminal application for these changes to take effect.
2.0.35
- Make handling of stdout and stderr consistent across all usages.
- Handle immediate exit from shell scripts with appropriate error messages.
- IMPORTANT: The
post-brew-install.shscript was not being invoked when runningbrew bundlecommand due to a path issue. Even if the path was hardcoded into theBrewfile, another issue (relating to that block being evaluated when theBrewfilewas being read itself) is present. So, this invocation has been turned off.
Adopting these changes
- Quit and restart your Terminal application for these changes to take effect.
2.0.34
- [fresh-install-of-osx.sh] Move the custom handling of the
direnvfor the home and profiles folders intoallow_all_direnv_configs. - [cleanup-browser-profiles.sh] Remove parallelization since the code seems cleaner.
- General cleanup for maintainability and removing duplicate code.
Adopting these changes
-
Rebase from upstream, resolve conflicts, and then proceed with the following steps:
cp "${DOTFILES_DIR}/files/--HOME--/custom.gitignore" "${HOME}/.gitignore" install-dotfiles.rb -
Quit and restart your Terminal application for these changes to take effect.
2.0.33
- Show the git repo size in the p10k prompt.
2.0.32
- Minor fixes for using
ZSHenv variable instead of hardcoding${HOME}/.oh-my-zshin multiple places.
2.0.31
- Unignore
${HOME}/.ssh/known_hostsso that the repository resurrection process is done without user interaction. - When using the
errorfunction, a visual notification is also raised in the Notifications area so that the user need not monitor themailcommand if there are any outdated GUI apps that need upgrading usingbcug.
Adopting these changes
-
Rebase from upstream, resolve conflicts, and then proceed with the following steps:
cp "${DOTFILES_DIR}/files/--HOME--/custom.gitignore" "${HOME}/.gitignore" install-dotfiles.rb
2.0.30
- Updated documentation to clearly call out where references to my username (
vraravam) should NOT be changed when forking for your usage. - [.aliases] Renamed
delete_zsh_compilationstodelete_caches.
2.0.29
- Added Tor Browser.
- Updated instructions for exporting/importing Raycast configurations.
2.0.28
- Fixed issue with
uprebandccscripts since they were not evaluating the current working directory at the time of invocation. Instead, they were evaluating at the time of shell startup. - [Brewfile] Added
dua-clifor disk usage measurement from the cli.
2.0.27
- [.aliases] Removed
upreb_mealias andupreb-universal.shand combined both into a single zsh autoloaded script. This also allows to override it with a folder-specific implementation that can handle pre- and post- (or full override) steps as needed. - [.shellrc] Reduce line length when invoking the
section_headerfunction by replacing the value ofHOMEenv var with~. - Introduced
.terraformrcfile for configuring terraform.
Adopting these changes
-
Rebase from upstream, resolve conflicts, and then proceed with the following steps:
install-dotfiles.rbAfter running the above script, there might be changes that show up in the dotfiles repo, which again need to be reconciled. While doing so, please keep in mind how this will need to work when running on a vanilla OS (even in cases where the prior machine is not working/accessible). So, ensure that any logic that you add should work in that scenario.
-
Quit and restart your Terminal application for these changes to take effect.
2.0.26
- Fixed an issue where running
fresh-install-of-osx.shcaused the whole terminal app to quit at the end.
2.0.25
- [Brewfile] Removed
ghosttysince there are some features that make iTerm better suited for my usecase.
2.0.24
- [Brewfile] Introduce
ghosttyand capture its configuration.
Adopting these changes
-
Rebase from upstream, resolve conflicts, and then proceed with the following steps:
cp "${DOTFILES_DIR}/files/--HOME--/custom.gitignore" "${HOME}/.gitignore" install-dotfiles.rb
2.0.23
- De-duplicate
uprebscript to handle all locally checked out branches in a generic manner using a universal script rather than duplicating for each folder. - [.shellrc] Updated the
section_headerfunction to be smart about viewport column width and center the text as optimally as possible.
2.0.22
- Introduce configuration in
gitto usepandocfor diffing word documents.
2.0.21
- Commented out the update to FF & Zen browser’s user.js scripts since I have started using RapidFox settings.
2.0.20
- Trying to grayjay for youtube replacement.
2.0.19
- Enhanced
curlconfigurations and enable retry even for first time setup. - Turn on compression for ssh connections.
- Use
repack.MIDXMustContainCruftin git config to optimize repo size.
2.0.18
- [Brewfile] Replace deprecated
tldrwithtlrc. - Run the
ssh-addcommand via direnv for theHOMEfolder. (It’s idempotent, and so safe to be re-run for each new terminal window startup.)
2.0.17
- [.gitignore_global] Add all
.*keepfiles to not be ignored. - Fix gitignore configs for profiles repo.
Adopting these changes
-
Rebase from upstream, resolve conflicts, and then proceed with the following steps:
cp "${DOTFILES_DIR}/files/--PERSONAL_PROFILES_DIR--/custom.gitignore" "${PERSONAL_PROFILES_DIR}/.gitignore" cp "${DOTFILES_DIR}/files/--HOME--/custom.gitignore" "${HOME}/.gitignore" install-dotfiles.rb
2.0.16
- [.gitconfig] Enable
clone.rejectShallow. - [Brewfile] Try out BoringNotch.
2.0.15
- [.gitconfig] Fixed issues with incorrect sorting configurations.
- [Brewfile] Replaced ‘floorp’ with ‘google chrome beta’ since floorp doesn’t expose custom key-bindings for switching workspaces. Moved to ice beta to support macos 26 Tahoe beta.
2.0.14
- Removed
ZenProfilefrom being processed to inject Natsumi for user chrome. - Updated documentation for catching up with multiple commits from upstream.
2.0.13
- Fixed an issue where the homebrew’s libraries were not picked up first in the PATH.
2.0.12
- [post-brew-install.sh] Fixed issue with app name for Visual Studio Code while crearing cmd-line executable.
- [Brewfile] Removed Picocrypt and Unarchiver due to non-usage.
2.0.11
- [software-updates-cron.sh] Runs the
bcgalias as the last command and if there are any oudated softwares, it will error out. This serves as a simple mechanism to prompt the user that some softwares need manual updating.
2.0.10
- [fresh-install-of-osx.sh] Added command to add the checked-out ssh keys to the ssh-agent.
- [.gitconfig] Added some more configurations.
- [Brewfile] Use new name for ollama cask.
2.0.9
- [fresh-install-of-osx.sh]
approve-fingerprint-sudo.shhas now been converted from a standalone script into a function.
2.0.8
- [fresh-install-of-osx.sh] Moved each logical block into a function so its easier to understand and maintain.
2.0.7
- [Brewfile] Onyx is now only processed if the current OS is non-beta.
2.0.6
- Updated more documentation.
- [capture-raycast-configs.sh] and [capture-prefs.sh] now handle switches vs arguments/parameters consistently.
- [software-updates-cron.sh] Now also pulls
ollamamodels:codellamaanddeepseek-r1.
2.0.5
- Updated
README.mdto make adoption steps clearer to follow. - Formatting of markdown files.
2.0.4
- [.aliases] Introduced a new function
find_and_append_prefsthat finds and appends the preferences associated with the partial string passed in as an argument. Also, sorts (and removes duplicates) from the config file used to capture preferences.
2.0.3
- Trying to fix issue with osx-defaults somehow corrupting the
System Settingsapp.
2.0.2
- [.shellrc] Exposed a new function
is_armto denote whether the current machine architecture is ARM. - [post-brew-install.sh] Will cleanup the
keybaseexecutables from the/usr/local/binfolder if they are present.
2.0.1
- [Brewfile] Added Picocrypt.
2.0.0
- Squashed all commits into a single commit.
- Tested on a fresh vanilla macos (15.5) machine.
1.1-23
- [Brewfile] Removed unused apps, moved commented out lines towards the bottom of the file.
1.1-22
- [Brewfile] Fix issue with vscode not being in PATH when running
bupccommand.
1.1-21
- [Brewfile] Replace AppCleaner with PearCleaner, and KeepingYouAwake with an extension to Raycast (Coffee).
1.1-20
- [Brewfile] Trial to check if returning
0will make the fresh installation script continue without needing to be rerun. - Minor tweaks to fix the gitignore for profiles repo.
- [.aliases] Renamed alias
code-gisttoedit-gistto make it more generic. - Handle setting up of Zed and Zed-Preview for cli access (if installed).
Adopting these changes
-
Rebase from upstream, resolve conflicts, and then proceed with the following steps:
cp "${HOME}/.dotfiles/files/--PERSONAL_PROFILES_DIR--/custom.gitignore" "${PERSONAL_PROFILES_DIR}/.gitignore" install-dotfiles.rb -
Quit and restart the Terminal application.
1.1-19
- Moved a lot of the shell functions from
${ZDOTDIR}/.aliasesinto individual files in${XDG_CONFIG_HOME}/zsh/so that they can be autoloaded/lazy-loaded on-demand. (Theoretically, this should improve shell startup time)
Adopting these changes
-
Rebase from upstream, resolve conflicts, and then proceed with the following steps:
cp "${HOME}/.dotfiles/files/--HOME--/custom.gitignore" "${HOME}/.gitignore" install-dotfiles.rb -
Quit and restart the Terminal application.
1.1-18
- [Brewfile] Ice is not installed on MacOS < 14, added KnockKnock.
- [fresh-install-of-osx.sh] Use natsumi-browser in Firefox profile (similar to Zen profile).
- [.gitignore_global] Regenerate from https://gitignore.io with more options.
- Major refactoring for ruby scripts to optimize for time and use of ruby idioms.
- [.zlogin] Optimize recompiling of zsh shell scripts.
1.1-17
- [software-updates-cron.sh] Removed parallelism (something that was introduced in the previous version when optimzing using gemini) - since this was causing lots of confusion when looking through the logs.
- [gitconfig] Removed
editorconfig setting since that’s already being governed by the env varEDITORset from~/.zshrc. - [Brewfile] Removed unused tools / added new tools.
- [capture-prefs-domains.txt] Added entries to capture PdfGear, TinkerTool, UTM.
- Removed partial line comments from the other config data files since they are inconsistent/might cause issues when parsing / applying them during the cleanup steps.
1.1-16
- Ran gemini to optimize the shell configuration scripts aimed at optimizing the shell startup time.
- Renamed ‘scripts/capture-defaults.sh’ to ‘scripts/capture-prefs.sh’
- Extracted ‘setup_login_item’ function from
${ZDOTDIR}/.aliasesinto a standalone script so as to avoid issues between bash vs zsh when runningpostinstallstep in Brewfile. - [capture-prefs.sh] Extracted the whitelist of preferences into a separate file: capture-prefs-domains.txt.
- [cleanup-browser-profiles.sh] Extracted the whitelist of files and directories that needs to be cleaned into separate files.
Note: This version has been successfully tested on a Macbook M1 on 2 May, 2025.
1.1-15
- Added config settings file for
miseto handleidiomatic_version_file_enable_tools
1.1-14
- [shellrc] Introduced new
is_zshfunction for defensively loading${ZDOTDIR}/.aliaseswhen runningbrewinstall/update commands (which runsbashshell)
1.1-13
- [Brewfile] Removed deprecated vscode plugins.
- [software-updates-cron.sh] Fix issue with BetterFox user.js not being put in correct Firefox profile; Added BetterZen’s user.js into Zen profile.
1.1-12
- [fresh-install-of-osx.sh] Set PATH even if dotfiles repo is present - so that future scripts can be invoked without issues.
- [Brewfile] Cleaned up some softwares that I rarely use.
- [.tcshrc] Removed empty file
1.1-11
- [.gitconfig] Minor changes to decorate git log.
- [.aliases] Added
upreb_meshell script that will intelligently run a shell script (if present) for the current folder or fall back to the globalgit uprebalias - [.npmrc] Set some npm configurations to hide progress bar and save the exact version into the BOM file.
1.1-10
- [.shellrc] Removed ‘depth’ option while cloning repos since that causes rebases from the upstream repo to get corrupted.
- [.gitconfig] Added some options recommended from the core git maintainers.
1.1-9
- Moved setting up of login items into the
Brewfileso that can be managed along with the cask block itself.
1.1-8
- Minor cleanup (removed leftover references to Arc).
1.1-7
- [software-updates-cron.sh] Added more steps/commands to be run via a cron job.
1.1-6
- Minor refactoring to reuse utilize utility methods defined in
.shellrc.
1.1-5
- [.cshrc] Removed empty file
- [.shellrc] Re-aligned colors for the success, warn, debug and error functions
1.1-4
- Simplify color output for scripts (avoid nesting) within the same line.
1.1-3
- [.aliases]
install_mise_versionsnow handles config files from more language-version-managers. - [fresh-install-of-osx.sh] Removed duplicate function defn:
build_keybase_repo_url. - [fresh-install-of-osx.sh] Moved some post-install steps into a new script which is invoked from the Brewfile’s
at_exitblock. - [software-updates-cron.sh] Corrected defensive checking of installed software before running some update commands.
1.1-2
- Moved
setup_login_itemfunction into theBrewfilesince its used after app-installations.
1.1-1
- [Brewfile] Replaced
libreofficewithonlyoffice. - [.aliases] Fixed issue with
start_dockerandstop_docker.
1.0-53
- [Brewfile] Added
rsyncto be used from homebrew so as to avoid the recently announced RCE vulnerability. - Changed the
DOTFILES_DIRenv var to use${HOME}/.dotfilesinstead of${HOME}/.bin-oss.
Adopting these changes
-
Rebase from upstream, resolve conflicts, and then proceed with the following steps:
cp "${HOME}/.bin-oss/files/--HOME--/custom.gitignore" "${HOME}/.gitignore" mv "${HOME}/.bin-oss" "${HOME}/.dotfiles" source "${HOME}/.shellrc" install-dotfiles.rb -
Quit and restart the Terminal application.
1.0-52
- Removed auto-configuration from rancher desktop to not manage/change the
PATHenv var since that’s already done in this line of the .zshrc file.
Adopting these changes
- Start rancher desktop, go into its preferences, and change the setting to not automatically set the
PATH. - Restart Terminal app and verify that
dockeris in yourPATH.
1.0-51
- [.aliases] Uncommented
start_dockerandstop_dockerand made them defensive. - Removed ‘ccleaner’ preferences since I am no longer using it.
1.0-50
- All Firefox-based browsers are now handled for their respective
chromefolders to be tracked and get updated as git repos. - [.aliases] Added utility functions for
pullandpushsimilar tost,count, etc taking in an optional git repo. - [.shellrc] Moved a utility function (
set_ssh_folder_permissions) so that it can be reused.
Adopting these changes
- After rebasing, just quit and restart the terminal emulator so that the
.envrcis processed. (Hint: Useallow_all_direnv_configsto accept and process all.envrcfiles in your system.)
1.0-49
- [capture-raycast-configs.sh] Automated initial password setup for Raycast export.
1.0-48
- [.shellrc] Extract common functions
strip_trailing_slashandextract_last_segment. - Use
unsetto jettison local variables once they are no longer needed.
Adopting these changes
- After rebasing, just quit and restart the terminal emulator so that the
.shellrcis loaded into memory.
1.0-47
- [capture-defaults.sh] Added more macos preferences to be exported/imported for backup.
- Removed
Itsycalsince raycast and/or a desktop widget can be used instead of a dedicated application.
1.0-46
- Removed duplication (now
scripts/resurrect-repositories.rbinvokes the common function defined in the.shellrc). - Removed usage of
evalto simplify running of shell commands.
Adopting these changes
- After rebasing, just quit and restart the terminal emulator so that the
.shellrcis loaded into memory.
1.0-45
- [capture-raycast-configs.sh] Added script to export/import raycast configs. More details can be found here. Code contributed by/adapted from @arunvelsriram’s gist.
- Reuse utility functions defined in
.shellrc
1.0-44
- [recreate-repo.sh] Fix an issue where a trailing slash would not properly process the repo in
${PERSONAL_PROFILES_DIR}(ie would not force-squash) - Cleaned
files/--PERSONAL_PROFILES_DIR--/custom.gitignore
Adopting these changes
-
After rebasing, run the following command prior to running the
install-dotfiles.rbscript.cp "${DOTFILES_DIR}/files/--PERSONAL_PROFILES_DIR--/custom.gitignore" "${PERSONAL_PROFILES_DIR}/.gitignore"
1.0-43
- Nested all Firefox-based profiles one level deeper.
Adopting these changes
These changes are optional, but if you don’t follow them, then the aliases/scripts pertaining to the browser profiles repo can be messed up..
- Quit any FF-based browser before rebasing from my repo.
- Run
git -C "${DOTFILES_DIR}" upreb - Resolve all conflicts.
- Open Finder on the
${PERSONAL_PROFILES_DIR}/ - Inside each of the FF-based profiles folders, create a new folder called
DefaultProfileand move all other sibling files/folders into that one. - Edit the
profiles.iniandinstalls.inifiles at the root of the FF profile folder, and add/DefaultProfileto the lines referring to the profile folder (usually it’ll be a relative path). - Restart your FF-based browser to verify that all functionality continues to work.
1.0-42
- Added dev dependencies for zen-browser.
- Unignore some files from the
personalfolder that were somehow ignored globally.
1.0-41
- Added new script
scripts/add-upstream-git-config.sh.
1.0-40
- Fixed documentation and reduced hardcoding of upstream repo-owner’s name.
1.0-39
- Introduced a new script to cleanup browser profiles folders.
- [fresh-install-of-osx.sh] Minor refactoring to enhance
clone_repo_intoto handle an optional target git branch which is also validated.
1.0-38
- [.aliases] Added extra checks for the
status_all_reposandcount_all_reposutility functions.
1.0-37
- Removed
Raycastfrom being tracked via the profiles repo since that corrupts Raycast’s internal db.
Adopting these changes
These instructions are only necessary if you had previously adopted changes from v1.0-24
- In Raycast, use the
Export Settings & Dataoption to export your current settings. - After successfully exporting the settings, quit Raycast and ensure that Raycast is completely shut down.
- Rebase the dotfiles repo, fix any conflicts and run the
install-dotfiles.rbscript. - Manually reconcile the diffs / dirty state of
files/--PERSONAL_PROFILES_DIR--/custom.gitignorewith$PERSONAL_PROFILES_DIR/.gitignoreon your local machine -
Run the following commands in the terminal
git -C "${DOTFILES_DIR}" restore files/--PERSONAL_PROFILES_DIR--/custom.gitignore cp "${DOTFILES_DIR}/files/--PERSONAL_PROFILES_DIR--/custom.gitignore" "${PERSONAL_PROFILES_DIR}/.gitignore" rm -rf "${HOME}/Library/Application Support/com.raycast.macos" mv "${PERSONAL_PROFILES_DIR}/Raycast" "${HOME}/Library/Application Support/com.raycast.macos" git -C "${PERSONAL_PROFILES_DIR}" rm -rf Raycast open /Applications/Raycast.app - Once Raycast is restarted AND if it shows an error about the database being corrupt, then choose the
Resetoption, and use theImport Settings & Dataoption to import your previously exported settings back in. - Once the above steps are done, if you rerun the
install-dotfiles.rbscript, it should not show any dirty files (especially the 2custom.gitignorefiles) - and if this is the case, your setup is now back to normal working state.
1.0-36
- Use
is_git_repoinstead ofis_directoryif the next command(s) expects it to be a git repo. - Remove Arc from
Brewfile(since I moved to Zen).
1.0-35
- Use
git-restore-mtimefromgit-tools(as opposed togit-utimesfromgit-extras) since its > 1x faster performance.
1.0-34
- Set the DNS server to ‘8.8.8.8’ only if running in a Jio network.
- Introduce PDFGear and KeyClu.
- Fixed some old documentation.
1.0-33
- Reuse utility functions defined in
.shellrc.
1.0-32
- [fresh-install-of-osx.sh] Added date calculation in
fresh-install-of-osx.shto track total execution time.
1.0-31
- [approve-fingerprint-sudo.sh] Handled case to execute
approve-fingerprint-sudo.shbased on touchId hardware.
1.0-30
- [resurrect-repositories.rb] Handled the case where git wouldn’t allow cloning a repo into a pre-existing, non-empty folder.
- [.zshrc] Handled case where docker-related aliases were not setup since it was not in the
PATHwhenfiles/--HOME--/.aliaseswas evaluated.
1.0-29
- [capture-defaults.sh] Removed some applications that I no longer use.
- [fresh-install-of-osx.sh] Replaced
TODOwith explanation for future reference as to why we can’t usehomebrewto install omz custom plugins.
1.0-28
- [Brewfile] Stop processing the
Brewfilesuch that the minimal installation can happen in a shorter duration of time. This is controlled by the env varHOMEBREW_BASE_INSTALLwhich is set in thefresh-install-of-osx.shscript when installing from scratch.
1.0-27
- [.aliases] Added 2 new utility functions:
countandcount_all_repos
1.0-26
- Merged
fresh-install-of-osx-advanced.shintofresh-install-of-osx.shto reduce complexity of loading different config files into the shell session. - [.gitconfig] Remove git sub-command
currentDirin favor of root. - [Brewfile] Remove
git-toolssincegit-extrashas an equivalent git sub-command. - [.gitignore_global] Generate from gitignore.io for common languages, OSes and editors.
- [fresh-install-of-osx.sh] Minimize use of
evaland sub-shells. - [fresh-install-of-osx.sh] Moved utility scripts (from
files/--HOME--/.aliases) that are only loaded while running thefresh-install-of-osx.shinto that single script to optimize shell startup time. - [fresh-install-of-osx.sh] Removed cloning of
natsumi-browserfrom.envrcand moved into fresh-install script. Updating the repo is now handled as part ofscripts/software-updates-cron.sh. - [.zshrc] Removed
zsh-defersince that was introducing more complexity in maintenance. - [.shellrc] Use
mktempto enhance implementation ofclone_repo_intowhich reduces need to process the home-repo in a special manner while doing a fresh install. - [.shellrc] Moved homebrew env vars from
files/--HOME--/.zshenvintofiles/--HOME--/.shellrc. - Merged
files/--HOME--/.zshrc.customintofiles/--HOME--/.zshrcandfiles/--HOME--/.aliases.customintofiles/--HOME--/.aliasesto reduce complexity of loading different config files into the shell session.
Adopting these changes
- After rebasing and resolving the conflicts
- Manually reconcile the diffs between
files/--HOME--/custom.gitignore&${HOME}/.gitignore, andfiles/--PERSONAL_PROFILES_DIR--/custom.gitignore&${PERSONAL_PROFILES_DIR}/.gitignore. -
Open the Terminal application and run the following commands:
rm -rf ${HOME}/.aliases.custom ${HOME}/.zshrc.custom ${HOME}/.oh-my-zsh/custom/plugins/zsh-defer cp files/--HOME--/custom.gitignore ${HOME}/.gitignore cp files/--PERSONAL_PROFILES_DIR--/custom.gitignore ${PERSONAL_PROFILES_DIR}/.gitignore install-dotfiles.rb - Quit and restart your Terminal application for the env vars, aliases & functions to be re-evaluated into the session memory.
- Run
bupcto cleanup brews and casks.
Note: This version has been successfully tested on a Macbook M1 on 22 Dec, 2024.
1.0-25
- [capture-defaults.sh] Capture defaults script now aborts when the
PERSONAL_CONFIGS_DIRenv var is not defined. - [.shellrc] Extracted common utility function to remove duplication and invoke them in the setup scripts.
- [fresh-install-of-osx-advanced.sh] Fixed potential issue with the
PATHnot being updated if the fresh-install-advanced script was run without starting a new terminal session. - [.aliases] Added a new
profilesalias to handle git repos checked out into thePERSONAL_PROFILES_DIR.
1.0-24
- Capture the Raycast configs/extensions/etc in the profiles repo
Adopting these changes
- Open Terminal and run the
install-dotfiles.rbscript. - Change the current directory in terminal to the profiles repo (
direnvwill take care of the rest)
1.0-23
- Incorporate the natsumi-browser into the Zen browser profile.
1.0-22
- [.shellrc] Moved functions that are only needed in the basic fresh-install script into that so as to reduce shell startup time.
Note: This version has been successfully tested on a Macbook M1 on 19 Dec, 2024.
1.0-21
- [fresh-install-of-osx-advanced.sh] Nested conditions and print more specific warning message when skipping cloning of the home and profiles repos.
- [.shellrc] Extracted some utility functions to remove duplication and invoke them in the setup scripts.
Adopting these changes
- Manually edit your
${HOME}/.ssh/configfile, and change all occurrences of~to${HOME}
1.0-20
- Removed necessity of quitting and restarting the Terminal application between executing the
fresh-install-of-osx.shandfresh-install-of-osx-advanced.sh. - [.shellrc] Extracted some utility functions to remove duplication and invoke them in the setup scripts.
- [.shellrc] Renamed
ensure_dir_exists_if_var_definedintoensure_dir_existsandclone_if_not_presentintoclone_omz_plugin_if_not_present. - [Brewfile] Removed
gs,wifi-passwordandvirtualbox.
Note: This version has been successfully tested on a Macbook M1 on 16 Dec, 2024.
Adopting these changes
- Run
git delete-tag success-tested-on-m1; git push origin :success-tested-on-m1to cleanup the defunct tag.
1.0-19
- [Brewfile] Added
keycastrto help with pairing and presentations of screen-grabs. - Added some more logging while running the fresh-install scripts.
1.0-18
- Restructured
Brewfileto convey what are bare minimum formulae vs recommended vs optional ie left to the user’s choice.
Adopting these changes
- The reason for this restructuring is explained up above. Since most of the adoptees have customized this file, it will probably result in conflicts. Please be diligent in resolving the conflicts.
1.0-17
- All GH urls now also take into account the branch that’s being tested for the setup scripts. Read the new section in the README if you are making changes that you want to test against a PR branch before the PR is merged.
1.0-16
- Moved some of the core zsh config files from
files/--HOME--/tofiles/--ZDOTDIR--/to accommodate custom location ofZDOTDIR. - [.shellrc] Merged all relevant lines from
files/--ZDOTDIR--/.zprofileintofiles/--HOME--/.shellrcand deletedfiles/--ZDOTDIR--/.zprofilesince that is the first file loaded during the fresh machine setup. This also avoids the defensive definition ofZDOTDIRin duplicate files.
Adopting these changes
- After rebasing, you will end up with conflicts. The env vars that were previously defined in
files/--ZDOTDIR--/.zprofilehave been moved intofiles/--HOME--/.shellrc. You might have to manually fix them. You can go ahead and delete the${HOME}/.zprofilesince that is no longer needed. - Run
install-dotfiles.rbso that the symlinked zsh config files in${HOME}point to the correct locations (files/--ZDOTDIR--/instead offiles/--HOME--/)
1.0-15
- [README.md] Fixed some grammatical errors in README.
- [.gitconfig] Added new git alias for logs.
1.0-14
- Use ‘zsh-defer’ to try to bring down shell startup time.
Adopting these changes
- Run
fresh-install-of-osx.shso that thezsh-deferplugin is cloned to the correct directory. - Restart terminal for the deferred-loading to take effect. (No harm in keeping the old session).
1.0-13
- [.shellrc] Introduced new utility functions
section_headeranddebugand standardized on usages.
1.0-12
-
Reverted changes from v1.0.9 related to ‘bupc’ since the 1st cleanup might be skipped due to the ‘ ’ condition status
1.0-11
- Converted from ‘iBar’ menubar app to ‘Ice’ since its open source and seems to have better features. This also removes the need to login into the App Store!
1.0-10
- Fix zsh auto-completion since some of the options were set after the
compinitinvocation - [.zprofile] Ensure that directories are created for env vars defined in
.zprofile setoptparamters are case-insensitive and can handle underscore and so changed them for readability- [.shellrc] Introduced new utility function
ensure_dir_exists_if_var_definedto help in cases wherecode-gistused to create unsaved files instead of directories for undefined env vars
1.0-9
- Remove redundant cleanup in ‘bupc’
- Removed MS Teams and MS Remote Desktop
Adopting these changes
- Restart terminal for the revised alias function to get loaded. (No harm in keeping the old session; just that it will perform an extra step unnecessarily on
bupcalias)
1.0-7
- [fresh-install-of-osx.sh] Fix issue when running in a fresh/vanilla machine since ‘ZDOTDIR’ was undefined.
1.0-6
- [install-dotfiles.rb] Fix issue when creating the include line for
~/.ssh/configif it was not present.
1.0-5
- [approve-fingerprint-sudo.sh] Persists authorization config for triggering touchId when running sudo commands in terminal across software updates.
Adopting these changes
- Run
approve-fingerprint-sudo.sh
1.0-4
- [install-dotfiles.rb] Refactored environment variable resolution logic to use
gsub!for improved performance.
1.0-3
- Moved all files & nested folders inside the
filesdirectory intofiles/--HOME--to make that location explicit (earlier it was implied)
1.0-2
- [install-dotfiles.rb] Refactored the logic to handle ssh global configuration file for ease of readability and maintainability.
1.0-1
- [Brewfile] Added
virtualboxto test out linux as a Virtual machine. - [CHANGELOG.md] Added changelog which will be maintained going forward for each commit.
- [README.md] Added a new section detailing steps to adopt updates/catchups for new changes on an ongoing basis.
- Changed all colored messages to be uniform and added a
successfunction to print in green. These are optimized for a dark theme in your terminal emulator.
1.0
install-dotfiles.rbcan now handle multiple env vars for nested files/folders in thefilessub-folder. They follow the naming convention of the env var being enclosed within 2 pairs of hyphens (--). For eg,files/--PERSONAL_PROFILES_DIR--/.envrcwill be symlinked on your local machine into${HOME}/personal/<yourLocalUsername>/profiles/.envrcassuming that thePERSONAL_PROFILES_DIRenv var has been defined. This is not a breaking change.
Adopting these changes
- Since I recreated the
1.0tag as part of this push, you might need to delete the tag in both your local and your remote and then dogit upreb. - Run the
install-dotfiles.rbscript which will automatically remove the older (broken) symlink and recreate the new one in the correct location.