dotfiles を chezmoi で管理し始めて約 4 ヶ月半になります。リポジトリの commit 数は 156、直近 2 ヶ月は月 30〜65 commits のペースで、ほぼ毎日なにかしら手を入れています。
TL;DR:
- dotfiles が「たまに直すもの」から「毎日触るもの」に変わった
- 変わった理由は 2 つ。Claude Code に現構成を見せて「今ならどうする?」と聞く習慣と、複数マシン運用で push / pull が日常動作になったこと
- 副産物として、ツールやエコシステムのキャッチアップが進む
日々整備が続いている理由は 2 つ
1 つめはマシンの数です。WSL と Mac 2 台(私用・会社)の計 3 環境を同じ chezmoi ソースから apply しています。全マシンのセットアップを終えると、どこかで直した設定を別のマシンで pull する、という動作が毎日発生します。pull する流れで気になったところを直して push する。この往復が習慣の土台になった気がします。
2 つめは Claude Code です。設定ファイルを開いて「この構成、今ならどうするのがモダン?」と聞くと、改善ネタが尽きません。提案された変更をその場で適用して、chezmoi diff で確認して commit する。1 回の会話が 1〜数 commits になります。
この 2 つが揃った結果が、冒頭の commit ペースです。
整備ループの実例
「聞く → 直す → commit → 別マシンで pull」のループを、規模の違う 3 つの例で紹介します。
一気に入れる: modern unix CLI 一式
「ターミナル周りで今どきの定番ツールを揃えたい」と聞いて、いわゆる modern unix 系の CLI を一気に導入しました。mise の config には今もこのときのセクションがそのまま残っています。
# modern unix
ripgrep = "latest"
fd = "latest"
bat = "latest"
eza = "latest"
fzf = "latest"
zoxide = "latest"
jq = "latest"
yq = "latest"このとき良かったのは、ツールを入れるだけで終わらず alias や pager の設定まで会話で進んだことです。ls / tree を eza の alias に、MANPAGER を bat に、fzf の検索ソースを fd に、git の pager を delta に。さらに push.autoSetupRemote や rerere といった modern git defaults まで、1 つの流れでまとめて入りました。
役割分担を聞く: brew か mise か
パッケージをどこで管理するかは何度か引っ越しました。最初は Homebrew に寄せていました。その後 Claude に相談したら「単体バイナリで完結する CLI は mise の方が向いている」という整理を提案され、納得して brew → mise に移しました。chezmoi の external 機能で入れていたツールも mise に寄せました。
このとき出会った tealdeer や btop の罠は、config のコメントとして残しています。
# dbrgn/tealdeer ships only completions/licenses on GitHub releases, no binaries.
"cargo:tealdeer" = "latest"{{- /* aqua's btop registry only ships linux/amd64 binaries; mac uses brew. */}}
{{- if eq .chezmoi.os "linux" }}
btop = "latest"
{{- end }}次に同じところで悩んだとき、コメントを読めば(自分も Claude も)同じ失敗を繰り返さずに済むはずです。
細かく直す: 気になったその日に 1 commit
大きな導入だけでなく、日々の小さな引っかかりもその日のうちに直します。
- atuin の履歴検索で、選択した瞬間にコマンドまで実行されるのが怖かったので、プロンプトに戻すだけに変更(
enter_accept = false) - シェル起動のたびに 1Password の認証が走って煩わしかったので、secret の読み出しを
op injectでバッチ化し、結果をディスクにキャッシュして Touch ID を 8 時間に 1 回へ
どれも単体では数行の変更ですが、「気になる → 聞く → 直る」のサイクルが短いので、引っかかりを放置しなくなりました。
副産物として、キャッチアップが勝手に進む気がします。mise のバックエンドの仕組み、op inject という CLI の使い方、chezmoi の run_onchange スクリプト、modern git defaults。どれも自分から調べに行ったというより、整備の会話の中で「そういうのがあるのか」と知ったものです。
構成のポイント
chezmoi のテクニック自体は、作者の twpayne/dotfiles と公式ドキュメントを参考にしました。自分の構成から、複数マシン運用で効いているところだけ紹介します。
ソースリポジトリの構造は、ここで触れるものだけ抜き出すとこの形です。
~/.local/share/chezmoi/ # リポジトリ (.chezmoiroot で home/ に寄せている)
└── home/
├── .chezmoi.toml.tmpl # マシン属性の自動判定
├── .chezmoiignore # マシンごとの配布制御
├── .chezmoiscripts/ # run_onchange_after_mise-install.sh.tmpl など
├── dot_Brewfile.tmpl # → ~/.Brewfile
├── dot_claude/ # → ~/.claude
├── private_dot_config/ # → ~/.config (fish / mise / git / atuin ...)
└── windows/ # WSL 用 (Windows Terminal 設定)マシン属性の自動判定
3 環境を 1 ソースで扱うため、.chezmoi.toml.tmpl でマシン属性(会社マシンか、WSL か、headless か)を hostname や環境変数から自動判定しています。会社マシンの判定に使う hostname の正規表現は環境変数経由で渡して、パターン自体はリポジトリに残しません。
{{- /* Work hostname: regex supplied via env to keep pattern out of the repo */ -}}
{{- $work_regex := env "CHEZMOI_WORK_HOSTNAME_REGEX" -}}
{{- if $work_regex -}}
{{- if regexMatch $work_regex .chezmoi.hostname -}}
{{- $work = true -}}
{{- end -}}
{{- end -}}判定した属性は、テンプレートの分岐や .chezmoiignore での配布制御に使います。会社マシンにだけ証明書設定を配る、私用マシンにだけ特定の env を配る、といった出し分けがここで決まります。
Brewfile を single source of truth に
Mac のパッケージは Brewfile を唯一の正として、chezmoi apply のたびに run_onchange スクリプトで同期しています。
brew bundle— Brewfile にあるものをインストールbrew bundle cleanup --force— Brewfile にないものをアンインストール
手で brew install したものは、Brewfile に書かない限り次の apply で消えます。破壊的ですが、おかげで「リポジトリに書いてあるものがすべて」という状態が保たれて、マシン間の差分に悩まなくなりました。
課題
環境セットアップに凝ってしまうことです。Claude に聞けば改善ネタはいくらでも出てくるので、気づくと dotfiles をいじること自体が目的になってきます。月 30〜65 commits という数字も、裏返せばそれだけの時間を環境整備に使っているということです。開発環境はあくまで開発のためのものなので、ほどほどにするべきだと思っています(自戒)。
やってみたい人へ
導入手順は公式ドキュメントが丁寧なので、そちらを見るのが早いです。構成の実例は twpayne/dotfiles が参考になります。
最初から全部を管理しようとしなくても、1 ファイルを chezmoi add するところから始められます。あとは気になったら Claude へ「この構成、今ならどうする?」と聞く。自分の場合はこのやり方で 4 ヶ月半続いています。