コンテンツにスキップ

Mac 2台同期(MacBook Air + Mac mini)chezmoi dotfiles 設計書

作成: 2026-07-07 ステータス: 設計承認済み・実装待ち 実装セッションへ: このドキュメントだけで文脈なしに実装に入れるよう書いてある。不明点は推測せずユーザーに確認すること。

背景・目的

Mac mini を新規購入した。運用形態は以下のとおり。

  • MacBook Air: メインの入力マシン(タイピングの大半はこちら)
  • Mac mini: 常時稼働の自動化用 + 家でのサブ利用

開発環境(shell 設定・git 設定・Homebrew・Karabiner・macOS defaults 等)を「共通基盤は同期、マシン固有は分岐」の形で 2 台間で同期し、将来の再セットアップも 1 コマンドで再現可能にする。

受け入れ条件

  1. Air で .zshrc 等を変更 → push → mini で chezmoi update 一発で反映される(逆方向も同様)
  2. まっさらな Mac で chezmoi init --apply <repo> 相当の少数コマンドから、brew パッケージ・shell 設定・Karabiner・defaults まで再現できる
  3. マシン別の差分(mini に GUI cask を入れない等)が role 変数の分岐で表現されている
  4. シークレット・SSH 秘密鍵が dotfiles リポジトリに一切含まれない
  5. 同期のズレ(ローカル改変・リモート behind・brew 乖離)が毎日自動チェックされ、ズレがあれば macOS 通知が出る

方式: chezmoi

比較検討の結果 chezmoi を採用(bare git repo 案・symlink 案は、マシン別分岐・1Password 統合・差分チェックを全部自作する必要があり不採用)。

  • 原本(型紙): ~/.local/share/chezmoi/(git リポ。GitHub の private リポ yk0817/dotfiles に push)
  • 実体: chezmoi apply$HOME に生成(symlink ではなくファイル生成)
  • 導入: brew install chezmoi

マシン識別: role 変数(hostname 直参照は禁止)

初回 chezmoi init 時に promptString で role(air / mini)を 1 回だけ質問し、~/.config/chezmoi/chezmoi.toml に保存する。.chezmoi.toml.tmpl をリポジトリに置いて実現する。テンプレート分岐は {{ if eq .role "mini" }} で書く。hostname のリネームや 3 台目追加に強くするための抽象化。

現状把握(2026-07-07 時点の Air の実測)

  • .zshrc(約 2.7KB): LANG/HISTFILE、compinit + zstyle、peco 連携(Ctrl-R 履歴・Ctrl-U cdr・git branch 選択 lb・docker exec de)、alias(gcc_pssh_jaistcacda 関数)、PATH 追加(google-cloud-sdk、~/bin~/.local/bin/env(uv)、Rancher Desktop 管理ブロック、LM Studio ブロック)
  • .zprofile: brew shellenv のみ
  • .bashrc(265B)、.vimrc.gitconfig(user、insteadOf で https→ssh、fetch.prune)あり
  • Homebrew: formula 107 個、cask 6 個(1password-cli、ant、claude-code、drawio、gcloud-cli、rancher)、tap anthropics/tap、npm グローバル多数(brew bundle dump が npm/uv 行も出す)
  • Karabiner: ~/.config/karabiner/ あり
  • ~/.claude: 既に yk0817/claude-config で git 管理済み(dotfiles には混ぜない。mini ではクローンする)
  • シークレット: 1Password(op CLI)に集約済み
  • 注意: $HOME 直下にコミット 0 件・branch master の git リポが存在する(過去の残骸)。dotfiles 移行の完了後に撤去する(下記「後片付け」)

dotfiles リポジトリの中身

対象 管理方法
.zshrc .zprofile .bashrc .vimrc dot_zshrc.tmpl 等。role 分岐あり
.gitconfig dot_gitconfig(分岐不要ならテンプレートにしない)
Karabiner ~/.config/karabiner/karabiner.json のみ管理(Karabiner が自動生成するバックアップ類は対象外。diff ノイズ防止)
Brewfile Brewfile.tmpl を 1 ファイル。共通 CLI は両 role、GUI cask(drawio、rancher 等)や重い GUI は air のみ、のように分岐。mini に必要な常時稼働系(temporal 等)は mini 側にも
brew bundle 実行 run_onchange_before_brew-bundle.sh.tmpl(Brewfile のハッシュをコメントに埋めて、変更時のみ brew bundle --file を再実行する chezmoi 定石パターン)
macOS defaults run_onchange_darwin-defaults.sh.tmpl(キーリピート速度等。現行 Mac の実値を defaults read で拾って初期値にする)
sync-check sync-check.sh 本体 + launchd plist(下記)
.chezmoi.toml.tmpl role の promptString
README 新マシン bootstrap 手順・日常運用(chezmoi edit に統一)を記載

同期対象にしないもの

  • SSH 秘密鍵(1Password SSH Agent に移行。下記)
  • .zsh_history(マシンローカル)
  • gh / gcloud / op の認証状態(各マシンで一度ログイン)
  • プロジェクトリポジトリ本体(mini には自動化系のみ手動クローン: temporal-workflows、research-orchestrator、st-japan-lab、ai-engineering-digest 等、必要になったもの)
  • ~/.claude(claude-config として別管理継続)

よく使う CLI / MCP の棚卸し(2026-07-07 Air 実測)

Brewfile.tmpl の中身を推測しないための実測リスト。role 分岐の目安付き。line 41 の cask 一覧のうち claude-code は下記の移行で無効化する。

Homebrew formula(共通 = 両 role)

CLI 用途 mini も必要か
git / gh バージョン管理・GitHub
chezmoi dotfiles 同期(この仕組み自体)
gitleaks commit 前シークレット検知(hook)
op(1password-cli) シークレット取得・op run
go zotero-cli / personal-finance のビルド ✅(zotero 使うなら)
temporal Temporal CLI ✅(mini=常時稼働の自動化)
peco .zshrc の Ctrl-R / cdr / lb / de 連携 ✅(無いと .zshrc が動かない)
ghostscript / poppler pdf-compress・PDF 処理 任意
graphviz dot 図 任意
ollama / gollama ローカル LLM mini がホストするなら✅
ccusage Claude Code 使用量表示 任意

Homebrew cask(GUI 寄り = 原則 air のみ)

cask 扱い
drawio air のみ(GUI。CLI export だけ要るなら mini も可)
rancher(Rancher Desktop) air のみ(重い GUI)
gcloud-cli 必要な role のみ
ant ほぼ不要(niche)
~~claude-code~~ Brewfile から外す。2026-07-07 にネイティブ install.sh 版(~/.local/bin/claude・自己更新)へ移行。cask/npm 版は自己再インストールで復活するので、Air で cask+npm を撤去してから両機ともネイティブ版に統一する

npm グローバル(brew 管轄外 → 別スクリプトで npm i -g)

line 93 の「npm/uv 行の扱いは実装時判断」はこの3つを対象に解決する。

パッケージ コマンド 用途
@googleworkspace/cli gws Google Workspace MCP のバックエンド
@mermaid-js/mermaid-cli mmdc Mermaid→PNG(各種スキル)
md-to-pdf md-to-pdf Markdown→PDF(zotero-upload 等)

brew でも npm でもない自作 CLI

CLI 入れ方 依存
~/zotero-cli/zotero-cli + zotero-mcp リポを clone → go build Go 必須。Zotero CLI 兼 MCP バイナリ
~/.claude/scripts/*.sh(bg-notify / block-secret-file-reads / task / drawio-auto-export / sync-home-repos) claude-config を clone すれば付いてくる drawio-auto-export→drawio、bg-notify→macOS 通知

MCP は claude-config でも Brewfile でも同期されない

MCP サーバ定義(drawio / gws / zotero)は ~/.claude.json(リポ外・$HOME 直下)にあり、claude-config でも dotfiles でも同期対象外。mini では claude mcp add ... -s user で再登録する(env は 1Password 経由)。宣言的に揃えたいなら再登録手順を ~/.claude/scripts/ のセットアップスクリプトにして両機で流す。

シークレットと SSH

  • GitHub 認証は 1Password SSH Agent に一本化。秘密鍵を 1Password に保管(既存鍵のインポートか新規生成かは実装時にユーザーに確認)し、~/.ssh/config を chezmoi 管理にして IdentityAgent "~/Library/Group Containers/2BUA8C4S2C.com.1password/t/agent.sock" を指定。秘密鍵ファイルがディスクから消え、mini のセットアップは 1Password ログインだけで git push まで通る
  • 1Password 側の設定(Settings → Developer → SSH Agent 有効化)は GUI 操作なのでユーザーが行う(手順を README に書く)
  • 設定ファイルに埋めたいシークレットが将来出てきたら、テンプレートの onepasswordRead "op://..." で apply 時注入(リポには参照だけ残る)

同期自動チェック(sync-check)

sync-check.sh を dotfiles に含め、launchd(LaunchAgent)で毎日 1 回実行。ズレ検出時のみ osascript で macOS 通知を出す(正常時は無音)。チェック項目:

  1. chezmoi status — 実体が原本からズレていないか(直接編集の事故検知)
  2. chezmoi git -- fetch + behind 判定 — リモートの未取り込み更新
  3. ~/.claude(claude-config)の dirty / behind / 未 push
  4. brew bundle check --file <Brewfile> — 宣言と実インストールの乖離

オプション(実装時にユーザーと相談): 既存の Claude Code SessionStart ブリーフィングに同チェック結果を 1 行追加する。

移行手順(実装フェーズのタスク順)

Phase 1: Air 側で dotfiles 構築

  1. brew install chezmoi
  2. chezmoi init → 既存ファイルを chezmoi add(.zshrc .zprofile .bashrc .vimrc .gitconfig karabiner.json)
  3. .chezmoi.toml.tmpl(role prompt)を作成、.zshrc 等をテンプレート化して role 分岐を導入
  4. brew bundle dump を元に Brewfile.tmpl を作成(npm/uv 行の扱いは実装時に判断。brew 管轄外なら別スクリプトに分離)
  5. defaults スクリプト・brew bundle スクリプト・sync-check + launchd plist を作成
  6. chezmoi apply して Air 上で差分ゼロ・シェル起動正常を確認(検証: 新しいターミナルで zsh が エラーなく起動し、alias/peco が機能すること)
  7. GitHub に private リポ yk0817/dotfiles を作成して push(リポ作成と push はユーザー承認を取る)
  8. 1Password SSH Agent への切り替え(ユーザーの GUI 操作を含む)

Phase 2: mini 側でセットアップ

  1. 1Password アプリ導入・ログイン、SSH Agent 有効化
  2. Homebrew 導入 → brew install chezmoichezmoi init --apply yk0817/dotfiles(role=mini と回答)
  3. gh auth login~/.claudegit clone git@github.com:yk0817/claude-config.git ~/.claude
  4. 自動化系リポを必要分クローン
  5. sync-check の launchd 登録確認、通知テスト

Phase 3: 後片付け

  1. $HOME 直下の空 git リポ(~/.git)を撤去(破壊的操作なのでユーザー確認のうえで)
  2. 移行後の旧 SSH 鍵ファイルの扱い(削除 or 保管)をユーザーに確認

リスクと対処

リスク 対処
実体を直接編集 → 次の apply で上書きされ消える 編集は chezmoi edit に統一(README に明記)。sync-check の status 検知が保険
Karabiner の頻繁な自動書き換えで diff ノイズ 管理を karabiner.json 1 ファイルに限定
mini ヘッドレス時に 1Password agent ロックで git 認証失敗 mini の 1Password 自動ロック設定を緩める(手順を README 化)。常時稼働ジョブが SSH を使う場合は要検証
run_onchange スクリプトの暴発(意図しない brew 実行) スクリプトは冪等に書く。brew bundle--no-upgrade を検討
chezmoi 学習コスト README に日常運用チートシート(edit / apply / update / status)を書く

実装時の注意(実装セッションへの申し送り)

  • ユーザーのグローバルルール(~/.claude/CLAUDE.md)に従う: 日本語 Conventional Commits、push 前にユーザー承認(dotfiles リポは新規なのでノート系例外に該当しない)、シークレット値を stdout に出さない
  • shell スクリプトを書く前に ~/.claude/docs/lang-rules/shell/*.md を Read する
  • gh repo create などの外向き操作は実行前にユーザーに一言確認する
  • 1Password の GUI 設定・GitHub への公開鍵登録など、Claude が代行できない手順は明示的にユーザーへ依頼して止まる

作成: 2026-07-07 / 最終更新: 2026-07-17