GuideSeptember 15, 20267 min read

Automating Everything: Hooks + Bootstrap + Watch Mode Together

Watch mode detects changes. Pre-push hooks capture dependencies. Post-pull hooks install packages. Bootstrap handles first-time setup. Together, they create a self-maintaining development environment.

Three Features, One Workflow

ConfigSync has three automation features that each solve a different problem. Used individually, they are convenient. Combined, they create something transformative: a development environment that maintains itself across every machine you own.

Watch mode monitors your config files and pushes automatically when they change. Hooks run commands before and after push/pull operations.Bootstrap scripts handle first-time machine setup. Here is how to wire them all together.

The Complete Chain Reaction

You edit ~/.zshrc on your work laptop. Here is what happens automatically:

The automated flow
# You save ~/.zshrc. Everything below happens automatically: # 1. Watch mode detects the change [watch] Changed: ~/.zshrc → triggering push # 2. Pre-push hooks capture current dependencies [pre_push] code --list-extensions > ~/.config/vscode-extensions.txt [pre_push] brew bundle dump --file=~/.Brewfile --force # 3. Push uploads changed configs + captured dependency lists [push] 3 files changed → uploading # 4. On your home machine (next pull): [pull] Applying 3 updated files [post_pull] brew bundle install --file=~/.Brewfile --no-lock [post_pull] Installing 2 new VS Code extensions [post_pull] source ~/.zshrc # 5. On a brand-new machine (first pull): [bootstrap] Installing Homebrew... [bootstrap] Installing oh-my-zsh... [pull] Applying full configuration [post_pull] brew bundle install (47 packages) [post_pull] Installing 23 VS Code extensions

You edited one file. The dependencies were captured, the push happened, and every other machine got the update along with any new packages.

The Configuration

Here is the complete config.yaml that powers this workflow:

~/.configsync/config.yaml
watch: enabled: true filter: - "~/.zshrc" - "~/.gitconfig" - "~/.config/starship.toml" - "~/.config/vscode/settings.json" debounce: 5 hooks: pre_push: - "code --list-extensions > ~/.config/vscode-extensions.txt" - "brew bundle dump --file=~/.Brewfile --force" - "pip freeze > ~/.config/pip-packages.txt" post_pull: - "brew bundle install --file=~/.Brewfile --no-lock 2>/dev/null || true" - "cat ~/.config/vscode-extensions.txt | xargs -L 1 code --install-extension 2>/dev/null || true" - "source ~/.zshrc 2>/dev/null || true" bootstrap: - name: "Homebrew" command: '/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"' detect: "command -v brew" - name: "oh-my-zsh" command: 'sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" "" --unattended' detect: "test -d ~/.oh-my-zsh" - name: "Starship prompt" command: "brew install starship" detect: "command -v starship"

How Watch Mode Triggers the Chain

Watch mode is the entry point. Start it in the background and forget about it:

Starting watch mode
# Run in the background configsync watch & # Or in a dedicated terminal with verbose output configsync watch --verbose

The debounce setting is important. When you are actively editing a file, watch mode waits for 5 seconds of inactivity after the last save before triggering a push. This prevents rapid-fire pushes during an editing session while still capturing changes promptly when you are done.

Watch filter matters: Only watch files you actively edit. Watching too many files adds overhead and creates unnecessary pushes. Your shell config, Git config, and editor settings are typically sufficient.

Hooks: Capture Before Push, Install After Pull

The key pattern is that pre-push hooks and post-pull hooks form pairs. Whatever you capture before pushing, you install after pulling:

The capture/install pattern
# Capture → Install pairs: # Homebrew: brew bundle dump → brew bundle install # VS Code: code --list-extensions → code --install-extension # pip: pip freeze → pip install -r # npm global: npm ls -g → npm install -g

Pre-push hooks capture the current state of package managers and tool inventories. Post-pull hooks take those captured lists and install anything missing. This keeps not just your configs in sync, but your entire tool set.

Bootstrap: The Foundation Layer

Bootstrap scripts handle what hooks cannot: installing the tools themselves. On a new machine, brew bundle install fails if Homebrew is not installed. Bootstrap runs before the first pull and sets up the prerequisites.

The detect field makes bootstrap idempotent. If Homebrew is already installed, that step is skipped. This means bootstrap is safe to run on existing machines — it only installs what is missing.

Think of it as three layers: bootstrap installs package managers, pull brings your configs and dependency lists, and post-pull hooks install your packages. Each layer builds on the previous one.

The Zero-Touch Result

Once configured, your development environment is fully automated. Edit a config and it propagates. Install a new VS Code extension and it appears on your other machines. Set up a brand-new laptop and everything installs itself. The initial 30-minute configuration investment pays off every single day.

Ready to try ConfigSync?

Sync your entire dev environment across machines in minutes. Free forever for up to 3 devices.