Copilot Chat の会話履歴を Markdown で変換・保存:20,000行→720行

対象読者

  • Copilot Chat(特に Agent Mode)を日常的に使っている人
  • やりとりの記録を残したい・チームで共有したい人
  • Agent Skills の実践的な使い方を知りたい人

Agent Skills の基本(ディレクトリ構造、SKILL.md の書き方)は「【2026年版】Agent Skills 入門」を参照してください。

併せて読みたい:Copilot チャット履歴から copilot-instructions.md と SKILL.md を育てる方法

Copilot Chat、使い捨てにしてませんか?

ども!龍ちゃんです。

GitHub Copilot のチャット履歴って、UIがあるおかげで会話の復帰はしやすいですよね。でも、「あのとき何をどう指示したっけ?」みたいな目的で履歴を見返すことって、あんまりないんじゃないでしょうか。

実は!Skillsやpromptみたいなファイルを作るにあたっては、履歴は宝庫なんです。

VS Code には「Chat: Export Chat…」というエクスポート機能があります。ただ、出力されるのは JSON。実際にエクスポートしてみると、6ターンの会話が 20,347行 の JSON になります。こういうやつです:

{
  "responderUsername": "GitHub Copilot",
  "requests": [
    {
      "message": {
        "text": "読み込まれているSkill一覧を取得することは可能ですか?"
      },
      "response": [
        {
          "kind": "thinking",
          "value": "ユーザーは「読み込まれているSkill一覧を取得することは可能ですか?」と聞いています...",
          "generatedTitle": "Reviewed skill information and considered directory structure"
        },
        {
          "kind": "toolInvocationSerialized",
          "toolSpecificData": {
            "kind": "terminal",
            "commandLine": { "original": "ls .claude/skills/" },
            "terminalCommandState": { "exitCode": 0, "duration": 50 }
          },
          "toolId": "list_dir"
        },
        { "value": "はい、可能です。現在読み込まれているSkill一覧を表示します..." }
      ],
      "modelId": "copilot/claude-sonnet-4.5",
      "result": { "timings": { "totalElapsed": 34900 } }
    }
  ]
}

テキスト応答、思考過程、ツール呼び出しが response[] に混在している。20,000行の JSON から必要な情報を拾うのは現実的ではない。(というか人間が読むのは無理ですわ)

本記事では、この JSON を CLI 1行で Markdown に変換する方法を紹介します。先ほどの 20,347行の JSON は 720行の Markdown に変換されます。情報量はほぼそのまま、行数は 96.5%削減 です。

BeforeAfter
形式JSON(20,347行)Markdown(720行)
可読性エディタでも厳しいそのまま読める
ツール呼び出しtoolInvocationSerialized の入れ子ファイル名 + diff 表示
思考過程kind: "thinking" を JSON の中から探す<details> 折りたたみ
コンテキスト参照variableData の巨大なオブジェクトReferenced Context リスト

VS Code の Export Chat 機能

手順はシンプルなんですが、一応確認しておきますね。

  1. VS Code で Copilot Chat パネルを開く
  2. コマンドパレット(Ctrl+Shift+P / Cmd+Shift+P)を開く
  3. Chat: Export Chat…」を選択
  4. 保存先を指定 → JSON ファイルが出力される

操作はこれだけです。問題はこの JSON の中身で、次で何が入っているかを整理していきますね。


Export JSON に何が入っているか:情報の棚卸し

「何を保存できるか」が分からないと、ツールを使う気にもならないですよね。まず export JSON に何が入っているかを整理していきます。

含まれる情報の一覧

カテゴリ含まれる情報実際の例(今回のサンプル)
会話テキストユーザーの入力、Copilot の応答「読み込まれているSkill一覧を取得することは可能ですか?」→ スキル13個のリストを返答
モデル情報使用モデル ID(ターンごと)copilot/claude-sonnet-4.5
応答時間各ターンの応答ミリ秒totalElapsed: 34900(34.9秒)
思考過程Thinking ブロック(モデルを問わず記録)思考テキスト + 生成タイトル。内容の詳細度はモデルにより異なる
ツール呼び出しファイル読み書き、ターミナル実行の記録list_dir, read_file, grep_search, run_in_terminal
コンテキスト参照チャットに渡したファイル、ワークスペース@workspace, prompt:copilot-instructions.md, prompt:CLAUDE.md
スキル一覧Copilot に読み込まれたスキル定義<skills> タグ内に13個のスキル名とファイルパス
エラー情報レート制限、キャンセル等Canceled(Turn 6)
エージェント情報Agent Mode の種別agent, modes: ["agent"]

今回のサンプル(6ターンのスキル発火テスト)だけでも、これだけの情報が JSON に詰まっています。

なぜ読みにくいか:情報の分散とノイズ

JSON が読みにくい理由は、サイズだけではありません。構造上の問題が3つあります。
まあそもそも生の JSON は人間が読む想定で設計されてないんですけどねw

1. ツール呼び出しの情報が2箇所に分散している

  • response[] 内の toolInvocationSerialized → ターミナル出力、exit code、所要時間
  • result.metadata.toolCallRounds → ツール名、引数(ファイルパス、検索クエリ等)

同じツール呼び出しの情報を2箇所から突き合わせないと全体像が見えません。

2. テキスト応答とツール呼び出しが混在している

response[] 配列の中に、テキスト応答(kind なし)、思考過程(kind: "thinking")、ツール呼び出し(kind: "toolInvocationSerialized")、インライン参照(kind: "inlineReference")がフラットに並んでいます。

3. VS Code 内部用のノイズが混ざっている

mcpServersStartingprogressTaskSerializedprepareToolInvocation など、ユーザーに関係ないイベントが response[] に含まれます。今回のサンプルでも Turn 1 の先頭に mcpServersStarting が入っていました。

さらに、コンテキスト参照の variableData には devcontainer のフルパスが Base64 エンコードで入っており、1つの変数定義だけで数十行を消費します。20,347行のうち相当部分がこのノイズです。

変換ツールで保存される情報 / されない情報

変換ツール copilot-chat-converter が何を残して何を落とすか、整理しておきますね。ここは個人・チームの判断で何を残すかという判断が必要かなって思います。

情報保存変換後の表示
会話テキスト(全文)User / Copilot セクション
モデル IDターンごと + ヘッダーに最頻モデル
応答時間人間可読に変換(34.9s500ms1m 30.0s
Thinking(思考過程)<details> 折りたたみ(タイトル付き)
ツール呼び出し(名前・引数)Tool Calls セクション(ファイルパス抽出)
ファイル書き込みdiff ブロック(<details> 折りたたみ)
ターミナル実行コマンド + exit code + 出力
コンテキスト参照Referenced Context リスト
エラー情報blockquote で表示(> **Error**: Canceled
ツール出力(長文)500文字超は末尾を切り詰め
VS Code 内部イベント×ノイズとしてスキップ
空の Thinking ブロック×vscodeReasoningDone マーカーをスキップ
ANSI エスケープコード×除去(ターミナル出力のカラーコード等)
devcontainer パス情報×ワークスペースプレフィックスを除去

まとめると: 会話の記録として必要な情報はほぼ全部入ってます。落ちるのは VS Code 内部のノイズと、長すぎるツール出力の末尾だけですね。


copilot-chat-converter:JSON → Markdown 変換

というわけで、エクスポートした JSON を Markdown に変換してくれる CLI ツールを作りました。Python + Click で実装し、実行には uv を使っています。SKILL.md もセットで用意しているので、後で出てくるワンコマンド化の話まで使えます。

自分の環境で再現したい方へ

既存の変換ツールとしては copilot-chat-to-markdown(Python スクリプト、スター106)があります。基本的なチャットとツール呼び出しの変換に対応しているので、まずはこちらを試してみるのがお手軽です。ただし Thinking ブロックや Agent Mode のファイル操作 diff には未対応なので、今回はそこまで含めて変換したくて自作しました。

本記事のツールは pip パッケージとしては公開していませんが、設計書(plan.md)と実装手順(action-plan.md)を Gist で公開しています。お手元の AI コーディングエージェントに読み込ませれば同等のツールを実装できるので、既存ツールと見比べながら自分の用途に合ったものを作ってみてください。

基本的な使い方

# 標準出力に変換結果を表示(内容確認用)
uv run copilot-chat-converter chat.json

# ファイルに出力
uv run copilot-chat-converter chat.json -o chat.md

ファイル出力時のターミナル表示:

🚀 copilot-chat-converter 起動
📝 処理対象: 1 ファイル

📄 処理中: chat.json
  ✅ 保存完了: chat.md

-o を省略すると標準出力に Markdown がそのまま出ます。パイプで他のコマンドに渡したいときに便利です。

複数ファイルの一括変換

定期的にエクスポートしてると JSON がどんどん溜まっていくんですよね。ディレクトリを指定すれば一括変換できます:

uv run copilot-chat-converter exports/*.json -o docs/chats/

出力ディレクトリが存在しない場合は自動作成されます。各 .json が同名の .md に変換されます(chat-2026-03-04.jsondocs/chats/chat-2026-03-04.md)。1件でエラーが出ても他のファイルの処理は継続します。

オプション一覧

オプション短縮形説明デフォルト
--output-o出力先(ファイルまたはディレクトリ)標準出力
--quiet-q進捗メッセージを非表示表示する
条件動作
-o なし、1ファイル標準出力(進捗メッセージは自動で抑制)
-o なし、複数ファイルエラー(出力先を明示してください)
-o ファイル名指定ファイルに出力
-o ディレクトリ/各 JSON を同名の .md として出力

変換結果の読み方:何がどう変わるか

さっき整理した JSON の中身が、実際にどう変換されるかを見ていきますね。以下はぜんぶ、先ほどの6ターンのチャットを変換した実際の出力です。

基本構造

ヘッダーにセッション全体のメタデータが入っていて、その下にターンごとの User / Copilot のやりとりが並ぶ構造です。

# Copilot Chat Session

## Metadata

- **Exported**: 2026-03-04 05:30:28 UTC
- **Model**: copilot/claude-sonnet-4.5
- **Total Turns**: 6
- **Requester**: (unknown)
- **Responder**: GitHub Copilot

---

## Turn 1

### User

読み込まれているSkill一覧を取得することは可能ですか?

### GitHub Copilot

**Model**: copilot/claude-sonnet-4.5 | **Response Time**: 34.9s

はい、可能です。現在読み込まれているSkill一覧を表示します。
  • Model: 全ターンで最も多く使われたモデルをヘッダーに表示、ターンごとの使用モデルも記載
  • Response Time: ミリ秒を人間可読に変換(34900ms34.9s

思考過程(Thinking)→ 折りたたみ

Agent Mode では、Copilot の思考過程が kind: "thinking" として記録されるんですね。Claude Sonnet 4.5、GPT-5.3-Codex、GPT-5 mini いずれのモデルでも確認できました。思考の詳細度はモデルによって違いますが、変換ツールはどのモデルでも同じ形式で表示してくれます。変換後は <details> で折りたたまれます:

<details><summary>Thinking: Reviewed skill information and considered directory structure</summary>

ユーザーは「読み込まれているSkill一覧を取得することは可能ですか?」と聞いています。

現在のコンテキストを見ると、システムプロンプトに以下のセクションがあります:
...

このSkill一覧をユーザーに提供できます。また、`.claude/skills/` ディレクトリの
内容をリストすることもできます。

</details>

折りたたみなので普段は邪魔にならず、「なぜ Copilot がその行動を取ったか」を確認したいときだけ展開できます。

今回のサンプルでは6ターン中に 10個の Thinking ブロック が含まれていました。JSON ではこれらが response[] 配列の中に埋もれていますが、Markdown では見出し付きの折りたたみとして整理されます。なお、VS Code が挿入する空の Thinking ブロック(vscodeReasoningDone: true のマーカー)は自動的にスキップされます。

モデルによる Thinking の違い: Claude モデルでは思考過程の全文がプレーンテキストで記録されます。GPT-5.3-Codex ではタイトル的な短文が記録され、詳細は暗号化されています。GPT-5 mini でも Thinking ブロックは記録されますが、内容は空のケースがあります。変換ツールはいずれも <details> 折りたたみとして表示し、利用可能な情報をすべて出力します。

ツール呼び出し → Tool Calls + File Operations

Agent Mode のツール呼び出しは2つのセクションに整理されます。

Tool Calls: 個々のツール呼び出しの詳細

#### Tool Calls

**1.1. list_dir** `.claude/skills`

File Operations: ファイル操作のサマリー

#### File Operations

**Read** (2 files):
- `docs/features/copilot-agent-skills-gh-actions/action-plan.md`
- `docs/features/copilot-agent-skills-gh-actions/verification-log.md`

書き込み系のツール呼び出し(create_file, replace_string_in_file 等)がある場合は diff 形式で表示されます:

**3.2. replace_string_in_file** `src/utils.py`

<details><summary>Diff (4 lines)</summary>

​```diff
- def old_function():
-     pass
+ def new_function():
+     return True
​```

</details>

読み取り系は File Operations にまとめて、書き込み系は diff で詳細を見せる形です。この分離のおかげで、ログが長くなっても見通しが保たれるんですよね。

ターミナル実行 → コマンド + exit code + 出力

run_in_terminal によるターミナル実行は、コマンド・exit code・出力をセットで表示します:

**5.1. run_in_terminal**
- Explanation: `最新10件のワークフロー実行状態を取得`
- Command: `gh run list --limit 10 --json databaseId,name,status,conclusion,createdAt,headBranch ...`

ツール出力が500文字を超えると末尾が切り詰められます。ターミナルの ANSI カラーコードは自動で除去してくれるので、コピペしても化けないのは地味に助かりますね。

ツール分類の一覧

変換ツールは内部でツールを3種類に分類し、それぞれ適切な表示形式を適用します。

分類ツール例表示形式
読み取りread_file, list_dir, grep_search, file_searchFile Operations にまとめ表示
書き込みcreate_file, replace_string_in_file, insert_text_in_filediff ブロック(<details> 折りたたみ)
ターミナルrun_in_terminalコマンド + exit code + 出力(500文字で切り詰め)

ワークスペースのパスプレフィックス(/workspaces/repo-name/)も自動で除去してくれます。ファイルパスが長くて読みにくいのはストレスなので、ここは地味に重要ですね。


Agent Skills でワンコマンド化:「チャット変換して」

なぜ SKILL 化するか

CLI コマンドは覚えれば使えますが、毎回 uv run copilot-chat-converter ... と打つのは正直だるいんですよね。SKILL.md に組み込めば:

  • 「チャット変換して exports/chat.json」の1行で完了
  • ファイルパスの指定もチャットの中でできる
  • CLI のオプションを覚えなくていい

CLI ツールを Agent Skills でラップするのは結構汎用的なパターンで、覚えておくと便利です。

gh CLI × Claude Code でブラウザなし GitHub 操作を実現する」で gh CLI を Skills でラップする設計思想を解説しており、その実践編として、以下の記事があります。。既存の CLI があるなら、SKILL.md を書くだけで「チャットから呼べるツール」になります。

GitHub Copilot 版 SKILL.md

GitHub Copilot の SKILL.md では description: |(YAML の複数行記法)を使うと発火しない問題があります。「Claude CodeからGitHub Copilotへ移植したらAgent Skillsが動かない?原因と解決策」で検証結果と回避策を詳しく解説しているので、Copilot 向けにスキルを書く場合は必ず確認してください。

.github/skills/copilot-chat-converter/
├── SKILL.md                    ← ~500トークンに収める
└── references/
    └── output-format.md        ← 詳細仕様(必要時に Copilot が読み込む)

.github/skills/copilot-chat-converter/SKILL.md に配置します。抜粋:

---
name: copilot-chat-converter
description: "CRITICAL: Copilot Chat JSONをMarkdownに変換。MANDATORY: チャット変換, チャット履歴, JSONをMarkdownに, チャットエクスポート。VS CodeのExport ChatのJSONを読みやすいMarkdownに変換。"
---
# Copilot Chat Converter

## When to Use
- ユーザーが「チャット変換して」「chat.json を変換」と言ったとき
- `.json` ファイルのパスと変換の指示が与えられたとき

## Quick Start

​```bash
uv run copilot-chat-converter chat.json -o output.md
​```

ポイント:

  • descriptionCRITICAL / MANDATORY を入れて発火を安定させる
  • description: |(パイプ)は使わない。複数行記法だと各行が別の属性として誤解釈され、description が空になって発火しません。必ず description: "..." の単一行で書きます。実際にこのスキルの初版でもこの問題を踏みました
  • SKILL.md 本体は Copilot の ~500 トークン制限に収める。詳細なフォーマット仕様は references/output-format.md に分離

Claude Code 版 SKILL.md

.claude/skills/copilot-chat-converter/SKILL.md に配置します。抜粋:

---
name: copilot-chat-converter
description: |
  GitHub Copilot ChatのエクスポートJSON形式をMarkdownに変換するスキル。
  "チャット変換して", "chat.jsonを変換", "Copilot Chatをマークダウンに",
  "JSONをMarkdownに", "/copilot-chat-converter" の場合に使用。
allowed-tools: Read, Bash
---

Claude Code 版はトークン制限が緩いため、出力の解釈方法やエラーハンドリングまで SKILL.md 本体に書けます。allowed-tools でスキルが使えるツールを明示的に制限するのも Claude Code 固有の機能です。

SKILL.md の全文、設計書(plan.md)、実装手順(action-plan.md)、出力形式リファレンスは Gist にまとめて公開しています。自分で同様のツールを作りたい方は参考にしてください。

Copilot 版 / Claude Code 版の違い

同じ CLI ツールをラップしていますが、スキル定義は各ツールの特性に合わせて変える必要があります。

GitHub Copilot 版Claude Code 版
配置場所.github/skills/.claude/skills/
descriptionCRITICAL / MANDATORY キーワード必須自然言語で記述
トークン制限~500トークン(references/ で分離)緩い(全文書ける)
allowed-tools記載なし(Copilot が自動判断)明示的に指定
発火条件description のキーワードマッチdescription + 自然言語理解
詳細仕様references/ に分離して Progressive Loading本体に含めてOK

両方に配置しておけば、Claude Code と VS Code Copilot のどちらからでも「チャット変換して」で同じ操作ができます。設定ファイルの共存パターンについては「Claude Code→GitHub Copilot移行で使える設定ファイル6つの対応表」を参照してください。

ちなみに GitHub Copilot は .claude/skills/ も参照できるので、Claude Code 版だけ作っておけばスラッシュコマンド(/copilot-chat-converter)で Copilot からも呼べます。両方書くのが面倒な人はまず Claude Code 版だけでOKです。


まとめ

Copilot Chat の会話を保存する流れをおさらいしておきますね。

  1. エクスポート: VS Code の「Chat: Export Chat…」で JSON を取得
  2. 情報の確認: export には会話テキスト・思考過程・ツール呼び出し・コンテキスト参照まで含まれている
  3. 変換: uv run copilot-chat-converter chat.json -o chat.md で Markdown に変換(20,000行 → 720行)
  4. ワンコマンド化: SKILL.md を配置して「チャット変換して」で完了

変換ツールは Agent Mode のツール呼び出し(diff 表示付き)、思考過程(Thinking)の折りたたみ表示、ファイル操作サマリーまで対応してます。VS Code 内部のノイズは自動で除去されて、必要な情報だけが残る感じです。

まずは1回エクスポートして変換してみてください。「こんなに情報が入っていたのか」と驚くはずです。(同時に履歴が長くてびっくりすると思います)

保存した会話履歴を copilot-instructions.md や SKILL.md の改善にフィードバックする方法は、次の記事で解説しますね。

ほなまた〜

実装リファレンス: 設計書・実装手順・SKILL.md 全文・出力形式リファレンスは Gist にまとめて公開しています。

ご覧いただきありがとうございます! この投稿はお役に立ちましたか?

役に立った 役に立たなかった

0人がこの投稿は役に立ったと言っています。
エンジニア募集中!

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です