対象読者
- 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%削減 です。
| Before | After | |
|---|---|---|
| 形式 | JSON(20,347行) | Markdown(720行) |
| 可読性 | エディタでも厳しい | そのまま読める |
| ツール呼び出し | toolInvocationSerialized の入れ子 | ファイル名 + diff 表示 |
| 思考過程 | kind: "thinking" を JSON の中から探す | <details> 折りたたみ |
| コンテキスト参照 | variableData の巨大なオブジェクト | Referenced Context リスト |
VS Code の Export Chat 機能
手順はシンプルなんですが、一応確認しておきますね。
- VS Code で Copilot Chat パネルを開く
- コマンドパレット(
Ctrl+Shift+P/Cmd+Shift+P)を開く - 「Chat: Export Chat…」を選択
- 保存先を指定 → 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 内部用のノイズが混ざっている
mcpServersStarting、progressTaskSerialized、prepareToolInvocation など、ユーザーに関係ないイベントが response[] に含まれます。今回のサンプルでも Turn 1 の先頭に mcpServersStarting が入っていました。
さらに、コンテキスト参照の variableData には devcontainer のフルパスが Base64 エンコードで入っており、1つの変数定義だけで数十行を消費します。20,347行のうち相当部分がこのノイズです。
変換ツールで保存される情報 / されない情報
変換ツール copilot-chat-converter が何を残して何を落とすか、整理しておきますね。ここは個人・チームの判断で何を残すかという判断が必要かなって思います。
| 情報 | 保存 | 変換後の表示 |
|---|---|---|
| 会話テキスト(全文) | ○ | User / Copilot セクション |
| モデル ID | ○ | ターンごと + ヘッダーに最頻モデル |
| 応答時間 | ○ | 人間可読に変換(34.9s、500ms、1m 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.json → docs/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: ミリ秒を人間可読に変換(
34900ms→34.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_search | File Operations にまとめ表示 |
| 書き込み | create_file, replace_string_in_file, insert_text_in_file | diff ブロック(<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 を書くだけで「チャットから呼べるツール」になります。
- 「gh CLI × Claude Code で Gist 操作をチャット1行で完結させる」で Gist 操作
- 「GitHub Actions 失敗ログ、まだ手動で読む?Copilot Agent Skills で CI デバッグを自動化する実装ガイド」で CI デバッグ
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
```ポイント:
descriptionにCRITICAL/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/ |
| description | CRITICAL / 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 の会話を保存する流れをおさらいしておきますね。
- エクスポート: VS Code の「Chat: Export Chat…」で JSON を取得
- 情報の確認: export には会話テキスト・思考過程・ツール呼び出し・コンテキスト参照まで含まれている
- 変換:
uv run copilot-chat-converter chat.json -o chat.mdで Markdown に変換(20,000行 → 720行) - ワンコマンド化: SKILL.md を配置して「チャット変換して」で完了
変換ツールは Agent Mode のツール呼び出し(diff 表示付き)、思考過程(Thinking)の折りたたみ表示、ファイル操作サマリーまで対応してます。VS Code 内部のノイズは自動で除去されて、必要な情報だけが残る感じです。
まずは1回エクスポートして変換してみてください。「こんなに情報が入っていたのか」と驚くはずです。(同時に履歴が長くてびっくりすると思います)
保存した会話履歴を copilot-instructions.md や SKILL.md の改善にフィードバックする方法は、次の記事で解説しますね。
ほなまた〜
実装リファレンス: 設計書・実装手順・SKILL.md 全文・出力形式リファレンスは Gist にまとめて公開しています。


