0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

GitHub Copilot CLI の中身を全部開けてみた - `definitions/*.agent.yaml` と fleet モードの非対称な作り

0
Last updated at Posted at 2026-06-25

こんにちは、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.jsonsession.fleet.start という RPC method から呼び出される仕組みでした。
  • 上位には **「振る舞いモード」**という軸があり、AgentMode = interactive / plan / autopilot の enum。autopilottask_complete まで止まらずに走るモードで、その中でさらに /fleet を発動すると todos テーブルを使った並列消化サブモードに入ります。これとは別軸で サブエージェント/research など definitions/*.agent.yaml 7 本 + sidekick/* 4 本)が並んでいて、この 2 軸構造が見えました。
  • ついでに tree-sitter (17 言語の .wasm)、voice 入力エンジン、ripgrep / tgrepbuiltin/customize-cloud-agent/SKILL.md まで丸ごと同梱されていました。

GitHub Copilot CLI の 2 軸構造 — 振る舞いモードとサブエージェント

[!NOTE]
この記事の観察結果は @github/copilot v1.0.64-1(gitCommit 6c5be1e)時点のものです。CLI は頻繁に更新されるので、構造は将来変わる可能性があります。package.jsonversion を見て確認してください。

なんでこんなことしたの

きっかけは「自分が .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-arm64linux-x64 などに変わると思います(package.jsonoptionalDependencies を見るとプラットフォーム別 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 つのレイヤに分かれて見えます。

GitHub Copilot CLI pkg/ ディレクトリ全景

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 で固定。リサーチは品質重視、ということだと思います。
  • exploretaskclaude-haiku-4.5 固定。高速 + 安いモデルで「外に切り出して並列で回す」用途に最適化されていますね。
  • code-review / rubber-duck / security-review はモデル指定なし=ユーザーが現在使っているモデルを継承する設計。レビュー系は「メインで使ってるモデルにそのまま見せたい」という意図に見えます。

2. tools: "*" という潔さ

code-review / rubber-duck / security-review / tasktools: "*" で全ツール許可。一方で 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 禁止」と書かれていました。toolscontext_boardsend_inbox の 2 つだけ。

main agent と並走する read-only ワーカーが、context window の外で参照素材を黙々と引いて inbox に置いておく、という役割分担です。promptPartsincludeDynamicContextBoard: true だけ true で、それ以外は全部 false。プロンプトを極小に保ってトークンを節約しているのが分かります。

[!NOTE]
subconscious-agentfeatureFlag: 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> 形式で名前を付け、paramsresult の 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 枚にまとめると、こんな対比になります。

definitions/ の中身 ─ サブエージェント 7 + sidekick 4 の全景

整理するとこうなります。

項目 定義形式 場所 種別
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)から実体までのルートがはっきり違うのが見えます。

/research と /fleet の非対称フロー

青が YAML 外出しルート、橙が ハードコード + RPC ルート/research は「外から呼ばれる小さなジョブ」、/fleet は「セッションに注入されるモード」という違いが、入口から実体までの経路で見えますね。

/fleet/research はいつ入った?

changelog.jsonConvertFrom-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.wasmqueries/<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.jspvrecorder/ (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 など)が別途あるはずなので、書きたいときはそっち経由で。本記事はあくまで本家の作りを設計参考として読んだもの、というスタンスです。

  • 役割ごとにモデルを切り分ける: 品質が要る researchclaude-sonnet-4.6 固定、速さで回す explore / taskclaude-haiku-4.5 固定、レビュー系は モデル指定なしでユーザー側のモデルを継承。「全部高品質モデル」にしないのがミソ。
  • tools は迷わせない単位で絞る: research は GitHub MCP + web + view/grep/glob だけ、rem-agentcontext_board 1 つだけ。万能型は 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。autopilottask_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(プロンプトファイル)。tools frontmatter に runSubagent / agent ツールを書けば subagent を呼べる
  • 単体起動不可: .instructions.md には tools frontmatter が無いので、それ単体で 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-agentcontext_board 1 つだけ

サブエージェント設計の効きどころは、複雑なプロンプトを書くことではなく、「このジョブにはどのモデルとどのツールスコープが合うか」を分けて当てることでした。モデル選定 + 別 context への切り出し + 必要な tool scope をセットで設計できるのが、custom agent を切り出す価値です。

そう考えると、自分のワークフローでも

  • しっかりやらないと困るジョブ用(fact-check / 設計判断)には品質モデルのサブエージェント
  • 高速で雑に回したいジョブ用(grep / file 一覧 / 軽い分類)には haiku 系の使い捨てサブエージェント
  • メイン context を汚したくない実行系(test / build / lint / format)には task 相当のラッパー — 実行ログを外に逃がしつつ、失敗時だけ要点をメインに戻す設計にできる

みたいな割り振りが効きそうです。「カスタムエージェントいらない派」だった自分ですが、サブエージェントを役割 + モデルで切る戦略は今後の選択肢に入れていきます。プロンプトや Skill で書ける部分はそのままで、モデル指定とコンテキスト分離が必要なところだけ custom agent に切り出す、というのが現実的な使い分けだと思います。

参考リンク

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?