株式会社TOEでは、AIコーディング環境のClaude Codeを複数のMacとiPhoneから使っています。先に結論を書きます。会話履歴のファイルは、あえてマシン間で同期していません。 代わりに、全案件の「次の一手」をgit履歴順に並べた1枚のボードと、各会話の要点メモを、hook(決まったタイミングで自動実行される仕組み)で生成しています。「会話の続き」ではなく「作業の続き」を復元する設計です。
この記事は、実際に動いているスクリプト2本とルールファイルを開いて、書いてあることだけをもとに書いています。
会話の再開が「別のPCでは原理的に効かない」
Claude Codeには過去の会話を再開する --resume という機能があり、会話履歴はjsonlというテキスト形式のファイルに残ります。同じPCの中なら、これで会話をそのまま呼び戻せます。
弊社は設定フォルダをGitHub経由で複数のMac間で自動同期していますが、この会話履歴だけは同期対象から除外しています。 除外設定に書かれている理由は「書込中pullの破損防止」。会話中に書き込まれている最中のファイルへ、別マシンからの同期が重なると壊れるためです。
その結果どうなるか。ルールファイルには、はっきりこう書いてあります。
別PC・dispatch では
claude --resume <UUID>は効かない。会話の続きではなく HANDOFF ベースで作業を再開する。
つまり「会話履歴を同期して、どこでもresumeできるようにする」道は最初から捨てています。壊れやすいものを頑張って同期するのではなく、同期して安全なもの(gitで管理するテキストファイル)だけで、作業に戻れるようにするという割り切りです。
前提になっているHANDOFF.mdのルール
この仕組みの土台は、AIではなくただの運用ルールです。配下のすべてのプロジェクトのルートに HANDOFF.md(引き継ぎメモ)を置き、セッション終了時に必ず更新する。中身は最低限この3点と決められています。
- 現在地 — いまどこまで進んでいるか、最後にやったこと
- 次の一手 — 即実行できる粒度のTODO
- ブロッカー — 待ち状態・外部依存・未解決の問い
差分がなくても最終更新日だけは進める、というところまでルール化されています。後述のスクリプトは、この引き継ぎメモが各案件に存在することを前提に組まれています。逆に言えば、このルールが守られていない案件では仕組み全体が空回りします。 自動化の下に人間の運用ルールが敷いてある、という構造です。
続き.md — 全案件を「最後に触った順」に並べる単一ボード
1本目のスクリプトが build_now_board.py(167行)です。生成物は 続き.md という1枚のMarkdownで、別のPCやiPhoneで「最後にやっていた作業はどれ?」となったとき、最初に読むファイルと位置づけられています。起動時にはSessionStart hookが冒頭を自動表示します。
やっていることはコード上、次の4段階です。
- 作業フォルダ配下を走査して、全案件の
HANDOFF.mdを集める - 各案件フォルダの「gitの最終コミット時刻」を取り、新しい順に並べる(=実際に最後に触った順)
- 各HANDOFFから「最終更新」の行と「次の一手」の先頭1〜3項目を正規表現で抜き出す
- 上位8件だけを、再開コマンド付きでボードに書き出す
出力される各項目には、案件名・最終コミット時刻・次の一手に加えて、cd "<案件の絶対パス>" && claude というそのまま貼れば作業を再開できるコマンドが1行ずつ付きます。1位の案件には「← 最後に作業」の印が付き、末尾には案件カタログ(INDEX.md)と過去会話の索引(SESSIONS.md)へのリンクが置かれます。
地味ですが実用上効いている工夫が走査の除外リストです。コードのコメントによると作業ツリーは12GBあり、node_modules や .git、ビルド生成物などのフォルダには最初から潜らない設計になっています。シンボリックリンク(別の場所を指すショートカットのようなもの)も辿りません。循環やリンク先の肥大で走査が終わらなくなるのを避けるためです。
会話メモ — 各ターンの「指示」と「結果」だけを抜いて残す
続き.mdだけだと「次に何をやるか」は分かっても、「直前にどういうやり取りをしたか」までは分かりません。HANDOFFが粗い日もあります。そこを埋めるのが2本目の save_turn_digest.py(121行)です。
これはStop hook(Claudeが応答を返し終わるたびに動く仕組み)として動きます。会話履歴のjsonlを読み、そのターンの最後のユーザー指示と、最後のAI回答のテキストだけを抜き出して、案件名ごとのファイル _会話メモ/<案件名>.md に追記します。ツールの実行結果やシステムメッセージ由来の行は飛ばし、人間が打った指示だけを拾うようになっています。ファイル名は作業ディレクトリのフォルダ名から自動で決まります。
書式は「指示: 〜」「結果: 〜」のペアが新しい順に並ぶだけの単純なもので、制限もはっきり決めてあります。
| 項目 | 値 |
|---|---|
| 1件あたりの最大文字数 | 指示・結果それぞれ500文字で打ち切り |
| 1ファイルに残すターン数 | 最大30件(古いものから削除) |
| 同一内容の連続追記 | 直前と同じなら書かない(hookの多重発火対策) |
| 手動編集 | 禁止(ファイル冒頭に明記) |
このファイルはgit同期の対象なので、auto-pushで全PCとiPhone(GitHub経由)に届きます。会話そのものは同期しないが、会話の要点500文字×30ターンぶんだけは同期する。 ここがこの設計の落としどころです。
過去の漏洩事故が、コードのコメントに残っている
正直に書くべき部分です。このスクリプトには、APIキーやトークンの典型パターン7種類を検出して [REDACTED] に置き換える処理が入っています。そしてその直上のコメントには「秘密情報の平文同期事故防止(2026-06-06の漏洩事故の再発防止)」とあります。
つまり弊社は一度、会話の中に含まれていた秘密情報を、平文のままgit同期に載せてしまう事故を起こしています。 会話の要点を自動でgitに流すという仕組みは、便利さと引き換えに「会話に貼ったものは何でも同期される」という危険を最初から抱えています。いまの検出処理も既知のパターン7種への対策であって、パターンに合致しない秘密が素通りする可能性は残ります。同じ仕組みを作る方は、この対策を後付けではなく初日から入れることをおすすめします。うちは後付けでした。
この設計の割り切りと弱点
コードを読んで確認できる範囲で、割り切っている点を挙げます。
- 並び順はgitのコミット時刻に依存します。 コミットしていない作業は「最後に触った案件」として上がってきません
- 「次の一手」の抽出は正規表現です。 HANDOFFの見出しの書き方が想定から外れると、ボードのその欄は空になります
- 会話メモは各ターンの最後の指示と最後の回答だけで、途中の試行錯誤は残りません。500文字で切れるので長い回答は尻切れになります
- ボードに載るのは上位8件だけで、それ以外の案件はINDEX経由で探すことになります
それでも「会話履歴を全部同期して完璧に再現する」方向に行かなかったのは、壊れる同期・膨らむデータ・漏れる秘密という3つのコストを避けて、再開に本当に必要な情報は『次の一手』と『直前のやり取りの要点』だけと決めたからです。この要件定義の部分は、AIがなくても紙のノートでも成立する話です。
関連する記録
- 成果物フォルダをGoogle Driveへ自動ミラー同期 — 54日で448回動いた73行のスクリプトと、コードに存在しなかった除外設定
- 自動化26本に「見張り役」の画面を付けたら、そもそも全部止まっていた — DB不要・追加コストゼロのダッシュボード
まとめ
- 会話履歴(jsonl)は書き込み中の同期で壊れるため、マシン間で同期しない設計にした。別PCでの会話resumeは最初から捨てている
- 代わりに、全案件のHANDOFF.mdをgit履歴順(最後に触った順)に並べ、次の一手と再開コマンド付きで上位8件を1枚に集約する
続き.mdをhookで自動生成している - 会話の文脈は、各ターンの指示と回答を500文字・30ターンまでに絞った案件別の会話メモとしてgit同期し、iPhoneからも読めるようにしている
- 秘密情報の平文同期事故を一度起こしており、その再発防止の検出処理がコードに残っている。同種の仕組みを作るなら初日から入れるべき対策
株式会社TOEでは、こうした社内での実践をもとに、中小企業向けのAI開発・業務自動化の相談を受けています。詳しくは 株式会社TOE をご覧ください。