Skip to content

Repository files navigation

Dotfiles

My personal environment, managed with chezmoi. On a fresh machine chezmoi apply links every config, runs the one-time installs, generates machine-local bits, and installs public packages in one command on macOS, Linux, and Windows. The private secrets companion has a separate bootstrap.

Design principle

Do not add personal customization when a default or widely adopted standard already solves the problem. Prefer, in order:

  1. built-in/default behavior
  2. official or widely adopted integration/plugin
  3. minimal configuration
  4. custom scripts/keymaps only when the above are insufficient

Custom configuration should have a concrete reason to exist. Avoid duplicating a tool's defaults, introducing new keybindings without a clear benefit, or keeping integration layers that are no longer used.

The previous shell / bootstrap.sh version (symlink-based) is preserved at the pre-chezmoi git tag — restore with git checkout pre-chezmoi.

Quick start

macOS / Linux

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
if [ -x /opt/homebrew/bin/brew ]; then
  eval "$(/opt/homebrew/bin/brew shellenv)"
elif [ -x /home/linuxbrew/.linuxbrew/bin/brew ]; then
  eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
fi
brew install chezmoi
git clone <repo> ~/dotfiles

# one-time: generate ~/.config/chezmoi/chezmoi.toml — prompts once for your
# git name/email and derives sourceDir from where you cloned (~ is expanded)
chezmoi init --source ~/dotfiles

chezmoi apply

Windows (PowerShell)scaffolded, verify on a real machine

# Enable Windows Developer Mode first (required for the Neovim symlink).
winget install Git.Git twpayne.chezmoi
# clone, then `chezmoi init --source <path>` (prompts, writes chezmoi.toml), then:
chezmoi apply
  • Setup walkthrough — including secret handling (SSH keys, ~/.secrets, identity): SETUP.md
  • Tool and plugin review: RECOMMENDATIONS.md

How it works

The chezmoi source lives in chezmoi/ (a home-mirror tree). chezmoi apply turns it into your home directory:

chezmoi source becomes kind
dot_zshrc, dot_gitconfig, dot_tmux.conf, … ~/.zshrc, ~/.gitconfig, … managed file (copy)
private_dot_ssh/ ~/.ssh/ (0700) managed files; keys stay per-machine
dot_config/symlink_nvim.tmpl ~/.config/nvimnvim/lazy symlink
symlink_dot_hammerspoon.tmpl ~/.hammerspoonhammerspoon/ symlink
dot_claude/ selected files in ~/.claude/ managed files
run_once_* / run_onchange_* packages, TPM plugins, and mise runtimes scripts

Managed vs symlink: big, live-edited config directories (nvim/, hammerspoon/) stay as their own folders and are symlinked. Claude's runtime directory stays local while chezmoi manages only its public config files. Everything else is a managed file; edit with chezmoi edit --apply ~/.zshrc.

Layout

Folder What
chezmoi/ chezmoi source — managed dotfiles, OS-branched via .chezmoiignore.tmpl
nvim/ Neovim — lazy/ LazyVim → ~/.config/nvim
hammerspoon/ macOS automation — symlinked to ~/.hammerspoon
packages/ package manifests — Brewfile (macOS/Linux), casks (macOS), Scoop (Windows)
scripts/ tooling: key generation, workspace identity, and Windows installers
vim/ legacy Vim config snapshots (not linked; kept for reference)

Cross-platform

chezmoi/.chezmoiignore.tmpl branches by OS. Linux skips macOS-only AeroSpace, Hammerspoon, and casks. Windows uses AppData for Neovim, installs shared CLI tools with Scoop, and manages Git Bash startup files alongside a PowerShell 7 all-hosts profile. Terminal appearance remains host-specific. Windows is scaffolded and must still be verified on a real machine after the migration.

Secrets

Nothing private lives in this repo. chezmoi apply installs only the public config. The private secrets companion (real SSH hosts, nvim DB connections, ~/.pgpass) owns its own bootstrap — clone it and run its ./setup.sh; see that repo's README for the command. Public clones simply skip it. See SETUP.md.

Comments inside the config files are in Korean, but the configs themselves are language-agnostic — the setup works the same regardless.

Verify tmux local changes against upstream

  • Use this when you want to check whether dot_tmux.conf.local has drifted from upstream OMT defaults.
git diff --no-index --color=always \
  <(curl -fsSL 'https://raw.githubusercontent.com/gpakosz/.tmux/master/.tmux.conf.local') \
  chezmoi/dot_tmux.conf.local
  • If you only want to compare the currently applied file with upstream:
git diff --no-index --color=always \
  <(curl -fsSL 'https://raw.githubusercontent.com/gpakosz/.tmux/master/.tmux.conf.local') \
  ~/.tmux.conf.local
  • No output means the files match.

  • git diff --no-index exits with status 1 when differences are found, which is expected and does not indicate command failure.

  • If you want to force delta even when your shell decides to suppress pager output (eg. inside pipes), use:

git diff --no-index --color=always \
  <(curl -fsSL 'https://raw.githubusercontent.com/gpakosz/.tmux/master/.tmux.conf.local') \
  chezmoi/dot_tmux.conf.local \
  | delta
  • If you want a plain change summary only:
import urllib.request
import difflib

upstream_url = 'https://raw.githubusercontent.com/gpakosz/.tmux/master/.tmux.conf.local'
up = urllib.request.urlopen(upstream_url).read().decode().splitlines()
with open('chezmoi/dot_tmux.conf.local', 'r', encoding='utf-8') as f:
    local = f.read().splitlines()

diff_lines = list(difflib.unified_diff(up, local, lineterm=''))
print('added', sum(1 for l in diff_lines if l.startswith('+') and not l.startswith('+++')))
print('removed', sum(1 for l in diff_lines if l.startswith('-') and not l.startswith('---')))

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages