chezmoi から Pure Shell Script への移行:AIネイティブ時代のdotfiles管理
この記事は人間がAIを使って検索しつつ手書きし、AIと推敲したものになります
はじめに
chezmoi はdotfilesを管理するためのソフトウェア。複数マシンで設定を共有したり、テンプレート機能、パスワード管理アプリとの連携に強みがある。dotfilesに対しての変更のdiffやapplyのdry runを走らせられるなど便利な機能がたくさんある。
ところが、今回、chezmoi から移行することにした。 移行先は、Pure Shell Script。 理由はシンプルに、chezmoiがnot for meだった。
移行に至った背景などを書いていく。
chezmoiの学習コストがつらくなってきた
一般人は年一ぐらいでしか新しいMacを買ったりセットアップしない。つまり、dotfilesを使ってセットアップするのは年に一回程度。
年に一回しか使わないと何が起こるのかというと、dotfilesの構成について忘れてしまう。「chezmoi apply だっけ? chezmoi update だっけ?」「新しいファイルを追加するときは chezmoi add で...いや chezmoi managed で確認して...」毎回chezmoiの使い方について調べ直すのが面倒になってきた。
ただ単に、既存マシンの変更を反映させて新規マシンでkickするだけなのに、フレームワーク固有の知識を毎回思い出す必要があるのは本末転倒。
macOSしか使わないとchezmoiのテンプレート機能がtoo much
chezmoiのテンプレート機能とは、ファイル名に .tmpl 拡張子を付けるだけでテンプレートを作れる。テンプレート内では、環境や条件に応じて異なる内容を動的に生成できる強力な機能。
例えば、こんな感じで書ける:
{{ if eq .chezmoi.os "darwin" }}
# macOS specific config
{{ else if eq .chezmoi.os "linux" }}
# Linux specific config
{{ end }}
しかし、macOSしか使わない人にとっては必要なレイヤーが一つ増えるだけで気軽な変更ができなくなる。chezmoiのテンプレート記法を覚える必要があるし、マシンによって処理を切り替えることも少ないし、そもそもプレーンな設定ファイルをそのまま置けばいいだけなのに、なぜGoのテンプレート構文を覚えなければならないのか、と。
AIがあるから、Pure Shell Scriptへの移行が現実的に
LLMがここまで性能が上がる前の世界ならば、dotfilesも何かしらのフレームワークの形を借りて強力な機能を実現する必要性があった。シンボリックリンクの張り方、バックアップの取り方、べき等性の担保...これらを自前で実装するのは面倒でバグの温床だった。
しかし、AIが十分に発達したことでフレームワークがなくても必要最小限の機能ならば自前で実装するのが現実的になった。Shell力が乏しいのもあってchezmoiを使っていた部分もあったが、もはやAIに聞けば済む。
むしろ、AIの方が知識量は上で、「こういう実装もできるのか...」と人間がAI様に教えてもらうシーンも多々あった。例えば、シンボリックリンクの存在確認と同時にリンク先が正しいかどうかをチェックする書き方や、.DS_Store などのスキップ対象を case 文でまとめる書き方など、地味だけど堅牢な実装を提案してもらえた。
実際の実装:Pure Shell Scriptでのdotfiles管理
移行後の install.sh はこんな構成になっている。核となるのは link 関数:
link() {
local src="$1" dst="$2"
# Create parent directory
mkdir -p "$(dirname "$dst")"
# Skip if link already correct
if [[ -L "$dst" && "$(readlink "$dst")" == "$src" ]]; then
return 0
fi
# Backup existing file/link
if [[ -e "$dst" || -L "$dst" ]]; then
mv "$dst" "$dst.bak.$(date +%Y%m%d%H%M%S)"
warn "Backed up: $dst"
fi
ln -s "$src" "$dst"
log "Linked: $dst -> $src"
}
この関数がやっていることは単純:
- 親ディレクトリを作成
- 既に正しいリンクが張られていればスキップ(べき等性の担保)
- 既存のファイルやリンクがあればタイムスタンプ付きでバックアップ
- シンボリックリンクを作成
chezmoiが内部で行っていることと本質的には同じだが、シェルスクリプトなので何をしているかが一目瞭然。1年後に見ても理解できる。
ディレクトリ構成もシンプルにした:
dotfiles/ ├── home/ # ~/ 直下に配置するファイル │ ├── .zshrc │ ├── .zprofile │ ├── .Brewfile │ └── ... ├── .config/ # ~/.config/ に配置する設定 ├── .ssh/ # ~/.ssh/ に配置する設定 ├── .claude/ # Claude Code設定 ├── scripts/ # セットアップスクリプト群 └── install.sh # メインスクリプト
どのようにchezmoiからPure Shell Scriptへの移行を安全に行ったのか
AIに適当に投げるだけでは心配。そこで、安全な移行を完了するために、複数のAI系ツールを活用した。
まずは、Claude CodeのPlan modeで現場調査
Claude CodeのPlan Modeを活用して現状のコード調査と、複数のsub-agentsを立ち上げてのbest practice調査を行った。
Max Planの圧倒的コスパの前では現状これが一番いい...。複数のsub-agentsを立ち上げて簡易的なMAGIシステムみたいに多数決でbest practiceを決めてもらった。
Claude Codeは Pure Shell Script、chezmoi、GNU stow の3つを提案してきた。
やはり、chezmoiがBest Practiceに近いのか...。ただ、現状に不満があるので、GNU stowも見てみた。ところが、GNU stow程度なら現在のAIなら実装できてしまう...。しかも、追加でツールを覚える必要がある...。ということで、Pure Shell Scriptに実装方針を決定。
Claude Codeの作成したPlanを磨き込む
一旦、Claude CodeにPlanを作成してもらい、80%ぐらいは満足できるPlanだったので改善指令を出しつつ、Claude Codeにとって不明な点を質問させた。
具体的には以下のような点を詰めた:
- どのファイルをスキップ対象にするか(
.DS_Store、.git、エディタのスワップファイルなど) ~/.ssh/のパーミッション設定をどう扱うかLibrary/Application Support/配下のアプリ設定をどこまでdotfilesに含めるか- GitHub Actionsでのe2eテストをどう構成するか
複数のCodex CLIによる多重レビュー
98%ぐらいは満足できるPlanが完成したので、次はそのPlanをCodex CLIを複数立ち上げてReviewさせた。指摘事項が上がってきたらClaude Codeに修正させる、のループを複数回繰り返したら完成。
GPT-5.2 xHigh は現状の慎重さと賢さでは信用している。
実際に指摘された内容としては:
- シェルスクリプトの
set -euo pipefailを冒頭に入れるべき $HOMEと~の使い分けの統一[[ ]]と[ ]の使い分け(bash前提なら[[でOK)
こういった細かい点を複数のAIでクロスレビューすることで、人間が見落としがちな点を拾えた。
最後に実行
Claude Codeにさらに詳細なPlanを立てさせつつ、実行したら完了。詳細なプランを立てさせるのは大事で、Context Compactionを経ても以前行っていた物事を覚えさせるために必要。
移行後のメリット
実際に移行してみて感じたメリットをまとめる。
学習コストの削減: ./install.sh を実行するだけ。覚えることはこれだけ。
デバッグのしやすさ: 何か問題があれば bash -x install.sh でトレースできる。chezmoiの内部で何が起きているかを追う必要がない。
CIでのテスト: GitHub Actionsで macos-latest ランナーを使って実際にスクリプトを実行し、シンボリックリンクが正しく張られているかを検証できる。これもシェルスクリプトだからこそシンプルに書けた。
AIとの相性: 新しい設定を追加したいとき、AIに「この設定ファイルを ~/.config/xxx/ に配置したい」と言えば、既存のスクリプトを理解した上で適切な変更を提案してくれる。フレームワーク固有の知識が不要なので、AIも人間も理解しやすい。
ところで、Linux環境向けには...
一応、Ubuntuを入れたThinkpadちゃんも持っている。けど、セットアップする機会がそこまでないし、Dockerなどを使って使い捨ての環境を作りやすいので現状必要としていない...。必要になれば、dotfilesを更新する...。
ちなみに、今回作成したスクリプトはmacOS前提で書いているが、条件分岐を追加するだけでLinux対応も可能:
if [[ "$(uname)" == "Darwin" ]]; then # macOS specific elif [[ "$(uname)" == "Linux" ]]; then # Linux specific fi
chezmoiのテンプレート機能と本質的にやっていることは同じだが、Goのテンプレート構文ではなくシェルスクリプトなので、読める人が圧倒的に多い。
まとめ
chezmoiは優れたツール。複数OS、複数マシンを使いこなし、テンプレート機能を駆使してDRYに設定を管理したい人には最適。
しかし、macOS一筋で年一回しかセットアップしないような人にとっては、Pure Shell Scriptで十分。AIの発達により、かつては面倒だった「シェルスクリプトで堅牢なセットアップスクリプトを書く」という作業が、自然言語で指示するだけで完了するようになった。
フレームワークを使うかどうかは、結局のところ「そのフレームワークの学習コストと、得られるメリットのトレードオフ」で決まる。AIネイティブ時代において、シンプルな要件ならシンプルな実装で済む、という選択肢が現実的になった。
dotfilesリポジトリは以下で公開している: