対象読者
- Copilot の Agent Mode を日常的に使っている人
- デバッグで「とりあえずエラーを貼って聞く」止まりの人
- Copilot が的外れなコードを読みに行って消耗した経験がある人
Copilot の設定ファイルの全体像は「GitHub Copilot の設定ファイル5種」を参照してください。
デバッグ調査をチャットから始めてないか
ども!龍ちゃんです。
バグ報告が来て、いつもみたいに Agent Mode のチャットに「このバグ調べて」と投げました。Copilot がファイルを次々読み始めて、待つ。関係なさそうなファイルまで読んでる。返ってきた分析は的外れだった。
「違う、そこじゃない」と追加で指示を出す。また読みに行く。また待つ。3ターン経っても全然進まない。結局自分でログ読んだ方が速かったんじゃないかと。精度を上げるためにPlanエージェントを使う手もあるんですけども、断続感がすごくて。
この体験、覚えがある人は多いんじゃないかなと思います。
なぜこうなるかというと、Plan エージェントがコードベースを広範囲に探索するからです。関係ないファイルまで読んでコンテキストウィンドウが埋まって、後半さらに精度が落ちる。「情報が足りないから広く探す」→「無駄な情報でコンテキストが埋まる」→「精度が落ちる」の悪循環です。
これ、Copilot が悪いんじゃなくて、渡し方の問題なんですよね。
じゃあどうするか。Copilot に投げる前に Issue.md を1枚書く。問題・仮説・関連パスを整理してから渡すだけで、探索範囲が絞られて初手から的確になります。
この記事では、Issue.md を起点にした Copilot デバッグワークフローを実践ベースで紹介していきます。
今回の内容です。
- Issue.md が効く2つの理由(思考の外部化とファイル起点のアクション)
- Issue.md を起点にしたデバッグの4ステップ
- 仮想シナリオで4ステップを走る実践例
- 人間がやること vs Copilot に任せることの役割分担
Issue.md でデバッグが変わる理由とフローの全体像
Issue.md とは
バグ発生時に、プロジェクトルートに一時的な調査ファイル(Issue.md)を作ります。Copilot に渡す前に、人間が先にコンテキストを整理するのがポイントです。
書くのは3つだけです。
- 発生している問題(何が起きているか、再現手順)
- 仮説(自分なりの原因予想)
- 関係するファイルのパス(Copilot の探索範囲を絞る)
テンプレートはこんな感じです。
# Issue: [バグの概要]
## 発生している問題
- 現象:[何が起きているか]
- 再現手順:[どうやったら起きるか]
## 仮説
- [自分なりの原因予想。わからなければ「わからないが○○が怪しい」でもOK]
## 関係するファイル
- `src/components/XXX.tsx`
- `src/hooks/useXXX.ts`3行・パス2〜3個で十分です。30秒で書ける量がちょうどいいです。
もちろん、詳しければ詳しいほど良いです!
仮説が浮かばないときは「わからないが、ここが怪しい」だけでも書いてください。完璧な仮説を書くのが目的じゃなくて、書くことで頭が整理されるのが本質です。「原因は○○かもしれない」と書こうとする過程で「いや、そもそも再現条件って何だっけ」みたいに思考が動き出す。それだけで Copilot への指示の質が変わります。
なぜこれが効くか
効く理由は2つあります。
理由1: 思考の外部化
チャットに「このバグ何?」と投げるのは、思考をスキップしてます。Issue.md を書く過程で「何が起きてるのか」「どこが怪しいのか」を自分の頭で一度整理する。この整理があるだけで、Copilot への指示の質が変わります。
「書くこと」が目的であって、「完璧なドキュメントを作ること」が目的じゃないです。
最終的に Issue.md に原因と対策までまとまるので、レポートを別途作る必要がない。振り返りもしやすいです。
理由2: ファイル起点で Copilot のアクションが変わる
チャットで口頭説明するのと、MD ファイルとして渡すのでは Copilot の挙動が違います。
チャットで「このバグ調べて」と言うと、Plan エージェントは「まずコードベースを探索しよう」から始めます。ファイルとして渡すと「このドキュメントに書かれたパスを読もう」から始まる。この初手の違いがでかいんですよね。
ファイルに関連パスが書いてあると、Copilot はそのパスから読み始める。探索範囲が絞られるので、コンテキストウィンドウを無駄に消費しない。後半まで精度が持続します。
このワークフロー自体は汎用的で、Claude Code でも同じパターンは使えます。ただ、Copilot の Agent Mode は Plan エージェントがファイル探索の範囲を広く取るため、スコープを絞る効果が特に大きいです。もちろんPlanエージェントを使わないパターンでも読み込ませることで精度が継続します。
Before/After: チャットで聞く vs Issue.md を渡す
具体的にどう変わるか、比較してみます。

Before(チャットで聞く):
あなた: APIリクエストが多重に走ってるバグを調べて→ Copilot がコードベース全体を探索 → 関係ないファイルまで読む → コンテキスト圧迫 → 的外れな分析が返ってくる
After(Issue.md を渡す):
あなた: @Issue.md このドキュメントを元に調査して→ Copilot が Issue.md に書かれた関連パスから読み始める → 初手から的を絞った分析が返ってくる
同じバグの調査なのに、初手の精度が全然違います。この差は Issue.md があるかないかだけで生まれます。
デバッグフローの全体像
Issue.md を起点にしたデバッグは、4ステップで進めます。

| ステップ | やること | 担当 |
|---|---|---|
| 1. Issue.md を書く | 問題・仮説・関連パスを整理 | 人間 |
| 2. Copilot に調査を依頼 | Issue.md ごと渡して的を絞った調査 | Copilot |
| 3. 仮説→検証→フィードバック | 人間が検証、Copilot が分析、を繰り返す | 人間 + Copilot |
| 4. 「なぜ直ったか」を確認 | 修正後に原因を言語化して次に備える | 人間 + Copilot |
次のセクションで、このフローを仮想シナリオで具体的に走らせてみます。
実践:仮想シナリオで4ステップを走る
ここからは、実際のバグ調査セッション(33ターン)を元に、仮想シナリオに置き換えて紹介していきます。ワークフローのパターンを伝えることが目的なので、プロジェクトの詳細は出しません。
仮想シナリオ: API リクエストの多重発火
ダッシュボード画面を開くと、同じ API リクエストが3〜4回飛んでいる。DevTools のネットワークタブで確認すると、同じエンドポイントへの GET リクエストが重複している。ユーザーから「画面の表示が遅い」と報告があった。
フロントエンドあるあるですね。useEffect の依存配列ミスで同じ API が複数回飛ぶやつ。
ステップ1: Issue.md を書く(問題整理)
バグ報告を受けたら、まず Issue.md を書きます。
# Issue: ダッシュボードの API 多重リクエスト
## 発生している問題
- ダッシュボード画面を開くと同じ API が3〜4回飛ぶ
- DevTools のネットワークタブで GET /api/dashboard が重複しているのを確認
- ユーザーから「表示が遅い」と報告あり
## 仮説
- useEffect の依存配列に不要な値が入っていて再実行されているのでは
- または、コンポーネントのマウント/アンマウントが繰り返されている可能性
## 関係するファイル
- `src/pages/Dashboard.tsx`
- `src/hooks/useDashboardData.ts`
- `src/components/DashboardWidgets.tsx`書くのに30秒もかかりません。ポイントは、Copilot に投げる前に自分の頭で一度整理することです。「DevTools で見た」「3〜4回飛んでる」「依存配列かマウントが怪しい」ーーこれだけ書いておくと、Copilot の初手が全然違ってきます。
ちなみにバックエンドの場合も同じです。関連パスがサービス層や DB アクセス層になるだけで、Issue.md のフォーマットはそのまま使えます。
裏付けとして、ログファイルなどを与えると仮説の質や検討の精度がぐっと上がります。
ステップ2: Copilot に調査を依頼する
Issue.md ごと Copilot に渡します。
@Issue.md このドキュメントを元に調査して。
関連ファイルを読んで、問題の原因候補を分析してほしい。分析結果は Issue.md に追記して。Issue.md に仮説と関連パスが書いてあるので、Copilot はコードベース全体を探索せずに的を絞った調査を始めます。Dashboard.tsx と useDashboardData.ts を読み込んで、useEffect の依存配列を確認して、原因候補を分析してくれる。
何も書かずに「このバグ直して」だと、ここで大量のファイルを読みに行ってコンテキストが溢れます。Issue.md がスコープの制約になっているわけです。
ここで「分析結果は Issue.md に追記して」と指示しているのがポイントです。Copilot の分析結果もチャットで受け取るんじゃなくて、最初から Issue.md に集約させる。こうすると調査の経緯がすべて1ファイルにまとまります。
Copilot が Issue.md に追記する内容はこんなイメージです:
## 調査結果(Copilot 追記)
- `useDashboardData.ts` の `useEffect` 内で `fetchData()` を呼んでいる
- 依存配列に `filters` オブジェクトが含まれている
- `filters` が毎回新しいオブジェクト参照を生成しているため、レンダリングごとに `useEffect` が再実行
- → API リクエストが多重に発生している原因仮説で「依存配列が怪しい」と書いておいたおかげで、Copilot がまさにそこにフォーカスして調査してくれたパターンですね。
ステップ3: 仮説→検証→フィードバックのサイクル
ここから人間と Copilot のキャッチボールが始まります。実際のセッションでは一番ターン数が多かったフェーズです。

人間が仮説を投げる:
filters の参照が変わってるのは分かった。
これって特定のウィジェットだけの問題?それとも全体で起きてる?手動検証して、結果を Issue.md に追記:
ここが大事なポイントです。検証結果をチャットに直接書くんじゃなくて、Issue.md に追記して Copilot に渡す。こうすると Copilot が Issue.md を起点に読み直してくれるので、調査のコンテキストが途切れません。
## 検証結果(追記)
- DevTools で確認、全ウィジェット共通で発生
- filters をコンソールで見たら毎回新しいオブジェクトが作られていた
- useMemo でメモ化すれば直る可能性あり
---copilot指示---
@Issue.md 検証結果を追記した。これを踏まえて原因と対策を分析して。分析結果も Issue.md に追記して。Copilot が分析結果を Issue.md に追記:
Copilot の分析結果もチャットで受け取るんじゃなくて、Issue.md に書かせます。こうすると調査の経緯がすべて1ファイルにまとまるので、後から振り返りやすい。
## 分析結果(Copilot 追記)
- [`useMemo`](https://react.dev/reference/react/useMemo) で `filters` をメモ化するのが正攻法
- ただし `DashboardWidgets.tsx` で `filters` を props として渡している箇所も確認が必要
- (コード差分を提示)人間がスコープを絞る:
サーバーサイドキャッシュの追加は今回は不要。
クライアント側の多重リクエスト防止だけでいい。ポイントは、人間が「ここを見ろ」「これは対応不要」を言うだけで Copilot の無駄な探索が激減することです。「DevTools で確認した結果はこうだった」「全ウィジェット共通だった」というランタイムデータは Copilot が自分では取れない。人間がデータを集めて、Copilot が分析する。この分業が回ると調査がスムーズに進みます。
原因が特定できたら、対応方針を決めるのは人間の仕事です。「useMemo でいく」「カスタムフックに切り出す」みたいに、2〜3パターンの実装案を出させて比較するのがお勧めです。
ステップ4: 「なぜ直ったか」を確認する
修正を適用して、リクエストが1回に収まったことを確認。ここで終わりにせずに、もう1ステップ入れます。
自分の理解が合ってるか確認したい。
filters オブジェクトが毎回新しい参照を生成していたので、
useEffect の依存配列チェックで「変わった」と判定されて再実行されていた。
useMemo でメモ化して参照を安定させたことで、不要な再実行がなくなった。
この理解で合ってる?自分の言葉で原因を言語化して投げて、Copilot に補足・整理してもらいます。
このステップを入れることで、「なんとなく直った」で終わらなくなります。(まさにAIを自分のために使うってフェーズですね。)
「修正して終わり」にしないのが大事です。「なぜ直ったか」を言語化することで、次の類似バグに備えられます。「Copilot チャット履歴から Instructions と SKILL.md を改善する3つの方法」で紹介した lessons ポストモーテムと同じ発想ですね。この理解確認を lessons ファイルに残しておくと、同じパターンのバグに二度ハマらなくなります。
人間がやること vs Copilot に任せること
ここまでの実践を踏まえて、役割分担を整理しておきます。33ターンのデバッグセッションから抽出した実績ベースの分担です。
人間がやるべきこと
| やること | 実践での例 |
|---|---|
| 初期ドキュメント作成 | ステップ1で Issue.md に問題・仮説・関連パスを記載 |
| スコープの制限 | 「サーバーサイドキャッシュは不要、クライアント側だけで」 |
| 手動検証 | DevTools でネットワークタブを確認、コンソールで filters の参照を確認 |
| ランタイムデータの取得 | HAR ファイル、ネットワークログ、ブラウザ上の実行時データ |
| 方針決定 | 対策案の選択(useMemo でいく) |
Copilot に任せること
| やること | 実践での例 |
|---|---|
| ドキュメントを元にしたコード調査 | ステップ2で Issue.md の関連パスからコードを読み込み |
| 複数ファイルの一括読み込み | Dashboard.tsx、useDashboardData.ts、DashboardWidgets.tsx を一度に確認 |
| 対策案の複数提示・比較 | useMemo、useCallback、カスタムフックへの切り出しを比較提示 |
| コード差分の生成 | 修正前/修正後の diff を出力 |
| 理解の補足・整理 | ステップ4で人間の言語化を検証・補足 |
特に重要なのは、AI が取得できないデータを人間が補完することです。ブラウザ上のランタイムデータ、認証が必要な API レスポンス、ネットワークログーーこれらは Copilot が直接アクセスできません。人間が取得して Issue.md に貼ることで、初めて Copilot の分析対象になります。
「人間がデータを集めて、AI が分析する」。この役割分担を意識するだけで、デバッグセッション全体の効率が変わります。
まとめ:Issue.md 1枚で変わること
「エラー貼って聞く」を「Issue.md 書いて渡す」に変えるだけで、Copilot の初手精度が上がります。
大事なのは3つだけです。
- 問題を書く(何が起きているか)
- 仮説を書く(わからなくてもいい、書こうとすることが大事)
- 関連パスを書く(Copilot の探索範囲を絞る)
30秒で書ける量で十分です。完璧なドキュメントを作ることが目的じゃなくて、自分の頭を整理して Copilot に的確な起点を渡すことが目的なので。
調査が終わった Issue.md は .gitignore に入れるか削除するか、運用は好みで構いません。コミットに残して調査経緯を追えるようにする派もいますし、一時ファイルとして使い捨てにする派もいます。
「修正して終わり」にしないことも大事です。「なぜ直ったか」まで確認して次に活かす。Issue.md → lessons → copilot-instructions.md / SKILL.md の流れが回ると、同じバグに二度ハマらなくなっていきます。この改善サイクルの詳細は「Copilot チャット履歴から Instructions と SKILL.md を改善する3つの方法」で紹介しているので、合わせて見てもらえると。
まずは次のバグで Issue.md を1枚書いてみてください。
ほなまた〜


