Claude Code の設定バックアップが8日間止まっていた原因と、WindowsとMacで設定を分離する計画
Claude Code の設定バックアップが8日間止まっていた原因と、WindowsとMacで設定を分離する計画
セッションを開いたときに、バックアップの鮮度警告が出ていた。 毎朝見る表示なので、そのまま別の作業に入った。 あとで切り分けさせたら、最後に成功した記録は8日前の 2026-08-01 で止まっていた。
やっかいだったのは、監視のほうが「正常」と言い続けていたことである。
何が壊れて、何が無事だったか
最初に自分でも混乱した。 ログのバックアップができていないのか、履歴の復元ができないのか。 壊れているなら、その日の日記記事はどうやって作ったのか。
切り分けさせると、壊れていたのは外部への退避だけで、ローカルのセッションログはそのまま残っていた。 記事の材料はバックアップではなくログ本体を読んでいるので、退避が止まっていても普通に作れる。 被害は「消えたら戻せない」という一点に集約されていた。 それは十分に困る。
止まっていた経路は2本あり、原因は別だった。
セッション履歴の退避は1Password の承認で止まり、~/.claude を GitHub の dotclaude へ送る同期は push で弾かれていた。
承認ダイアログが前に出てこない
セッション履歴の退避は、暗号化のパスフレーズを 1Password から取り出す工程を挟む。 そこで承認が要る。
先に自分の思いつきをぶつけた。 1Password には MCP サーバーがあるのだから、それを設定すれば毎朝の承認が要らなくなるのではないか。 1日1回ならこのままでもいいが、何回も承認している気がする。
その手は通らなかった。 MCP 側には値を読み取るツールが存在しない(できるのは一覧、作成、改名、追記だけ)。 しかも MCP は Claude のセッション内でしか動かないので、朝7時のタスクスケジューラからは呼べない。
診断はそこから2回ひっくり返った。
op whoami は「not signed in」を即返す。
これを根拠に「CLI 統合そのものがオフ」と説明された。
ところが op vault list を叩かせると、即エラーではなく45秒ハングしてタイムアウトした。
whoami は認証を発火させず現在の状態を答えるだけなので、統合オフの根拠にはならない。
実態は統合オンで、承認待ちのまま止まっていた。
では、なぜ承認ダイアログが目の前に出てこないのか。
1Password はトレイに常駐しているだけで、表示ウィンドウを持っていなかった。
ストア版(MSIX)だったので shell:AppsFolder 経由で前面に出させたら、承認は通った。
その前に一度、60秒のタイムアウトで切れている。
保管庫の一覧が取れたので、8日分の履歴退避をまとめて流した。 実物を確認させたところ、8日分すべて追いついていた。
このとき自分が聞いたのはこれである。
多分ね、OKした気がするんすけど、ちょっと覚えてないっす。失敗しても成功を返すんすか?
この質問は承認の挙動について出したものだった。 ところが直後に検証させた同期スクリプトのほうに、「失敗しても成功と記録する」経路が実在した。
dotclaude 同期が弾かれていた理由
dotclaude 同期のログの末尾は、コミットの行のすぐ下に FAIL: push に失敗 が並んでいた。
コミットはローカルに残り、GitHub には載っていない。
自分の見立ては「この8日間ずっと Mac で作業していたからではないか」だった。 推測で答えさせず、ログの実物で確かめさせた。 見立ては当たっていて、説明のほうが間違っていた。
同期スクリプトは git fetch も git pull もしない。
Mac が先に push していれば、Windows は古い土台の上でコミットすることになり、non-fast-forward で必ず弾かれる。
自動同期は1日に複数回走るので、2台を同じ日に使うたびに再現する。
そして、押し戻された状態で手動実行するとこうなる。
11:05 定刻同期 → commit → FAIL: push に失敗
11:14 手動実行 → ステージ差分なし → 「正常終了」→ 成功マーカーを 11:14 に更新
該当箇所は、ステージされた差分が無ければリモートと照合せずに成功時刻を書いて終了していた。 ローカルの HEAD と GitHub の実体が別物なのに、鮮度監視は「正常」を出す。 セッション開始時のチェックも通る。 次に気づく機会が、どこにも無い。
復旧は別セッションに渡した
原因が見えた時点で、復旧作業は手元のセッションから切り離した。 Windows 機のセッションに依頼文を書かせ、それを別のセッションに渡して調査と復旧をやらせた。 症状、確認済みの事実、依頼内容の順である。 症状にはログ末尾の2行と最後に成功した時刻を、事実には「履歴の退避は今朝10時台に両系統とも成功しており、止まっているのは dotclaude 同期だけ」という切り分けを添えさせた。
受け取った側は push を通したあと、origin と一致しているか、rebase 後の settings.json に両機の変更が共存しているか、state ファイルが更新されたかを検証した。
恒久対応も同じセッションでコミットさせた。
学習ゲートのクイズ4問に答えてから受領証を出す、いつもの手順を通っている。
Mac 側は pull すれば新しいスクリプトが入る。 launchd の登録は触らなくてよい。 タスクはスクリプトをパスで呼ぶので、次回実行から自動的に新版になる。
何が2台のあいだで往復していたか
push の失敗は結果であって、原因は「同じファイルを2台で共有していること」にある。
直近30件の自動同期コミットで、実際に変更されたファイルを数えさせた。
| ファイル | 変更回数 | 性質 |
|---|---|---|
settings.json | 12 / 30 | マシン固有(許可リストの絶対パス、hooks のOS依存パス) |
home/gitconfig | 4 / 30 | マシン固有(credential helper のパス、core.hooksPath) |
CLAUDE.md | 4 / 30 | 共有すべき本体 |
往復しているのは実質2ファイルで、残りは共有して価値のある内容だった。
~/.claude そのものがリポジトリで、settings.json は実ファイルがそのまま追跡されている。
リポジトリ外の設定を写すミラー処理は、実行したマシンの内容で無条件に上書きする。
どちらのマシンも正しく動いているのに、毎回相手の設定を消していた。
実害はすでに出ていた。
Windows 機の settings.json を機械的に検査させると、macOS のパスが5箇所混ざっていた。
hooks セクションにも入り込んでいて、SessionStart が Windows に存在しないパスを指していた。
Claude Code はフックの失敗を非ブロッキングとして扱うので、これは黙って死ぬ。
同じ形の事故を 2026-08-04 に踏んでいる。 主作業機を Windows から macOS へ移したとき、フックのパスが Windows のまま残り、再帰削除ガードを含む4つの安全機構が同時に死んでいた。 今回は方向が逆なだけで、原因は変わらない。
「同じファイルを使う必要はない」と方針を出した
構造が見えた時点で、こう指示した。
WindowsとMacで同じファイルを使う必要なくて、例えば上書きされちゃうんだとしたら、これは普通にレポジトリ2つに分けるとか、重複した内容でファイルを分けるとか、なんかうまくやってくれませんかね。
そのうえで計画書を作らせた。
戻ってきた答えは、リポジトリ分割の不採用だった。
skills が108ファイル、rules が19、commands が19あり、これを二重管理にすると共有の利点を丸ごと失う。
片方だけ更新される事故が新しく生まれる。
代わりに出てきたのが、往復している4ファイルだけを hosts/<OS>/ へ隔離する案で、これを採った。
settings.json は追跡をやめ、実ファイルは各機に置いたままにする。
同期スクリプトは uname -s で自分のOSを判定し、自分のディレクトリにしか書かない。
相手のディレクトリに触れないので、上書きが構造的に起こり得なくなる。
同期スクリプトには安全策を3つ足させた。 成功判定をリモート照合に変えること。 分岐の解消はクリーンな作業ツリーで行うこと。 ミラーのコピー失敗を fail-closed にすること。
1つ目には注文を付けた。 判定だけを足すと、不具合が「毎回成功」から「毎回失敗」に変わるだけになる。 差分の有無にかかわらず fetch し、behind なら取り込み、ahead なら push し、0対0を確認してから成功マーカーを書く。 「差分が無いので何もせず終了」という早期 return は廃止した。
レビュー7回と、決裁フォーム4問
計画書は Codex に7回回した。
1回目のレビュー中にリポジトリの HEAD が動いていた。 2回目以降は読み取り専用のサンドボックスを指定して走らせた。 事前に HEAD と reflog の件数を控えておき、レビューのたびに突き合わせて、書き込みが起きていないことを確認させた。
指摘は実務的な穴ばかりだった。
.gitignore に settings.json と書くと hosts/windows/settings.json まで無視され、新規ファイルの収集が --exclude-standard なのでホスト別コピーが1つも GitHub に載らない。
その状態でルートの削除だけが Mac へ伝播すれば、防ごうとしていたデータ消失を自分の計画で起こすことになる。
Windows の同期タスクが4時間ごとに走るという指摘も出た。
移行の途中で確実に割り込むので、先に両機の自動同期を止めるフェーズを足させた。
7回目で「実行可」になったので、HTML 化して決裁フォームを立てさせ、Chrome の前面タブに出させた。
図が img として0個に見えて一瞬あせったが、--embed-resources でインライン svg に展開されていただけだった。
判断は4問。
settings.json を追跡から外すか。
すでに push されているリベースを追認するか。
混入している Mac 専用フック5箇所をどう始末するか。
既存の home/ ディレクトリを残すか。
移行はまだ実行していない
着手は次にまわした。 自動同期が4時間ごとに割り込むので、両機を止めてから始める。
残ったのは一点だけである。 「成功と記録されている」ことは、「成功した」ことではない。 鮮度監視は8日間ずっと正常と言っていた。 疑うきっかけになったのも監視ではなく、手元の違和感のほうだった。