こんにちは、CLI の中身が気になって app.js を grep しちゃうアーキテクトのやまぱん!です 😊
今回は GitHub Copilot CLI のインストールツリーをローカルで開けて、「組み込みのサブエージェントってどこで定義されてるの?」を確かめた話です。
TL;DR
- GitHub Copilot CLI のインストールツリー (
~/.copilot/pkg/<platform>/<version>/) を開けると、definitions/配下にサブエージェント定義の YAML が 7 本、definitions/sidekick/に裏方エージェントの YAML が 4 本 入っています。 - 「
/research」はdefinitions/research.agent.yamlという YAML 定義で動いていますが、「/fleet」は YAML ではなくapp.jsの中に 長文プロンプトとしてハードコード されていて、schemas/api.schema.jsonのsession.fleet.startという RPC method から呼び出される仕組みでした。 - 上位には **「振る舞いモード」**という軸があり、
AgentMode = interactive / plan / autopilotの enum。autopilotはtask_completeまで止まらずに走るモードで、その中でさらに/fleetを発動すると todos テーブルを使った並列消化サブモードに入ります。これとは別軸で サブエージェント(/researchなどdefinitions/*.agent.yaml7 本 +sidekick/*4 本)が並んでいて、この 2 軸構造が見えました。 - ついでに tree-sitter (17 言語の
.wasm)、voice 入力エンジン、ripgrep/tgrep、builtin/customize-cloud-agent/SKILL.mdまで丸ごと同梱されていました。
[!NOTE]
この記事の観察結果は@github/copilotv1.0.64-1(gitCommit6c5be1e)時点のものです。CLI は頻繁に更新されるので、構造は将来変わる可能性があります。package.jsonのversionを見て確認してください。
なんでこんなことしたの
きっかけは「自分が .agent.md で書いてるカスタムエージェントみたいに、Copilot CLI の組み込みエージェントも YAML で定義されてるのかな?」という素朴な疑問でした。
普段 VS Code の Copilot Chat 側ではユーザー定義の .agent.md / .instructions.md / SKILL.md をたくさん書いていて、「組み込みの /research や /fleet も同じ感覚で外出しされてるんじゃないか」と気になっていたんです。
ある日「リサーチって YAML で定義されてる?」と Copilot 自身に聞いてみたところ、ローカルにインストールされた CLI 本体を実地で開けてくれて、definitions/research.agent.yaml というファイルがあることを教えてくれました。「あ、やっぱり YAML で書かれてるんだ!」となって、ついでに pkg/ 配下を全部覗いてみたら想像以上にいろいろ詰まっていた、というのがこの記事のきっかけです。
(結論を先に言うと、/research は予想どおり YAML 定義だったけど、/fleet は YAML じゃなくてコード内ハードコードだった、という非対称な作りが見えました。詳しくは後半で。)
なお、後述するように Copilot CLI 本体は 修正・派生物作成・再配布が禁止されているので、この記事ではあくまで「設計を理解するための短い抜粋」に留めて、長文プロンプトの丸ごと転載は避けています。
どこを開けたの
私の環境(Windows 11 / npm 経由インストール)では次のパスでした。
~/.copilot/pkg/<platform>/<version>/
実体は C:\Users\<ユーザー名>\.copilot\pkg\win32-x64\1.0.64-1\ でした。macOS / Linux の場合は <platform> 部分が darwin-arm64 や linux-x64 などに変わると思います(package.json の optionalDependencies を見るとプラットフォーム別 package が網羅されているのが分かります)。
[!NOTE]
細かい話: Copilot CLI のインストール先は%USERPROFILE%\.copilot\(=C:\Users\<user>\.copilot\)です。%APPDATA%(=C:\Users\<user>\AppData\Roaming\)ではないので、%APPDATA%\.copilotを探しても見つかりません。本記事のコマンド例では PowerShell の$HOMEを使っていますが、Windows 環境変数に揃えたい人は$env:USERPROFILE\.copilot\...と読み替えてください。
[!IMPORTANT]
このフォルダは 読み取り専用で扱ってください。CLI 本体の LICENSE(後述)で修正・派生物作成は禁止されています。
pkg ディレクトリ全景
Get-ChildItem で覗いた構成を機能ごとに整理するとこうなります。
| グループ | 主なファイル / フォルダ | 役割 |
|---|---|---|
| 本体 |
app.js (約 8.5 MB), index.js, npm-loader.js, sea-loader.js
|
CLI のメインロジック |
| エージェント定義 |
definitions/*.agent.yaml, definitions/sidekick/*.yaml
|
サブエージェントと裏方エージェントの YAML |
| API スキーマ |
schemas/api.schema.json, schemas/session-events.schema.json
|
クライアント↔サーバの RPC 型定義 |
| 組み込み Skill |
builtin/, builtin-skills/
|
Copilot cloud agent カスタマイズ用 SKILL.md |
| コード解析 |
tree-sitter*.wasm (17 言語), queries/*-highlights.scm
|
grep / view の構文認識 |
| 検索エンジン |
ripgrep/, tgrep/
|
コードベース検索バックエンド |
| 音声入力 |
voice-server.js, voice-engine.worker.js, voice-installer.worker.js, pvrecorder/
|
音声入力一式 |
| SDK 群 |
sdk/, copilot-sdk/, foundry-local-sdk/
|
クライアント SDK |
| その他 |
clipboard/, prebuilds/, mxc-bin/, worker/, preloads/, conpty_console_list_agent.js
|
ネイティブバインディング・ターミナル制御 |
| メタデータ |
LICENSE.md, package.json, changelog.json (約 628 KB) |
ライセンス・バージョン・履歴 |
「CLI ツール」と聞いて想像するサイズより、だいぶ大きいですね。tree-sitter で 17 言語ぶんの .wasm を抱え、音声入力エンジンや 8 MB を超える本体まで含めて、ひとつの自己完結したランタイムになっています。
図にすると、こんな感じで「本体 + 定義 + ランタイム部品 + メタデータ」の 4 つのレイヤに分かれて見えます。
definitions/ の正体 — サブエージェント 7 本
definitions/ 直下には次の 7 本 の *.agent.yaml が並んでいました。
| name | model | tools | 役割 |
|---|---|---|---|
research |
claude-sonnet-4.6 |
GitHub MCP + web_fetch + web_search + grep / glob / view
|
リサーチ専用。検索並列 3-5、fetch 並列 10-15、Cite 必須 |
code-review |
(動的選択) |
*(全部) |
バグ・セキュリティ・ロジックエラーだけを surface する高 S/N レビュー |
explore |
claude-haiku-4.5 |
grep / glob / view / bash / powershell / lsp + GitHub MCP (read-only) |
別 context window で codebase を高速探索。並列呼び出し安全 |
rem-agent |
(動的選択) |
context_board のみ |
session trajectory を読んで dynamic context board を add / prune。/subconscious run から起動 |
rubber-duck |
(動的選択) |
*(全部) |
提案・設計・実装・テストへの建設的批判 (devil's advocate) |
security-review |
(動的選択) |
*(全部) |
11 vuln category を確信度 >80% でだけ flag。false positive 最小化 |
task |
claude-haiku-4.5 |
*(全部) |
dev コマンド(test / build / lint / format)実行。成功時要約・失敗時全出力で main context を汚さない |
注目ポイントを 3 つ。
1. モデル指定の戦略が役割ごとに違う
-
researchだけclaude-sonnet-4.6で固定。リサーチは品質重視、ということだと思います。 -
exploreとtaskはclaude-haiku-4.5固定。高速 + 安いモデルで「外に切り出して並列で回す」用途に最適化されていますね。 -
code-review/rubber-duck/security-reviewはモデル指定なし=ユーザーが現在使っているモデルを継承する設計。レビュー系は「メインで使ってるモデルにそのまま見せたい」という意図に見えます。
2. tools: "*" という潔さ
code-review / rubber-duck / security-review / task は tools: "*" で全ツール許可。一方で research / explore / rem-agent は使えるツールを 明示列挙 していて、ツールスコープを絞っています。これはセキュリティの最小権限原則というより、「迷わせない」「並列度を上げやすくする」ための割り切りに見えました。
3. promptParts という共通ヘッダー
どの YAML にも promptParts: というセクションがあって、トグルでプロンプトのプリセット断片を on/off できる作りでした。たとえば research.agent.yaml だとこうです。
promptParts:
includeAISafety: true
includeToolInstructions: true
includeParallelToolCalling: true
includeCustomAgentInstructions: false
includeCustomAgentInstructions: false がデフォルトなので、これらのサブエージェントは ユーザーが用意した AGENTS.md などのカスタム指示を読まない設計 になっているのが分かります。サブエージェントはタスクを綺麗にこなしてほしいので、外部の指示で挙動が揺れないようにしている、ということだと思います。他のサブエージェントだと includeEnvironmentContext, includeDynamicContextBoard, includeConsolidationPrompt などのフラグも顔を出します(subconscious-agent は前者の 1 つだけ true、他は全部 false にしてプロンプトを極小化していました)。
深掘り 1: research.agent.yaml
research の中身がいちばん「設計の意図」が読み取れたので、ポイントだけ抜粋します(全文転載は避けます)。
name: research
displayName: Research Agent
model: claude-sonnet-4.6
tools:
- github-mcp-server/get_file_contents
- github-mcp-server/search_code
- github-mcp-server/search_repositories
# ...issue / PR 系も含めて GitHub MCP を一通り...
- web_fetch
- web_search
- grep
- glob
- view
promptParts:
includeAISafety: true
includeToolInstructions: true
includeParallelToolCalling: true
includeCustomAgentInstructions: false
prompt: |
# ...
# Discovery phase: parallel search 3-5 max (GitHub rate-limit ~30/min)
# Deep-dive phase: get_file_contents を 10-15 並列で fetch
# READMEs はディスカバリ用、深掘りは個別ファイル
# Cite format: `org/repo:path/to/file.ext:line-range` 必須
# Work autonomously — do NOT ask questions
ここから読める設計判断は次のとおりです。
- 二相モデル (Discovery → Deep-dive) を最初からプロンプトに刻んでいる。search で当たりをつけたら止めて、fetch に切り替える、というワークフローを LLM 任せにせず明文化。
-
並列数を「3-5」「10-15」と具体的に指定。GitHub API のレートリミット (
~30/min) を理由として明記しているのが渋い。 -
Cite フォーマットを
org/repo:path/to/file.ext:line-rangeで固定。これが守られているから後段のオーケストレーターが結果を機械的にハンドリングしやすくなるわけですね。 -
Work autonomously — do NOT ask questions。サブエージェントは中断せず最後まで走る前提。
このプロンプト、後述する /fleet のハードコードプロンプトと比べると、サブエージェント定義は YAML で外出ししたほうが reload / 編集しやすいから外出ししている、という意図が透けて見えます。
深掘り 2: sidekick/subconscious-agent.yaml
definitions/sidekick/ という別フォルダには、裏方エージェントが 4 本入っていました。サブエージェントとは別系統で動くワーカー群です。
| name | model | 特徴 |
|---|---|---|
subconscious-agent |
[claude-haiku-4.5, gpt-5-mini] |
dynamic context board を読んで関連 item を main agent の inbox に concat 送信。featureFlag COPILOT_SUBCONSCIOUS
|
github-context |
[claude-haiku-4.5, gpt-5.4-mini] |
GitHub MCP + read_memories + session_store_sql で外部 context を集めて inbox に 1 件以下 (<=500 chars) だけ送る。featureFlag GITHUB_CONTEXT_SIDEKICK_AGENT
|
test-sidekick-persistent |
同上 | E2E テスト用 (behavior: persistent) |
test-sidekick-restart |
同上 | E2E テスト用 (behavior: restart) |
サブエージェント本体には無い、sidekick: というトップレベルセクションが付いているのがポイントです。
sidekick:
triggers:
- user.message
cancelOnNewTurn: true
maxSendsPerTurn: 1
featureFlag: COPILOT_SUBCONSCIOUS
launchConditions:
- launchSubconscious
-
triggers: [user.message]— ユーザーが何か送ったタイミングで自動的に起動。 -
cancelOnNewTurn: true— 次のターンが来たら走行中のものを止める。 -
maxSendsPerTurn: 1— 1 ターンで inbox に 1 通だけ。 -
featureFlag— 環境変数フラグで全体オフにできる。
そして、subconscious-agent の動作はかなり厳格で「context board のサマリを読む → 関連する item を context_board command:"get" で取得 → そのまま verbatim concat して send_inbox 1 回」「再送禁止」「要約や paraphrase 禁止」と書かれていました。tools は context_board と send_inbox の 2 つだけ。
main agent と並走する read-only ワーカーが、context window の外で参照素材を黙々と引いて inbox に置いておく、という役割分担です。promptParts も includeDynamicContextBoard: true だけ true で、それ以外は全部 false。プロンプトを極小に保ってトークンを節約しているのが分かります。
[!NOTE]
subconscious-agentはfeatureFlag: COPILOT_SUBCONSCIOUSで gating されていて、launchConditions: [launchSubconscious]を満たさないと起動しません。普段の操作で見えないのは、ユーザー側のメモリ機能を有効にしていないとそもそも launch されない設計だからのようです。
深掘り 3: /fleet モードはどこにいる?
definitions/ を全部見ても fleet.agent.yaml のようなファイルは ありません。/fleet だけ YAML 外出しから外れている、というのがこの記事のもう 1 つの観察点です。
その代わりに、app.js をテキスト検索すると見つかります。
$base = "$HOME\.copilot\pkg\win32-x64\1.0.64-1"
Select-String -Path "$base\app.js" -Pattern 'You are now in fleet mode' -SimpleMatch
ヒット箇所のプロンプトを覗くと、要旨はこんな感じでした(フェアユース範囲で意訳・要点抽出)。
- 冒頭は
You are now in fleet mode. Dispatch sub-agents (via the task tool) in parallel ...で始まる -
todosテーブル(SQLite)を真実のソースにして、SELECT id, title, status FROM todos WHERE status != 'done'で残タスクを引き、依存のないものは並列、todo_depsのあるものだけ直列化する - 単発の background subagent 投入は禁止。複数まとめて投げるか sync 1 本に倒す
位置付けはサブエージェントではなく、メインエージェントの振る舞いを切り替えるモードでした。
session.fleet.start の RPC 定義
schemas/api.schema.json を見ると、ちゃんと RPC method として SDK 越しに公開されています。
[!NOTE]
RPC method とは「Remote Procedure Call の手続き(メソッド)」のことで、ざっくり「クライアントから別プロセス(ここでは CLI 内の session サーバ)にある関数を、引数と戻り値の型を決めて呼び出す仕組み」です。Copilot CLI は内部で JSON-RPC ライクな構造を持っていて、session.fleet.startのように<namespace>.<action>形式で名前を付け、paramsとresultの JSON Schema で型を定義しています。「内部 API のエンドポイント」と読み替えるとイメージしやすいです。
| key | 値・意味 |
|---|---|
rpcMethod |
session.fleet.start |
description |
"Starts fleet mode by submitting the fleet orchestration prompt to the session." |
params (FleetStartRequest) |
sessionId: string (required) + prompt?: string
|
result (FleetStartResult) |
started: boolean (required) のみ |
stability |
experimental |
/fleet スラッシュコマンドは、この RPC を叩いて ハードコードされたプロンプトを既存セッションに注入するだけ。戻り値は started: true/false のシンプルな結果型でした。
/fleet の親戚 — autopilot mode
fleet を追っていると、もう一段 high-level な「autopilot mode」という概念に必ずぶつかります。schemas/api.schema.json を見ると、agent には 3 つのモード があると enum で宣言されていました。
"AgentMode": {
"type": "string",
"enum": ["interactive", "plan", "autopilot"]
}
-
interactive: 普段の対話モード。ツール実行ごとに承認が必要 -
plan: 計画を立てて承認を取ってから実行するモード(plan approval) -
autopilot: ツール実行や file 編集の承認をスキップして自走するモード
そして app.js を覗くと、autopilot mode のときだけ追加で注入される指示が見つかります(フェアユース範囲で意訳・要点抽出)。
You are working in autopilot mode. Continue working until the task is complete without asking for permission.- 終了条件は
task_completeツールを呼んだ時 だけ。タスクが完了する前に止まると autopilot のリレーが切れる - 質問せず、必要な情報は自分で調べ、必要なら fleet を発動して並列で消化する
2 つの関係を並べるとこうなります。
- autopilot mode = メインエージェントの「止まらない」モード
- fleet = autopilot 中(または明示発動)で
todosテーブルを並列消化する specialized サブモード - どちらも YAML ではなく、
app.js内のハードコードプロンプト +schemas/api.schema.jsonの RPC / enum で表現される
/fleet を打つと内部的に session.fleet.start が走り、現在のセッションを mode: autopilot に切り替えつつ fleet 用 prompt を注入する、という二段ロケットになっているわけですね。changelog でも Autopilot mode and /fleet command now available to all users (v0.0.411) のようにセットで GA された経緯があり、**autopilot が「容れ物」、fleet が「中身」**という関係が読み取れます。
[!NOTE]
task_completeは autopilot を安全に止めるための専用ツールで、agent が「タスク完了」を明示宣言してはじめて autopilot ループが抜ける設計です。これがあるおかげで、autopilot 中でも勝手にプロンプト終端で停止せず、最後まで走り切ってから止まる、という挙動になります。
YAML vs ハードコード — 非対称の意味
ここまでに見てきた definitions/*.agent.yaml 7 本 + sidekick/*.yaml 4 本と、ハードコード組の /fleet を 1 枚にまとめると、こんな対比になります。
整理するとこうなります。
| 項目 | 定義形式 | 場所 | 種別 |
|---|---|---|---|
research |
YAML | definitions/research.agent.yaml |
サブエージェント定義 |
explore, task, rubber-duck, code-review, security-review, rem-agent
|
YAML | definitions/*.agent.yaml |
サブエージェント定義 |
subconscious-agent, github-context ほか |
YAML | definitions/sidekick/*.yaml |
裏方エージェント定義 |
/fleet |
ハードコード (テンプレートリテラル) + JSON schema |
app.js / schemas/api.schema.json
|
組み込みモード(メインエージェントの振る舞い切替) |
なぜ非対称なのか、私の読みはこうです。
- サブエージェントは「外から呼ばれる小さなプロセス」。プロンプトを差し替えやすく、テスト可能性も高いほうがいい → YAML で外出し。
-
fleet は「メインエージェントそのものの振る舞いを切り替えるモード」。SDK 越しに
session.fleet.startという RPC で 既存セッションにプロンプトを注入 する。サブエージェントではなく モード遷移 なので、定義ファイルとして外出しする旨味が少ない。 - 加えて fleet プロンプト内に SQL クエリ(
todosテーブルへのSELECT/UPDATE)が直接書かれているので、CLI 本体側の SQLite スキーマと密結合。これも YAML として独立させにくい理由のひとつだと思います。
リサーチは YAML 定義、fleet はアプリ内蔵モード、という非対称は、やりたいこと(モード切替 vs ジョブ投入)の違いがそのまま実装形式の違いに落ちている、と読めます。
図で並べると、入口(slash command)から実体までのルートがはっきり違うのが見えます。
青が YAML 外出しルート、橙が ハードコード + RPC ルート。/research は「外から呼ばれる小さなジョブ」、/fleet は「セッションに注入されるモード」という違いが、入口から実体までの経路で見えますね。
/fleet と /research はいつ入った?
changelog.json を ConvertFrom-Json して全バージョンに当てると、こうなっていました(出現したバージョンだけ抜粋)。
-
/fleet: v0.0.411 で全ユーザー開放(Autopilot mode and /fleet command now available to all users)→ v0.0.412 で orchestrator が subagent 出力を検証・並列度強化 → v0.0.415 で autopilot + fleet が plan approval メニューに昇格。それ以降 v1.0.64-1 までは changelog 上で fleet に言及したエントリは見当たりません(プロンプト本文は app.js 内で静かに更新されている可能性はありそう)。 -
/research: v0.0.417 で初登場(Add /research command for deep research with exportable reports)→ v1.0.40 で orchestrator + subagent モデルに刷新(/research uses an orchestrator/subagent model for more thorough and reliable deep research results)。
fleet のほうが先に入って、research は後発でちゃんと YAML 定義として整理された、という時系列がおそらく今の非対称構造を生んでいます。
周辺資産ツアー — オマケだけど面白い
ついでに pkg/ 配下にあった「これも入ってたの?」系を並べておきます。
builtin/ と builtin-skills/
builtin\customize-cloud-agent\SKILL.md
builtin-skills\customize-cloud-agent\SKILL.md
2 つは同一内容でした(Get-FileHash 一致)。中身は「Copilot cloud agent(旧 Copilot coding agent)の development environment を copilot-setup-steps.yml で customize する方法」を書いた SKILL.md です。CLI 本体に Skill が 1 つだけ同梱されているのが少し意外でした。
冒頭の YAML frontmatter には user-invocable: false と書いてあって、ユーザーから直接呼ぶスキルではなく、Copilot CLI 内部から自動的に参照される作りでした。
tree-sitter + queries
17 言語ぶんの .wasm(bash / c / c_sharp / cpp / css / go / html / java / javascript / json / php / python / ruby / rust / scala / tsx / typescript)と core の tree-sitter.wasm、queries/<lang>-highlights.scm が同梱。grep ツールが構文ハイライト&構造認識できるのはこれが入っているからです。tree-sitter のパーサは C 実装を .wasm 化したもので、Node.js だけで OS / CPU を選ばず同じパーサをロードできます。
ripgrep/ と tgrep/
ripgrep は高速検索ツール、tgrep は tree-sitter 連携の構造検索バックエンド。grep ツールの裏側で両方使われています。
音声入力
voice-server.js / voice-engine.worker.js / voice-installer.worker.js と pvrecorder/ (Picovoice の Recorder) が同梱されていて、CLI で音声入力ができるようになっています。
SDK 群
sdk/ / copilot-sdk/ に加えて foundry-local-sdk/(Azure AI Foundry Local 用 SDK)が同梱。CLI 単体に Foundry Local SDK が入っているのは目を引きました。
.agent.yaml から読み取れる「設計観点」
ここまで読んで「自分でもこんな感じのエージェント定義を書きたい」と思った人向けに、definitions/*.agent.yaml を眺めて感じた設計の効きどころを並べておきます。
[!WARNING]
同梱のdefinitions/を 直接書き換えるのは LICENSE 上 NG(次節参照)です。公式が用意した user-level の拡張ルート(カスタムエージェント置き場や custom agent instructions など)が別途あるはずなので、書きたいときはそっち経由で。本記事はあくまで本家の作りを設計参考として読んだもの、というスタンスです。
-
役割ごとにモデルを切り分ける: 品質が要る
researchはclaude-sonnet-4.6固定、速さで回すexplore/taskはclaude-haiku-4.5固定、レビュー系は モデル指定なしでユーザー側のモデルを継承。「全部高品質モデル」にしないのがミソ。 -
tools は迷わせない単位で絞る:
researchは GitHub MCP + web + view/grep/glob だけ、rem-agentはcontext_board1 つだけ。万能型はtools: "*"で潔く全部出す。 -
promptPartsで共通断片を on/off:includeAISafety/includeToolInstructions/includeParallelToolCalling/includeCustomAgentInstructions/includeEnvironmentContext/includeDynamicContextBoardなどのフラグでプロンプトの構成要素を組み立てる。ユーザー指示を読みたくないならincludeCustomAgentInstructions: false、context board を見たいならincludeDynamicContextBoard: true、というように。 -
テンプレ変数
{{cwd}}{{grepToolName}}{{globToolName}}{{shellToolName}}はランタイムに展開される。プロンプトを環境非依存に書ける。 -
sidekick:ブロックで並走ワーカー化:triggers/cancelOnNewTurn/maxSendsPerTurn/featureFlag/launchConditionsでメインと並走する read-only エージェントを定義できる。subconscious-agentがそれの好例。
「プロンプトを長く書く」より「役割ごとにモデルとツールスコープを切って、promptParts の組み合わせを変える」のがこの設計の効きどころ、というのが私の読みです。
ライセンスと取り扱いの注意
pkg/.../LICENSE.md には GitHub Copilot CLI License が入っていて、要点として次のような制約があります(私の読みなので、必ず原文を確認してください)。
- 修正・派生物作成・スタンドアロン再配布は 禁止
- アプリやサービスの一部として unmodified で配布するのは可
- 属性表示が必要
なので、
-
definitions/の YAML を直接書き換えるのは やめておきましょう(次回 update で巻き戻るのと、ライセンス的にもグレー) -
app.jsの長文プロンプトを丸ごとブログに転載するのも 避けるべき - 設計を理解するための短い抜粋+解説(この記事のような使い方)は、調査目的の範囲で fair に行う
という線引きで触るのがよさそうです。
探索の再現コマンド(PowerShell)
私が使ったコマンドを read-only なものだけ載せておきます。手元で同じことをやってみたい人向け。
$base = "$HOME\.copilot\pkg\win32-x64\1.0.64-1"
# 定義ファイル一覧
Get-ChildItem "$base\definitions" -Recurse -File | Select-Object FullName
# 1 つの agent.yaml を頭から見る
Get-Content "$base\definitions\research.agent.yaml" -TotalCount 40
# app.js から fleet プロンプトの場所を探す
Select-String -Path "$base\app.js" -Pattern 'You are now in fleet mode' -SimpleMatch |
ForEach-Object { "Line $($_.LineNumber)" }
# schema 内の fleet 参照
Select-String -Path "$base\schemas\api.schema.json" -Pattern 'fleet' |
ForEach-Object { "[L$($_.LineNumber)] $($_.Line.Trim())" }
# changelog をパースしてどのバージョンに /fleet と /research が出るか
$j = Get-Content "$base\changelog.json" -Raw | ConvertFrom-Json
foreach ($p in $j.PSObject.Properties) {
if ($p.Name -notmatch '^\d') { continue }
$blob = $p.Value | ConvertTo-Json -Depth 12 -Compress
if ($blob -match '/fleet|/research') {
"v=$($p.Name)"
}
}
書き換えはせず、Select-String / Get-Content / Get-ChildItem だけで十分中身は読めます。
まとめ
- GitHub Copilot CLI の
pkg/配下は、サブエージェント定義の YAML、tree-sitter、音声、SDK、SQLite と組み合わさるオーケストレーションプロンプトまで含めた 自己完結ランタイムでした。 -
researchなどのサブエージェントは YAML 定義(definitions/*.agent.yaml)、/fleetはモード切替のハードコード + RPC schema という非対称は、「ジョブを投げるか、モードを切り替えるか」というやりたいことの違いから来ています。 - 上位には 振る舞いモードの軸があり、
AgentMode = interactive / plan / autopilotの enum。autopilotはtask_completeまで止まらないモードで、その中で/fleet(並列消化用 prompt 注入)を発動します。これとは別軸で サブエージェントの軸(/researchなど独立ジョブ +sidekick/*並走 worker)が並んでいる、という 2 軸構造が見えました。 - 裏方の
sidekick/subconscious-agent.yamlは、read-only な並走ワーカーをtriggers/featureFlag/maxSendsPerTurnで安全側に振った設計。安全弁まで YAML 側に持たせているのが面白いです。
definitions/ と schemas/ の 2 フォルダだけでも開けてみると、Copilot CLI が 何を「外出し」して何を「組み込み」にしているか の設計判断が読み取れて面白いですよ~!
もう 1 つの気付き — サブエージェント戦略、思ったより実用かも
正直 VS Code で Copilot を使っているときは「カスタムエージェントなんてわざわざ作らなくても、プロンプトで指示できることなら instructions や Skill で十分じゃないの?」とずっと思っていました。プロンプトで書ける内容をわざわざ別 file に切り出してエージェント化する意味が、ピンと来ていなかったんです。
でも、最近は context window や入力トークンを節約する話があちこちで語られていて、メインの会話に何でも詰め込むのがだんだん重くなってきました。「何を読ませないか」と「どのモデルに渡すか」が、プロンプトと同じくらい設計対象になってきた感じがあります。そのタイミングで definitions/*.agent.yaml を眺めて、見方が変わりました。
刺さったのは、サブエージェントは「何のモデルを使うか」を指定して、別 context / 別 tool scope で委譲できること。これが instructions や inline Skill だけでは届きにくく、prompt file だけだと「呼ばれる側の人格・権限・モデル」として再利用しにくい領域でした。
公式 Docs を確認すると、VS Code Copilot Chat の世界では役割がきれいに分かれていました(Subagents in VS Code ほか)。
-
起動側:
.agent.md(カスタムエージェント)と.prompt.md(プロンプトファイル)。toolsfrontmatter にrunSubagent/agentツールを書けば subagent を呼べる -
単体起動不可:
.instructions.mdにはtoolsfrontmatter が無いので、それ単体で subagent dispatch を起動する手段は無い -
呼ばれる側の設計: 名前・モデル・tool scope・
user-invocable: false/agents:許可リスト・disable-model-invocationを持って 「呼ばれる側の人格」を作れるのは.agent.mdの専売特許。Skill のcontext: forkは「Skill 自身を forked subagent context で動かす」experimental 機能で、別枠
prompt file は 呼び出し側のレシピとしてはかなり強くて、agent frontmatter で built-in agent (ask / agent / plan) や custom agent を指定できますし、tools で使うツールを上書きすることもできます(Use prompt files in VS Code 参照、tools は custom agent 側より prompt file 側が優先)。実際私の手元の prompt files でも agent: "ask" agent: "agent" で custom agent を指定する使い方は日常的に動いていて、運用面でも引き続き現役です。ただ、呼ばれる側として名前・モデル・tool scope・subagent 可否を持つ実体を作るなら .agent.md になる、という整理です。これが custom agent の固有価値、というのが今回の発見でした。
ここまで来ると、definitions/*.agent.yaml の使い分けが「なるほど」と腑に落ちます。
-
品質モデル (
claude-sonnet-4.6) で重要な 1 ジョブを回す:research -
軽いモデル (
claude-haiku-4.5) で「高速・並列・使い捨て」を回す:explore/task -
レビュー系はあえてモデル指定なしでユーザー側を継承:
code-review/rubber-duck/security-review -
ツール権限も「迷わせない単位」で絞る:
researchは GitHub MCP + web に集中、rem-agentはcontext_board1 つだけ
サブエージェント設計の効きどころは、複雑なプロンプトを書くことではなく、「このジョブにはどのモデルとどのツールスコープが合うか」を分けて当てることでした。モデル選定 + 別 context への切り出し + 必要な tool scope をセットで設計できるのが、custom agent を切り出す価値です。
そう考えると、自分のワークフローでも
- しっかりやらないと困るジョブ用(fact-check / 設計判断)には品質モデルのサブエージェント
- 高速で雑に回したいジョブ用(grep / file 一覧 / 軽い分類)には haiku 系の使い捨てサブエージェント
-
メイン context を汚したくない実行系(test / build / lint / format)には
task相当のラッパー — 実行ログを外に逃がしつつ、失敗時だけ要点をメインに戻す設計にできる
みたいな割り振りが効きそうです。「カスタムエージェントいらない派」だった自分ですが、サブエージェントを役割 + モデルで切る戦略は今後の選択肢に入れていきます。プロンプトや Skill で書ける部分はそのままで、モデル指定とコンテキスト分離が必要なところだけ custom agent に切り出す、というのが現実的な使い分けだと思います。
参考リンク
- GitHub Copilot CLI 公式: https://github.com/github/copilot-cli
- GitHub Copilot CLI Docs: https://docs.github.com/en/copilot/concepts/agents/about-copilot-cli
- tree-sitter: https://tree-sitter.github.io/tree-sitter/
- Picovoice pvrecorder: https://github.com/Picovoice/pvrecorder



