10
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Claude Code・Codex・Gemini の会話ログを日次Markdownとして自動整理する ― chat_logs から LLM_history を自動生成する仕組み

10
Last updated at Posted at 2026-03-07

はじめに

Claude Code、Codex、Gemini を併用していると、あとから「あの日どのツールで何を相談したか」を追いたくなる場面が増えます。

ただし実際のログは、ツールごとに保存形式も保存場所も違います。

  • Codex は JSONL ベース
  • Claude Code も JSONL だがイベント種別が多い
  • Gemini はセッション JSON が主体

そのままでは読みづらく、日単位の振り返りにも向きません。

そこで、各ツールのログを chat_logs に集約し、さらに LLM_history 配下へ「日次概要 + LLM別詳細 Markdown」として自動整形する仕組みを作りました。

本記事では、その構成、設計意図、スクリプト、そして cron による毎日1回の自動実行までをまとめます。

完成イメージ

この構成により、日付単位で次の2種類の見方ができます。

ファイル 用途
YYYY-MM-DD.md 1日の全体像をざっと確認する概要
YYYY-MM-DD.codex.md など ツール別に詳細な会話本文を読む

システム構成

今回の仕組みは、ログ収集・状態管理・Markdown 出力の 4 層で構成しています。

コンポーネント 役割
元ログ ~/.codex/sessions, ~/.claude/projects, ~/.gemini/tmp 各ツールの生ログを保持
差分収集 batch_copy_codex_diff.sh など 元ログを chat_logs に差分コピー
状態管理 SQLite (LLM_history/_meta/history.db) 取り込み済みファイル、正規化済みメッセージ、重複排除キーを保持
出力 render_llm_history.py + LLM_history/ 日次概要・LLM別詳細・月次一覧を生成

chat_logs だけでなく SQLite を間に挟んでいるのがポイントです。これにより、ログ差分収集と閲覧用 Markdown 生成を疎結合にできます。

前提環境

筆者の環境は以下のとおりです。既存の chat_logs 収集基盤の上に、本記事の Markdown 整理レイヤを追加しています。

項目 詳細
OS Ubuntu 24.04.4 LTS
CPU Intel Core i7-12700K
RAM 64 GB
GPU NVIDIA GeForce RTX 3070(VRAM 8 GB)
接続方式 Windows → VS Code Remote SSH → Linux
作業ルート /home/username/work_space
元ログ集約先 chat_logs/
出力先 LLM_history/
正規化スクリプト tools_for_ai/codex/render_llm_history.py
実行ラッパ tools_for_ai/codex/update_llm_history.sh
永続状態 LLM_history/_meta/history.db
定期実行 cron(毎日 04:05 UTC)

LLM_history/.gitignore に追加しておくのがおすすめです。
日次ファイルが増え続けるため、未追跡ファイルのノイズを防げます。
記事内の絶対パスは、個人名を避けるため username 表記に統一しています。

仕組みの全体像

なぜ chat_logsLLM_history を分けるのか

この構成では、あえて「集約ログ」と「閲覧用ドキュメント」を分離しています。

役割 理由
chat_logs 元ログの差分保管 再解析や再生成の元データとして残す
LLM_history 人が読むための Markdown 読みやすさを最優先に整形する

この分離により、表示ルールを後から変えても chat_logs から再生成できます。

なぜ SQLite を挟むのか

chat_logs を毎回フルスキャンして Markdown を直接再生成することもできますが、差分収集方式との相性を考えると SQLite を挟んだ方が運用しやすくなります。

SQLite に持たせている情報 役割
source_files どの _merged_*.jsonl を何回目のパーサで取り込んだか管理
messages 正規化済みの会話本文を保持
message_key LLM ごとの重複排除キー

これにより、次のことが可能になります。

  • 変更のあった入力ファイルだけ再取り込みする
  • 過去分を --render-all で高速に再出力する
  • 差分コピーで同じセッションが再度流れてきても重複を抑える

なぜ「日次概要 + LLM別詳細」にしたのか

最初は1日1ファイルに全部入れる案もありましたが、会話量が多い日は長すぎて読みにくくなります。逆に LLM ごとに完全分離すると、その日の全体像が見えなくなります。

そこで折衷案として、次の形にしました。

見方 向いている用途
日次概要 その日何をしていたかを横断的に把握
LLM別詳細 同じツールでの会話だけを深く追跡

ログ形式の違い

各ツールはログ形式が違うため、正規化ステップが必要です。

ツール 集約元 代表ファイル 主な抽出対象
Codex chat_logs/chatgpt/... _merged_rollouts.jsonl response_item の user / assistant
Claude Code chat_logs/claude/... _merged_sessions.jsonl type=user/assistant の本文
Gemini chat_logs/gemini/... _merged_sessions.jsonl messages[] の user / gemini

特に Codex は保存先ディレクトリ名が chatgpt ですが、実際には Codex ログを格納しています。これは既存運用との互換のため、そのまま使っています。

正規化でやっていること

1. 不要イベントの除外

人が読み返す用途では、すべてのイベントを残す必要はありません。進捗通知や内部指示は落としています。

除外対象
system/developer 相当 AGENTS.md instructions, permissions instructions
進捗イベント queue-operation, progress, event_msg の一部
低シグナル応答 I will ... のような Gemini の進捗文
ツール呼び出しだけの行 ツール呼び出し: ...

2. 重複排除

差分収集は「更新されたセッションファイルを丸ごと再コピー」する方式なので、そのまま連結して読むと重複が出ます。そこで SQLite に正規化済みメッセージを保存し、メッセージキーで重複を防ぎます。

ツール 重複排除キー
Codex session_id + timestamp + role + content_hash
Claude Code uuid
Gemini message.id

3. 日付判定の統一

ログは UTC タイムスタンプを持っていますが、日次ファイルは Asia/Tokyo などのローカルタイムで切った方が実運用に合います。

入力 出力
2026-03-01T15:00:11.871Z 2026-03-02 00:00:11 JST

この変換を統一しておくことで、深夜帯の会話が期待どおり同じ日付にまとまります。

出力ファイル構成

生成後のディレクトリは次のようになります。

LLM_history/
  _meta/
    history.db
  index.md
  2026/
    2026-03/
      index.md
      2026-03-01.md
      2026-03-01.codex.md
      2026-03-01.claude.md
      2026-03-01.gemini.md
パス 内容
LLM_history/index.md 全月・全日一覧
LLM_history/YYYY/YYYY-MM/index.md 月次一覧
YYYY-MM-DD.md 日次概要
YYYY-MM-DD.codex.md など LLM別詳細
LLM_history/_meta/history.db 増分管理用 SQLite

Step 1: 差分収集スクリプトの準備

まずは各 LLM の元ログを chat_logs に取り込む必要があります。今回の環境では、すでに以下の差分収集スクリプトを使っています。

スクリプト 役割
/home/username/tools/batch_copy_codex_diff.sh Codex ログ取り込み
/home/username/tools/batch_copy_claude_diff.sh Claude Code ログ取り込み
/home/username/tools/batch_copy_gemini_diff.sh Gemini ログ取り込み

これらは chat_logs/<tool>/000xx/ のような連番ディレクトリを作り、 _merged_*.jsonl を生成します。

Step 2: Markdown 生成スクリプト(render_llm_history.py)

会話本文の整形は render_llm_history.py が担当します。

スクリプトの役割

処理 内容
ソース探索 chat_logs 配下の _merged_*.jsonl を列挙
形式吸収 Codex / Claude / Gemini の本文抽出
永続化 SQLite に正規化済みメッセージと取り込み状態を保存
出力 日次概要・LLM別詳細・月次一覧・全体一覧を生成
清掃 消えた日付や不要ファイルを削除

主な実行コマンド

# 全件再生成
python3 /home/username/work_space/tools_for_ai/codex/render_llm_history.py --render-all

# 特定日だけ更新
python3 /home/username/work_space/tools_for_ai/codex/render_llm_history.py --date 2026-03-01

# タイムゾーン変更
python3 /home/username/work_space/tools_for_ai/codex/render_llm_history.py --tz Asia/Tokyo

Step 3: 実行ラッパ(update_llm_history.sh)

日常運用では、差分収集と Markdown 生成を別々に叩くより、ラッパにまとめた方が楽です。

update_llm_history.sh は次の流れで動きます。

代表的な使い方

# 収集 + 生成
/home/username/work_space/tools_for_ai/codex/update_llm_history.sh

# 既に chat_logs が更新済みなら生成だけ
/home/username/work_space/tools_for_ai/codex/update_llm_history.sh --skip-sync

Step 4: cron による日次実行

今回の環境では、差分収集ジョブがすでに 04:00 UTC に入っていたため、その5分後に LLM_history 生成を追加しました。

現在の cron 登録

# batch_copy diff jobs
0 4 * * * /home/username/tools/batch_copy_claude_diff.sh > /dev/null 2>&1
0 4 * * * /home/username/tools/batch_copy_codex_diff.sh > /dev/null 2>&1
0 4 * * * /home/username/tools/batch_copy_gemini_diff.sh > /dev/null 2>&1

# LLM_history daily render (UTC)
5 4 * * * /home/username/work_space/tools_for_ai/codex/update_llm_history.sh --skip-sync >> /home/username/work_space/tmp/update_llm_history.log 2>&1

こうした理由

選択 理由
04:05 UTC 差分収集が終わった直後に動かしたい
--skip-sync 同じタイミングで二重に収集しない
>> ...log 2>&1 失敗時の原因をあとから追える

この cron 実装では CRON_TZ が使えなかったため、スケジュールは UTC で登録しています。
一方、Markdown 内の日付判定は Asia/Tokyo で行っています。

実際の見え方

生成後は、たとえば次のように読み分けられます。

ファイル 読み方
2026-03-01.md その日のセッション一覧と LLM 別リンクを見る
2026-03-01.codex.md Codex の会話だけ読む
2026-03-01.claude.md Claude Code の会話だけ読む
2026-03-01.gemini.md Gemini の会話だけ読む

月次一覧には次のように「概要 + 各 LLM の詳細リンク」が並びます。

日付 概要 Codex Claude Gemini
2026-03-01 あり あり あり あり
2026-03-02 あり あり あり なし
2026-03-04 あり なし なし あり

この形にしておくと、「今日は Gemini だけだった」「この日は Claude のみ大量に使った」といった偏りも一覧で把握できます。

運用上のポイント

1. 生成物は Git 管理しない

生成ファイルは日々増えるので、基本的には .gitignore に入れるのが無難です。

2. 表示ルールを変えたくなったら --render-all

進捗文の除外ルールやタイトル生成ルールを変えた場合は、全件再生成すれば過去分にも反映できます。

python3 /home/username/work_space/tools_for_ai/codex/render_llm_history.py --render-all

3. 将来的な拡張

拡張案 内容
週次サマリ 1週間単位のインデックスを追加
全文検索 history.db に FTS を追加
タグ抽出 会話からトピックを自動分類
HTML 出力 Markdown だけでなく静的サイト化

まとめ

今回の仕組みでは、3 種類の LLM ログを chat_logs に集約し、さらに LLM_history として人間向けの Markdown に再構成しました。

ポイントは次の3つです。

  • 保存用の chat_logs と閲覧用の LLM_history を分離した
  • 日次概要 + LLM別詳細 にして可読性と追跡性を両立した
  • cron で毎日1回更新し、運用を手放せる形にした

「複数の AI コーディングツールを使っているが、あとから会話を振り返りづらい」と感じているなら、この構成はかなり相性が良いはずです。

10
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?