メインコンテンツへ移動
AIチュートリアル

PythonでAIコーディングアシスタントのチャットを抽出・正規化する

AI Coding Assistant Data Extractionを使って、Claude Code、Codex CLI、Cursor、Windsurf、Trae、Continue、Gemini CLI、OpenCode、Cline、Roo Code、Aiderのローカルチャット履歴を検出し、バックアップ、分析、トレーニングに使える正規化済みJSONLへ変換する方法を学びます。

PythonでAIコーディングアシスタントのチャットを抽出・正規化する

このプロジェクトの機能

AI Coding Assistant Data Extraction は、複数のコーディングアシスタントにローカル保存された会話を収集し、一貫した JSONL 形式で書き出します。チャット履歴のバックアップ、個人分析、ファインチューニング用データの準備、またはアプリケーションがローカルデータベースを消去する前の会話保存に役立ちます。

このツールキットは、macOS、Linux、Windows 上の保存場所を自動的に検出します。サードパーティ製の Python 依存関係を必要とせず、JSONL ファイル、JSON セッションファイル、Markdown トランスクリプト、SQLite データベース、ネストされた JSON ストレージツリーを読み取れます。

対応ソース

現在、以下のツールに対応しています。

  • Claude Code: ~/.claude/projects/ 配下の JSONL セッションファイル。
  • Codex CLI: ~/.codex/sessions/ 配下の JSONL ロールアウトファイル。
  • Cursor: グローバルおよびワークスペースのストレージにある SQLite state.vscdb ファイル。
  • Windsurf: ベストエフォートのヒューリスティックで解析する SQLite ストレージ。
  • Trae: ベストエフォートのヒューリスティックで解析する SQLite および JSONL ストレージ。
  • Continue: ~/.continue/sessions/ 内の JSON ファイル。
  • Gemini CLI: ~/.gemini/tmp/ 配下の JSON チャットファイル。
  • OpenCode: JSON のセッション、メッセージ、パートのツリー。
  • Cline と Roo Code: エディター拡張機能が保存する JSON タスクフォルダー。
  • Aider: プロジェクトディレクトリ内にある .aider.chat.history.md という名前の Markdown トランスクリプト。

インストールとセットアップ

リポジトリをクローンまたはダウンロードし、プロジェクトルートからスクリプトを実行します。抽出ツールが使用するのは Python 標準ライブラリだけです。Python 3.9 以降が必要で、Python 3.10 以降を推奨します。

python --version

コア抽出ツールの実行に、仮想環境や依存関係のインストールは必要ありません。抽出前に、対象の AI コーディングツールをそのマシンで使用し、ローカルの会話ファイルまたはデータベースが存在することを確認してください。

最初の抽出を実行する

対話形式で実行するには、引数なしでメインスクリプトを起動します。番号付きメニューが表示され、抽出するソースを選択できます。

python extract.py

プロンプトを表示せず、対応するすべてのソースを抽出するには、--all を使用します。

python extract.py --all

カンマ区切りのリストで特定のソースを選択することもできます。ソース ID はリポジトリのソース一覧、または --list の実行結果で確認できます。

python extract.py --sources cursor,claude_code,aider

会話を抽出せず、検出されたインストール先を確認するには、次を実行します。

python extract.py --list

同梱のシェルショートカットは、利用可能なシステムで全ソースの抽出を実行します。

./extract_all.sh

出力先と検索パスを選択する

デフォルトでは、タイムスタンプ付きの JSONL ファイルが ./extracted_data に書き込まれます。別の保存先を選択するには、--output-dir を使用します。

python extract.py --all --output-dir ./chat-backup

ほとんどのツールには予測可能なアプリケーションデータディレクトリがあるため、抽出ツールは一般的なオペレーティングシステムの場所を自動的に検索します。Aider は異なり、中央のアプリケーションデータフォルダーではなく、各プロジェクトディレクトリ内に Markdown トランスクリプトを 1 つ保存します。

プロジェクトやアプリケーションデータが通常とは異なる場所にある場合は、1 つ以上の --search-path オプションを使用します。

python extract.py --sources aider \
  --search-path ~/client-work \
  --search-path /mnt/data/repos

追加の検索パスは、対応する他のツールを標準とは異なる場所にインストールしている場合にも役立ちます。

会話を 1 つのファイルに統合する

通常、選択した各ソースには、それぞれタイムスタンプ付きの出力ファイルが割り当てられます。--merge を追加すると、抽出したすべての会話を all_conversations.jsonl に連結できます。

python extract.py --all --merge

一般的な出力ディレクトリには、次のようなファイルが含まれます。

extracted_data/
├── claude_code_conversations_20260816_143022.jsonl
├── cursor_conversations_20260816_143022.jsonl
├── aider_conversations_20260816_143022.jsonl
├── cline_conversations_20260816_143022.jsonl
└── all_conversations.jsonl

正規化された形式を理解する

出力ファイルの各行は、1 つの会話を表します。共通の構造には、messages 配列、source 識別子、session_id が含まれます。その他のフィールドは、元のツールが記録した内容によって異なります。

{
  "messages": [
    {
      "role": "user",
      "content": "How do I fix this TypeScript error?",
      "code_context": [
        {
          "file": "/Users/you/project/index.ts",
          "code": "const x: string = 123;"
        }
      ],
      "timestamp": "2026-01-16T14:30:22Z"
    },
    {
      "role": "assistant",
      "content": "The error occurs because a number is assigned to a string type.",
      "tool_use": [
        {
          "name": "edit_file",
          "input": {"path": "src/index.ts"}
        }
      ],
      "timestamp": "2026-01-16T14:30:25Z"
    }
  ],
  "source": "cursor-composer",
  "session_id": "c1a2b3...",
  "project_path": "/Users/you/project",
  "name": "TypeScript Type Error Fix",
  "created_at": 1705414222000
}

code_context、トークン使用量、プロジェクトパス、タイムスタンプ、ツール呼び出し、差分などのフィールドは、ソースに保存されている場合に含まれます。一貫して利用できるフィールドは、messages、source、session_id です。

抽出の仕組み

  1. プログラムはオペレーティングシステムを検出し、Application Support、.config、.local/share、%APPDATA%、%LOCALAPPDATA%などの場所を含む、データルートの候補一覧を作成します。
  2. 各ソースは、それらのルート内で既知のフォルダー名とファイル名を検索します。
  3. 適切なリーダーが、JSONL、JSON、SQLite、Markdown、またはネストされたJSON形式のストレージを読み込みます。
  4. 抽出器は、検出したレコードを共有メッセージスキーマに正規化します。
  5. タイムスタンプ付きのJSONLファイルが出力ディレクトリに書き込まれます。

SQLiteデータベースは読み取り専用で開かれるため、実行中のエディターをブロックしにくくなります。また、リーダーは分離されているため、破損またはロックされたファイルがあっても、抽出全体が停止せず部分的な結果が生成されます。

文書化されていないストレージ形式に対応する

Cursor、Windsurf、Traeは、安定したストレージスキーマを公開していません。Cursorの抽出器は、ワークスペースのItemTableチャット、インラインコンポーザーのデータ、分割されたbubbleIdコンポーザーのデータなど、複数の既知の形式を明示的に処理します。

WindsurfとTraeでは、extractors/common.pyにある汎用ヒューリスティックを使用します。チャット関連のキーを検索し、解析済みJSONを走査して、ロールとテキストのメッセージペアに似たオブジェクトを探します。これは意図的にベストエフォートで行われます。今後のアプリケーション更新でストレージ形式が変更された場合は、関連するKEY_HINTSの値を更新する必要があります。

出力をトレーニングデータに使用する

正規化されたJSONLファイルは、Hugging Faceのdatasetsライブラリで読み込めます。次の例では、抽出されたすべてのファイルを読み込み、アシスタントメッセージを含む会話だけを残し、トークナイザーのチャットテンプレートで整形します。

from datasets import load_dataset

dataset = load_dataset(
    "json",
    data_files="extracted_data/*.jsonl",
    split="train"
)
dataset = dataset.filter(
    lambda x: any(m["role"] == "assistant" for m in x["messages"])
)

def format_chat(example):
    return {
        "text": tokenizer.apply_chat_template(
            example["messages"],
            tokenize=False
        )
    }

dataset = dataset.map(format_chat)

モデルの要件に応じて、レコードをさらに確認・変換してください。ソースによって異なる任意フィールドが含まれる場合があるため、トレーニングパイプラインでは主に共有メッセージ構造を利用してください。

新しいソースで抽出器を拡張する

各ソース抽出器は、2つの関数からなるシンプルなインターフェースに従います。continue_ext.pyをコピーすると、簡単な出発点になります。

DISPLAY_NAME = "My Tool"
SOURCE_ID = "my_tool"

def find_installations(extra_paths: list[Path] | None = None) -> list[Path]:
    """スキャン対象として適切なディレクトリまたはファイルを返します。"""

def extract(installations: list[Path]) -> list[dict]:
    """正規化された会話辞書を返します。"""

モジュールを作成したら、extract.pyのREGISTRYリストに登録します。共有リーダーと汎用ヒューリスティックはextractors/common.pyで利用できます。

機密性の高い会話データを保護する

ローカルのチャット履歴には、APIキー、専有コード、個人のパス、顧客情報、ツール入力が含まれている場合があります。抽出したファイルを共有したりトレーニングに使用したりする前に、内容を確認してください。

  1. 出力をスキャンして秘密情報を確認します。
  2. code_contextフィールドとtool_useフィールドを注意深く確認します。
  3. extracted_data/を公開リポジトリにコミットしないでください。
  4. 機密性の高いバックアップは暗号化ストレージに保管します。
pip install detect-secrets --break-system-packages
detect-secrets scan extracted_data/*.jsonl

プロジェクトではextracted_data/が.gitignoreに含まれていますが、公開する前に、リポジトリとバックアップの運用方法を確認してください。

トラブルシューティング

インストール先が見つからない

ツールがインストールされていない、保存済みのチャット履歴がない、または標準以外の場所を使用している可能性があります。まず--listを実行し、次に--search-pathで該当するディレクトリを指定してください。ソース抽出器のSEARCH_DIRS定数またはAPP_DIR_NAMES定数を確認することもできます。

CursorまたはWindsurfでデータベースがロックされていると報告される

抽出器は読み取り専用のSQLite接続を使用するため、通常、実行中のアプリケーションが抽出をブロックすることはありません。エラーが続く場合は、アプリケーションを終了してから、もう一度抽出を実行してください。

WindsurfまたはTraeで会話が0件になる

--listでアプリケーションディレクトリが見つかっていることを確認してください。見つかっているにもかかわらずチャットが抽出されない場合は、該当するstate.vscdbのキーを調べ、適切な抽出器のKEY_HINTSに一致するパターンを追加してください。

まとめ

AI Coding Assistant Data Extractionを使うと、多様なストレージ形式とオペレーティングシステムにまたがるローカルのコーディング会話を、依存関係なしで保存・正規化できます。まずpython extract.py --listを実行して必要なソースを選択し、生成されたJSONLに機密情報が含まれていないか確認してから、正規化されたレコードをバックアップ、分析、または慎重に準備したトレーニングワークフローに使用してください。

このツールキットは、自分のマシンにインストールしたAIツールのデータを対象としています。データを抽出する権利を有していること、機密情報を保護すること、各ツールの利用規約を遵守すること、そして結果を共有またはトレーニングに使用する前に秘密情報をスキャンすることは、利用者の責任です。